summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org>2019-05-14 12:31:59 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-05-14 12:43:25 (GMT)
commit8652a500669059d77ce7bace6e9e9da1b30c54b0 (patch) (unidiff)
tree54ee082e3804c0574e67252be8fbceb48b8f156a /src
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.
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/wordsplit.c201
1 files changed, 178 insertions, 23 deletions
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;
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--;
1197 for (i = 1; i < len; i++) 1298 for (i = str[0] == '-' ? 1 : 0; i < len; i++)
1198 { 1299 {
1199 if (str[i] == ':') 1300 if (str[i] == ':')
1200 { 1301 {
@@ -1222,9 +1323,16 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1222 *pend = str + j; 1323 *pend = str + j;
1223 break; 1324 break;
1224 } 1325 }
1225 else if (ISDIGIT (str[1])) 1326 else if (is_param)
1226 { 1327 {
1227 if (!ISDIGIT (str[i])) 1328 if (ISDIGIT (str[i]))
1329 {
1330 param_idx = param_idx * 10 + to_num (str[i]);
1331 if ((str[0] == '-' && -param_idx < INT_MIN)
1332 || param_idx > INT_MAX)
1333 return expvar_recover (wsp, str - 1, ptail, pend, flg);
1334 }
1335 else
1228 { 1336 {
1229 return expvar_recover (wsp, str - 1, ptail, pend, flg); 1337 return expvar_recover (wsp, str - 1, ptail, pend, flg);
1230 } 1338 }
@@ -1234,6 +1342,10 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1234 return expvar_recover (wsp, str - 1, ptail, pend, flg); 1342 return expvar_recover (wsp, str - 1, ptail, pend, flg);
1235 } 1343 }
1236 } 1344 }
1345
1346 if (is_param && str[0] == '-')
1347 param_idx = wsp->ws_paramc - param_idx;
1348
1237 if (i == len) 1349 if (i == len)
1238 return _wsplt_seterr (wsp, WRDSE_CBRACE); 1350 return _wsplt_seterr (wsp, WRDSE_CBRACE);
1239 } 1351 }
@@ -1254,23 +1366,39 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1254 } 1366 }
1255 else 1367 else
1256 { 1368 {
1257 rc = wordsplit_find_env (wsp, str, i, &vptr); 1369 if (is_param)
1258 if (rc == WRDSE_OK)
1259 { 1370 {
1260 if (vptr) 1371 if (param_idx >= 0 && param_idx < wsp->ws_paramc)
1261 { 1372 {
1262 value = strdup (vptr); 1373 value = strdup (wsp->ws_paramv[param_idx]);
1263 if (!value) 1374 if (!value)
1264 rc = WRDSE_NOSPACE; 1375 rc = WRDSE_NOSPACE;
1376 else
1377 rc = WRDSE_OK;
1265 } 1378 }
1266 else 1379 else
1267 rc = WRDSE_UNDEF; 1380 rc = WRDSE_UNDEF;
1268 } 1381 }
1269 else if (wsp->ws_flags & WRDSF_GETVAR)
1270 rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure);
1271 else 1382 else
1272 rc = WRDSE_UNDEF; 1383 {
1273 1384 rc = wordsplit_find_env (wsp, str, i, &vptr);
1385 if (rc == WRDSE_OK)
1386 {
1387 if (vptr)
1388 {
1389 value = strdup (vptr);
1390 if (!value)
1391 rc = WRDSE_NOSPACE;
1392 }
1393 else
1394 rc = WRDSE_UNDEF;
1395 }
1396 else if (wsp->ws_flags & WRDSF_GETVAR)
1397 rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure);
1398 else
1399 rc = WRDSE_UNDEF;
1400 }
1401
1274 if (rc == WRDSE_OK 1402 if (rc == WRDSE_OK
1275 && (!value || value[0] == 0) 1403 && (!value || value[0] == 0)
1276 && defstr && defstr[-1] == ':') 1404 && defstr && defstr[-1] == ':')
@@ -1321,7 +1449,17 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1321 wordsplit_free (&ws); 1449 wordsplit_free (&ws);
1322 1450
1323 if (defstr[-1] == '=') 1451 if (defstr[-1] == '=')
1324 wsplt_assign_var (wsp, str, i, value); 1452 {
1453 if (is_param)
1454 rc = wsplt_assign_param (wsp, param_idx, value);
1455 else
1456 rc = wsplt_assign_var (wsp, str, i, value);
1457 }
1458 if (rc)
1459 {
1460 free (value);
1461 return rc;
1462 }
1325 } 1463 }
1326 else 1464 else
1327 { 1465 {
@@ -1458,7 +1596,7 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1458static int 1596static int
1459begin_var_p (int c) 1597begin_var_p (int c)
1460{ 1598{
1461 return c == '{' || ISVARBEG (c) || ISDIGIT (c); 1599 return c == '{' || c == '#' || ISVARBEG (c) || ISDIGIT (c);
1462} 1600}
1463 1601
1464static int 1602static int
@@ -2106,9 +2244,6 @@ scan_word (struct wordsplit *wsp, size_t start, int consume_all)
2106 return _WRDS_OK; 2244 return _WRDS_OK;
2107} 2245}
2108 2246
2109#define to_num(c) \
2110 (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 ))
2111
2112static int 2247static int
2113xtonum (int *pval, const char *src, int base, int cnt) 2248xtonum (int *pval, const char *src, int base, int cnt)
2114{ 2249{
@@ -2498,7 +2633,7 @@ wordsplit_free_words (struct wordsplit *ws)
2498void 2633void
2499wordsplit_free_envbuf (struct wordsplit *ws) 2634wordsplit_free_envbuf (struct wordsplit *ws)
2500{ 2635{
2501 if (ws->ws_flags & WRDSF_NOCMD) 2636 if (!(ws->ws_flags & WRDSF_ENV))
2502 return; 2637 return;
2503 if (ws->ws_envbuf) 2638 if (ws->ws_envbuf)
2504 { 2639 {
@@ -2513,6 +2648,23 @@ wordsplit_free_envbuf (struct wordsplit *ws)
2513} 2648}
2514 2649
2515void 2650void
2651wordsplit_free_parambuf (struct wordsplit *ws)
2652{
2653 if (!(ws->ws_options & WRDSO_PARAMV))
2654 return;
2655 if (ws->ws_parambuf)
2656 {
2657 size_t i;
2658
2659 for (i = 0; ws->ws_parambuf[i]; i++)
2660 free (ws->ws_parambuf[i]);
2661 free (ws->ws_parambuf);
2662 ws->ws_paramidx = ws->ws_paramsiz = 0;
2663 ws->ws_parambuf = NULL;
2664 }
2665}
2666
2667void
2516wordsplit_clearerr (struct wordsplit *ws) 2668wordsplit_clearerr (struct wordsplit *ws)
2517{ 2669{
2518 if (ws->ws_errno == WRDSE_USERERR) 2670 if (ws->ws_errno == WRDSE_USERERR)
@@ -2529,6 +2681,7 @@ wordsplit_free (struct wordsplit *ws)
2529 free (ws->ws_wordv); 2681 free (ws->ws_wordv);
2530 ws->ws_wordv = NULL; 2682 ws->ws_wordv = NULL;
2531 wordsplit_free_envbuf (ws); 2683 wordsplit_free_envbuf (ws);
2684 wordsplit_free_parambuf (ws);
2532} 2685}
2533 2686
2534int 2687int
@@ -2557,7 +2710,9 @@ const char *_wordsplit_errstr[] = {
2557 N_("undefined variable"), 2710 N_("undefined variable"),
2558 N_("input exhausted"), 2711 N_("input exhausted"),
2559 N_("unbalanced parenthesis"), 2712 N_("unbalanced parenthesis"),
2560 N_("globbing error") 2713 N_("globbing error"),
2714 N_("user-defined error"),
2715 N_("invalid parameter number in assignment")
2561}; 2716};
2562int _wordsplit_nerrs = 2717int _wordsplit_nerrs =
2563 sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]); 2718 sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]);

Return to:

Send suggestions and report system problems to the System administrator.