diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-04-20 08:54:21 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-04-20 09:47:40 +0300 |
commit | 3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64 (patch) | |
tree | a3c83a584f8e2b54e294ff1dfa04a2262459d5a4 | |
parent | 1498bd570eb001a6b2bc3f1a5074e8b384d6db30 (diff) | |
download | grecs-3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64.tar.gz grecs-3e07e3ad30e8a7a091e213eb4df839b7cf7f1e64.tar.bz2 |
Improve variable handling in wordsplit.
Positional variables ($N and ${N}) are recognized. Variable names in
curly braces follow the same rules as unadorned ones.
This commit also changes memory reallocation strategy in wsplt_assign_var.
If ws_envbuf needs to be expanded, new allocation size is selected as
3/2 of the previous allocation, if that size is less than max(size_t).
-rw-r--r-- | include/wordsplit.h | 16 | ||||
-rw-r--r-- | src/wordsplit.c | 67 |
2 files changed, 60 insertions, 23 deletions
diff --git a/include/wordsplit.h b/include/wordsplit.h index 1a047f7..3a7ab25 100644 --- a/include/wordsplit.h +++ b/include/wordsplit.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* wordsplit - a word splitter | 1 | /* wordsplit - a word splitter |
2 | Copyright (C) 2009-2018 Sergey Poznyakoff | 2 | Copyright (C) 2009-2019 Sergey Poznyakoff |
3 | 3 | ||
4 | This program is free software; you can redistribute it and/or modify it | 4 | This program is free software; you can redistribute it and/or modify it |
5 | under the terms of the GNU General Public License as published by the | 5 | under the terms of the GNU General Public License as published by the |
@@ -66,9 +66,15 @@ struct wordsplit | |||
66 | const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of | 66 | const char **ws_env; /* [Input] (WRDSF_ENV, !WRDSF_NOVAR) Array of |
67 | environment variables. */ | 67 | environment variables. */ |
68 | 68 | ||
69 | char **ws_envbuf; | 69 | /* Temporary storage for environment variables. It is initialized |
70 | size_t ws_envidx; | 70 | upon first assignment which occurs during the parsing process |
71 | size_t ws_envsiz; | 71 | (e.g. ${x:=2}). When this happens, all variables from ws_env are |
72 | moved to ws_envbuf first, and the ws_envbuf address is assigned | ||
73 | to ws_env. From this moment on, all variable expansions are served | ||
74 | from ws_envbuf. */ | ||
75 | char **ws_envbuf; /* Storage for variables */ | ||
76 | size_t ws_envidx; /* Index of first free slot */ | ||
77 | size_t ws_envsiz; /* Size of the ws_envbuf array */ | ||
72 | 78 | ||
73 | int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos); | 79 | int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos); |
74 | /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up | 80 | /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up |
@@ -197,8 +203,8 @@ struct wordsplit | |||
197 | #define WRDSO_DOTGLOB 0x00000004 | 203 | #define WRDSO_DOTGLOB 0x00000004 |
198 | #if 0 /* Unused value */ | 204 | #if 0 /* Unused value */ |
199 | #define WRDSO_ARGV 0x00000008 | 205 | #define WRDSO_ARGV 0x00000008 |
200 | /* Keep backslash in unrecognized escape sequences in words */ | ||
201 | #endif | 206 | #endif |
207 | /* Keep backslash in unrecognized escape sequences in words */ | ||
202 | #define WRDSO_BSKEEP_WORD 0x00000010 | 208 | #define WRDSO_BSKEEP_WORD 0x00000010 |
203 | /* Handle octal escapes in words */ | 209 | /* Handle octal escapes in words */ |
204 | #define WRDSO_OESC_WORD 0x00000020 | 210 | #define WRDSO_OESC_WORD 0x00000020 |
diff --git a/src/wordsplit.c b/src/wordsplit.c index bad59b1..f94015a 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c | |||
@@ -1086,12 +1086,16 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | |||
1086 | } | 1086 | } |
1087 | else | 1087 | else |
1088 | { | 1088 | { |
1089 | wsp->ws_envsiz *= 2; | 1089 | size_t n = wsp->ws_envsiz; |
1090 | newenv = realloc (wsp->ws_envbuf, | 1090 | |
1091 | wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0])); | 1091 | if ((size_t) -1 / 3 * 2 / sizeof (wsp->ws_envbuf[0]) <= n) |
1092 | return _wsplt_nomem (wsp); | ||
1093 | n += (n + 1) / 2; | ||
1094 | newenv = realloc (wsp->ws_envbuf, n * sizeof (wsp->ws_envbuf[0])); | ||
1092 | if (!newenv) | 1095 | if (!newenv) |
1093 | return _wsplt_nomem (wsp); | 1096 | return _wsplt_nomem (wsp); |
1094 | wsp->ws_envbuf = newenv; | 1097 | wsp->ws_envbuf = newenv; |
1098 | wsp->ws_envsiz = n; | ||
1095 | wsp->ws_env = (const char**) wsp->ws_envbuf; | 1099 | wsp->ws_env = (const char**) wsp->ws_envbuf; |
1096 | } | 1100 | } |
1097 | } | 1101 | } |
@@ -1128,6 +1132,29 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | |||
1128 | return WRDSE_OK; | 1132 | return WRDSE_OK; |
1129 | } | 1133 | } |
1130 | 1134 | ||
1135 | /* Recover from what looked like a variable reference, but turned out | ||
1136 | not to be one. STR points to first character after '$'. */ | ||
1137 | static int | ||
1138 | expvar_recover (struct wordsplit *wsp, const char *str, | ||
1139 | struct wordsplit_node **ptail, const char **pend, int flg) | ||
1140 | { | ||
1141 | struct wordsplit_node *newnode; | ||
1142 | |||
1143 | if (wsnode_new (wsp, &newnode)) | ||
1144 | return 1; | ||
1145 | wsnode_insert (wsp, newnode, *ptail, 0); | ||
1146 | *ptail = newnode; | ||
1147 | newnode->flags = _WSNF_WORD | flg; | ||
1148 | newnode->v.word = malloc (3); | ||
1149 | if (!newnode->v.word) | ||
1150 | return _wsplt_nomem (wsp); | ||
1151 | newnode->v.word[0] = '$'; | ||
1152 | newnode->v.word[1] = str[0]; | ||
1153 | newnode->v.word[2] = 0; | ||
1154 | *pend = str; | ||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1131 | static int | 1158 | static int |
1132 | expvar (struct wordsplit *wsp, const char *str, size_t len, | 1159 | expvar (struct wordsplit *wsp, const char *str, size_t len, |
1133 | struct wordsplit_node **ptail, const char **pend, int flg) | 1160 | struct wordsplit_node **ptail, const char **pend, int flg) |
@@ -1148,7 +1175,12 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1148 | break; | 1175 | break; |
1149 | *pend = str + i - 1; | 1176 | *pend = str + i - 1; |
1150 | } | 1177 | } |
1151 | else if (str[0] == '{') | 1178 | else if (ISDIGIT (str[0])) |
1179 | { | ||
1180 | i = 1; | ||
1181 | *pend = str; | ||
1182 | } | ||
1183 | else if (str[0] == '{' && (ISVARBEG (str[1]) || ISDIGIT (str[1]))) | ||
1152 | { | 1184 | { |
1153 | str++; | 1185 | str++; |
1154 | len--; | 1186 | len--; |
@@ -1180,25 +1212,24 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1180 | *pend = str + j; | 1212 | *pend = str + j; |
1181 | break; | 1213 | break; |
1182 | } | 1214 | } |
1215 | else if (ISDIGIT (str[1])) | ||
1216 | { | ||
1217 | if (!ISDIGIT (str[i])) | ||
1218 | { | ||
1219 | return expvar_recover (wsp, str - 1, ptail, pend, flg); | ||
1220 | } | ||
1221 | } | ||
1222 | else if (!ISVARCHR (str[i])) | ||
1223 | { | ||
1224 | return expvar_recover (wsp, str - 1, ptail, pend, flg); | ||
1225 | } | ||
1183 | } | 1226 | } |
1184 | if (i == len) | 1227 | if (i == len) |
1185 | return _wsplt_seterr (wsp, WRDSE_CBRACE); | 1228 | return _wsplt_seterr (wsp, WRDSE_CBRACE); |
1186 | } | 1229 | } |
1187 | else | 1230 | else |
1188 | { | 1231 | { |
1189 | if (wsnode_new (wsp, &newnode)) | 1232 | return expvar_recover (wsp, str, ptail, pend, flg); |
1190 | return 1; | ||
1191 | wsnode_insert (wsp, newnode, *ptail, 0); | ||
1192 | *ptail = newnode; | ||
1193 | newnode->flags = _WSNF_WORD | flg; | ||
1194 | newnode->v.word = malloc (3); | ||
1195 | if (!newnode->v.word) | ||
1196 | return _wsplt_nomem (wsp); | ||
1197 | newnode->v.word[0] = '$'; | ||
1198 | newnode->v.word[1] = str[0]; | ||
1199 | newnode->v.word[2] = 0; | ||
1200 | *pend = str; | ||
1201 | return 0; | ||
1202 | } | 1233 | } |
1203 | 1234 | ||
1204 | /* Actually expand the variable */ | 1235 | /* Actually expand the variable */ |
@@ -1417,7 +1448,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1417 | static int | 1448 | static int |
1418 | begin_var_p (int c) | 1449 | begin_var_p (int c) |
1419 | { | 1450 | { |
1420 | return c == '{' || ISVARBEG (c); | 1451 | return c == '{' || ISVARBEG (c) || ISDIGIT (c); |
1421 | } | 1452 | } |
1422 | 1453 | ||
1423 | static int | 1454 | static int |