aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-05-14 15:31:59 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-05-14 15:43:25 +0300
commit8652a500669059d77ce7bace6e9e9da1b30c54b0 (patch)
tree54ee082e3804c0574e67252be8fbceb48b8f156a
parent65f41a742e025487f8ec7f2e7ca2a3af3283fc96 (diff)
downloadgrecs-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.h20
-rw-r--r--src/wordsplit.c201
-rw-r--r--tests/wordsplit.at122
-rw-r--r--tests/wsp.c832
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
254int wordsplit (const char *s, wordsplit_t *ws, int flags); 271int wordsplit (const char *s, wordsplit_t *ws, int flags);
255int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags); 272int wordsplit_len (const char *s, size_t len, wordsplit_t *ws, int flags);
256void wordsplit_free (wordsplit_t *ws); 273void wordsplit_free (wordsplit_t *ws);
257void wordsplit_free_words (wordsplit_t *ws); 274void wordsplit_free_words (wordsplit_t *ws);
258void wordsplit_free_envbuf (wordsplit_t *ws); 275void wordsplit_free_envbuf (wordsplit_t *ws);
276void wordsplit_free_parambuf (struct wordsplit *ws);
259int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv); 277int wordsplit_get_words (wordsplit_t *ws, size_t *wordc, char ***wordv);
260 278
261static inline void wordsplit_getwords (wordsplit_t *ws, size_t *wordc, char ***wordv) 279static 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
1037static int 1049static int
1038wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, 1050wsplt_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
1157int
1158wsplt_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 '$'. */
1147static int 1223static 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;