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 | |||
@@ -75,6 +75,16 @@ struct wordsplit | |||
75 | char **ws_envbuf; /* Storage for variables */ | 75 | char **ws_envbuf; /* Storage for variables */ |
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); |
80 | /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up | 90 | /* [Input] (WRDSF_GETVAR, !WRDSF_NOVAR) Looks up |
@@ -99,7 +109,7 @@ struct wordsplit | |||
99 | 109 | ||
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. */ |
105 | size_t ws_endp; /* Points past the last processed byte in | 115 | size_t ws_endp; /* Points past the last processed byte in |
@@ -226,6 +236,12 @@ struct wordsplit | |||
226 | $(echo foo bar) */ | 236 | $(echo foo bar) */ |
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 |
231 | #define WRDSO_XESC WRDSO_XESC_WORD | 247 | #define WRDSO_XESC WRDSO_XESC_WORD |
@@ -250,12 +266,14 @@ struct wordsplit | |||
250 | #define WRDSE_PAREN 7 | 266 | #define WRDSE_PAREN 7 |
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); |
255 | int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags); | 272 | int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags); |
256 | void wordsplit_free (wordsplit_t *ws); | 273 | 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 | ||
261 | static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv) | 279 | static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv) |
diff --git a/src/wordsplit.c b/src/wordsplit.c index 521a1eb..6a33636 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c | |||
@@ -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 |
@@ -27,6 +27,7 @@ | |||
27 | #include <stdarg.h> | 27 | #include <stdarg.h> |
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 |
32 | # include <gettext.h> | 33 | # include <gettext.h> |
@@ -56,6 +57,9 @@ | |||
56 | #define WSP_RETURN_DELIMS(wsp) \ | 57 | #define WSP_RETURN_DELIMS(wsp) \ |
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 |
61 | 65 | ||
@@ -284,6 +288,14 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, | |||
284 | wsp->ws_options |= WRDSO_BSKEEP_QUOTE; | 288 | wsp->ws_options |= WRDSO_BSKEEP_QUOTE; |
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; |
289 | wsp->ws_wordi = 0; | 301 | wsp->ws_wordi = 0; |
@@ -1036,7 +1048,7 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len, | |||
1036 | 1048 | ||
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; |
1042 | char *v; | 1054 | char *v; |
@@ -1071,7 +1083,7 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | |||
1071 | { | 1083 | { |
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 | } |
1077 | } | 1089 | } |
@@ -1142,6 +1154,70 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, | |||
1142 | return WRDSE_OK; | 1154 | return WRDSE_OK; |
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 '$'. */ |
1147 | static int | 1223 | static int |
@@ -1177,6 +1253,8 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1177 | const char *start = str - 1; | 1253 | const char *start = str - 1; |
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])) |
1182 | { | 1260 | { |
@@ -1185,16 +1263,39 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, | |||
1185 | break; | 1263 | break; |
1186 | *pend = str + i - 1; | 1264 | *pend = str + i - 1; |