diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-05-14 15:31:59 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-05-14 15:43:25 +0300 |
commit | 8652a500669059d77ce7bace6e9e9da1b30c54b0 (patch) | |
tree | 54ee082e3804c0574e67252be8fbceb48b8f156a | |
parent | 65f41a742e025487f8ec7f2e7ca2a3af3283fc96 (diff) | |
download | grecs-8652a500669059d77ce7bace6e9e9da1b30c54b0.tar.gz grecs-8652a500669059d77ce7bace6e9e9da1b30c54b0.tar.bz2 |
wordsplit: rewrite positional parameters implementation
This improves 3e07e3ad
* include/wordsplit.h (ws_paramv,ws_paramc)
(ws_parambuf,ws_paramidx,ws_paramsiz): New fields.
(WRDSO_PARAMV,WRDSO_PARAM_NEGIDX): New options.
(WRDSE_BADPARAM): New error code.
(wordsplit_free_parambuf): New proto.
* src/wordsplit.c (wordsplit_init): Initialize new fields.
(wsplt_assign_var): Fix double-free and memory leak.
(expvar): Expand positional parameters.
(begin_var_p): Add '#'
(wordsplit_free_envbuf): Fix condition.
(wordsplit_free_parambuf): New function.
(wordsplit_free): Call wordsplit_free_parambuf.
(_wordsplit_errstr): New error description.
* tests/wordsplit.at: Update wsp invocations.
Test positional parameters.
* tests/wsp.c: Rewrite.
-rw-r--r-- | include/wordsplit.h | 20 | ||||
-rw-r--r-- | src/wordsplit.c | 201 | ||||
-rw-r--r-- | tests/wordsplit.at | 122 | ||||
-rw-r--r-- | tests/wsp.c | 832 |
4 files changed, 704 insertions, 471 deletions
diff --git a/include/wordsplit.h b/include/wordsplit.h index a175275..d7eb26f 100644 --- a/include/wordsplit.h +++ b/include/wordsplit.h | |||
@@ -76,4 +76,14 @@ struct wordsplit | |||
76 | size_t ws_envidx; /* Index of first free slot */ | 76 | size_t ws_envidx; /* Index of first free slot */ |
77 | size_t ws_envsiz; /* Size of the ws_envbuf array */ | 77 | size_t ws_envsiz; /* Size of the ws_envbuf array */ |
78 | |||
79 | char const **ws_paramv; /* [WRDSO_PARAMV] User-supplied positional | ||
80 | parameters */ | ||
81 | size_t ws_paramc; /* Number of positional parameters */ | ||
82 | |||
83 | /* Temporary storage for parameters. Works similarly to ws_enbuf. | ||
84 | */ | ||
85 | char **ws_parambuf; | ||
86 | size_t ws_paramidx; | ||
87 | size_t ws_paramsiz; | ||
78 | 88 | ||
79 | int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos); | 89 | int (*ws_getvar) (char **ret, const char *var, size_t len, void *clos); |
@@ -100,5 +110,5 @@ struct wordsplit | |||
100 | See ws_getvar for a discussion of possible | 110 | See ws_getvar for a discussion of possible |
101 | return values. */ | 111 | return values. */ |
102 | 112 | ||
103 | const char *ws_input; /* Input string (the S argument to wordsplit. */ | 113 | const char *ws_input; /* Input string (the S argument to wordsplit. */ |
104 | size_t ws_len; /* Length of ws_input. */ | 114 | size_t ws_len; /* Length of ws_input. */ |
@@ -227,4 +237,10 @@ struct wordsplit | |||
227 | #define WRDSO_NOCMDSPLIT 0x00002000 | 237 | #define WRDSO_NOCMDSPLIT 0x00002000 |
228 | 238 | ||
239 | /* Enable positional parameters */ | ||
240 | #define WRDSO_PARAMV 0x00004000 | ||
241 | /* Enable negative positional indices (${-1} is the last positional | ||
242 | parameter) */ | ||
243 | #define WRDSO_PARAM_NEGIDX 0x00008000 | ||
244 | |||
229 | #define WRDSO_BSKEEP WRDSO_BSKEEP_WORD | 245 | #define WRDSO_BSKEEP WRDSO_BSKEEP_WORD |
230 | #define WRDSO_OESC WRDSO_OESC_WORD | 246 | #define WRDSO_OESC WRDSO_OESC_WORD |
@@ -251,4 +267,5 @@ struct wordsplit | |||
251 | #define WRDSE_GLOBERR 8 | 267 | #define WRDSE_GLOBERR 8 |
252 | #define WRDSE_USERERR 9 | 268 | #define WRDSE_USERERR 9 |
269 | #define WRDSE_BADPARAM 10 | ||
253 | 270 | ||
254 | int wordsplit (const char *s, wordsplit_t *ws, int flags); | 271 | int wordsplit (const char *s, wordsplit_t *ws, int flags); |
@@ -257,4 +274,5 @@ void wordsplit_free (wordsplit_t *ws); | |||
257 | void wordsplit_free_words (wordsplit_t *ws); | 274 | void wordsplit_free_words (wordsplit_t *ws); |
258 | void wordsplit_free_envbuf (wordsplit_t *ws); | 275 | void wordsplit_free_envbuf (wordsplit_t *ws); |
276 | void wordsplit_free_parambuf (struct wordsplit *ws); | ||
259 | int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv); | 277 | int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv); |
260 | 278 | ||
diff --git a/src/wordsplit.c b/src/wordsplit.c index 521a1eb..6a33636 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c | |||
@@ -1,4 +1,4 @@ | |||
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 |
@@ -28,4 +28,5 @@ | |||
28 | #include <pwd.h> | 28 | #include <pwd.h> |
29 | #include <glob.h> | 29 | #include <glob.h> |
30 | #include <limits.h> | ||
30 | 31 | ||
31 | #if ENABLE_NLS | 32 | #if ENABLE_NLS |
@@ -57,4 +58,7 @@ | |||
57 | ((wsp)->ws_flags & WRDSF_RETURN_DELIMS || ((wsp)->ws_options & WRDSO_MAXWORDS)) | 58 | ((wsp)->ws_flags & WRDSF_RETURN_DELIMS || ((wsp)->ws_options & WRDSO_MAXWORDS)) |
58 | 59 | ||
60 | #define to_num(c) \ | ||
61 | (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 )) | ||
62 | |||
59 | #define ALLOC_INIT 128 | 63 | #define ALLOC_INIT 128 |
60 | #define ALLOC_INCR 128 | 64 | #define ALLOC_INCR 128 |
@@ -285,4 +289,12 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, | |||
285 | } | 289 | } |
286 | } | 290 | } |
291 | |||
292 | if (!(wsp->ws_options & WRDSO_PARAMV)) | ||
293 | { | ||
294 | wsp->ws_paramv = NULL; | ||
295 | wsp->ws_paramc = 0; | ||
296 | } | ||
297 | wsp->ws_paramidx = wsp->ws_paramsiz = 0; | ||
298 | wsp->ws_parambuf = NULL; | ||
287 | 299 | ||
288 | wsp->ws_endp = 0; | 300 | wsp->ws_endp = 0; |
@@ -1037,5 +1049,5 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len, | |||
1037 | static int | 1049 | static int |
1038 | wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | 1050 | wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, |
1039 | char *value) | 1051 | char const *value) |
1040 | { | 1052 | { |
1041 | int n = (wsp->ws_flags & WRDSF_ENV_KV) ? 2 : 1; | 1053 | int n = (wsp->ws_flags & WRDSF_ENV_KV) ? 2 : 1; |
@@ -1072,5 +1084,5 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | |||
1072 | for (; j > 1; j--) | 1084 | for (; j > 1; j--) |
1073 | free (newenv[j-1]); | 1085 | free (newenv[j-1]); |
1074 | free (newenv[j-1]); | 1086 | free (newenv); |
1075 | return _wsplt_nomem (wsp); | 1087 | return _wsplt_nomem (wsp); |
1076 | } | 1088 | } |
@@ -1143,4 +1155,68 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | |||
1143 | } | 1155 | } |
1144 | 1156 | ||
1157 | int | ||
1158 | wsplt_assign_param (struct wordsplit *wsp, int param_idx, char *value) | ||
1159 | { | ||
1160 | char *v; | ||
1161 | |||
1162 | if (param_idx < 0) | ||
1163 | return WRDSE_BADPARAM; | ||
1164 | if (param_idx == wsp->ws_paramc) | ||
1165 | { | ||
1166 | char **parambuf; | ||
1167 | if (!wsp->ws_parambuf) | ||
1168 | { | ||
1169 | size_t i; | ||
1170 | |||
1171 | parambuf = calloc ((size_t)param_idx + 1, sizeof (parambuf[0])); | ||
1172 | if (!parambuf) | ||
1173 | return _wsplt_nomem (wsp); | ||
1174 | |||
1175 | for (i = 0; i < wsp->ws_paramc; i++) | ||
1176 | { | ||
1177 | parambuf[i] = strdup (wsp->ws_paramv[i]); | ||
1178 | if (!parambuf[i]) | ||
1179 | { | ||
1180 | for (; i > 1; i--) | ||
1181 | free (parambuf[i-1]); | ||
1182 | free (parambuf); | ||
1183 | return _wsplt_nomem (wsp); | ||
1184 | } | ||
1185 | } | ||
1186 | |||
1187 | wsp->ws_parambuf = parambuf; | ||
1188 | wsp->ws_paramidx = param_idx; | ||
1189 | wsp->ws_paramsiz = param_idx + 1; | ||
1190 | } | ||
1191 | else | ||
1192 | { | ||
1193 | size_t n = wsp->ws_paramsiz; | ||
1194 | |||
1195 | if ((size_t) -1 / 3 * 2 / sizeof (wsp->ws_parambuf[0]) <= n) | ||
1196 | return _wsplt_nomem (wsp); | ||
1197 | n += (n + 1) / 2; | ||
1198 | parambuf = realloc (wsp->ws_parambuf, n * sizeof (wsp->ws_parambuf[0])); | ||
1199 | if (!parambuf) | ||
1200 | return _wsplt_nomem (wsp); | ||
1201 | wsp->ws_parambuf = parambuf; | ||
1202 | wsp->ws_paramsiz = n; | ||
1203 | wsp->ws_parambuf[param_idx] = NULL; | ||
1204 | } | ||
1205 | |||
1206 | wsp->ws_paramv = (const char**) wsp->ws_parambuf; | ||
1207 | wsp->ws_paramc = param_idx + 1; | ||
1208 | } | ||
1209 | else if (param_idx > wsp->ws_paramc) | ||
1210 | return WRDSE_BADPARAM; | ||
1211 | |||
1212 | v = strdup (value); | ||
1213 | if (!v) | ||
1214 | return _wsplt_nomem (wsp); | ||
1215 | |||
1216 | free (wsp->ws_parambuf[param_idx]); | ||
1217 | wsp->ws_parambuf[param_idx] = v; | ||
1218 | return WRDSE_OK; | ||
1219 | } | ||
1220 | |||
1145 | /* Recover from what looked like a variable reference, but turned out | 1221 | /* Recover from what looked like a variable reference, but turned out |
1146 | not to be one. STR points to first character after '$'. */ | 1222 | not to be one. STR points to first character after '$'. */ |
@@ -1178,4 +1254,6 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1178 | int rc; | 1254 | int rc; |
1179 | struct wordsplit ws; | 1255 | struct wordsplit ws; |
1256 | int is_param = 0; | ||
1257 | long param_idx = 0; | ||
1180 | 1258 | ||
1181 | if (ISVARBEG (str[0])) | 1259 | if (ISVARBEG (str[0])) |
@@ -1186,14 +1264,37 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1186 | *pend = str + i - 1; | 1264 | *pend = str + i - 1; |
1187 | } | 1265 | } |
1188 | else if (ISDIGIT (str[0])) | 1266 | else if ((wsp->ws_options & WRDSO_PARAMV) && ISDIGIT (str[0])) |
1189 | { | 1267 | { |
1190 | i = 1; | 1268 | i = 1; |
1191 | *pend = str; | 1269 | *pend = str; |
1270 | is_param = 1; | ||
1271 | param_idx = to_num (str[0]); | ||
1192 | } | 1272 | } |
1193 | else if (str[0] == '{' && (ISVARBEG (str[1]) || ISDIGIT (str[1]))) | 1273 | else if ((wsp->ws_options & WRDSO_PARAMV) && str[0] == '#') |
1274 | { | ||
1275 | char b[16]; | ||
1276 | snprintf (b, sizeof(b), "%d", (int) wsp->ws_paramc); | ||
1277 | value = strdup (b); | ||
1278 | if (!value) | ||
1279 | return _wsplt_nomem (wsp); | ||
1280 | if (wsnode_new (wsp, &newnode)) | ||
1281 | return 1; | ||
1282 | wsnode_insert (wsp, newnode, *ptail, 0); | ||
1283 | *ptail = newnode; | ||
1284 | newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; | ||
1285 | newnode->v.word = value; | ||
1286 | return 0; | ||
1287 | } | ||
1288 | else if (str[0] == '{' | ||
1289 | && (ISVARBEG (str[1]) | ||
1290 | || (is_param = (((wsp->ws_options & WRDSO_PARAMV) | ||
1291 | && ISDIGIT (str[1])) | ||
1292 | || ((wsp->ws_options & WRDSO_PARAM_NEGIDX) | ||
1293 | && (str[1] == '-' | ||
1294 | && ISDIGIT (str[2]))))) != 0)) | ||
1194 | { | 1295 | { |
1195 | str++; | 1296 | str++; |
1196 | len--; | 1297 | len--; |