summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-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
@@ -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
254int wordsplit (const char *s, wordsplit_t *ws, int flags); 271int wordsplit (const char *s, wordsplit_t *ws, int flags);
@@ -257,4 +274,5 @@ void 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
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,
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;
@@ -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
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 '$'. */
@@ -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--;
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] == ':')
@@ -1223,7 +1324,14 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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);
@@ -1235,4 +1343,8 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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);
@@ -1255,21 +1367,37 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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)
@@ -1322,5 +1450,15 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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
@@ -1459,5 +1597,5 @@ static 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
@@ -2107,7 +2245,4 @@ scan_word (struct wordsplit *wsp, size_t start, int consume_all)
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)
@@ -2499,5 +2634,5 @@ void
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)
@@ -2514,4 +2649,21 @@ wordsplit_free_envbuf (struct wordsplit *ws)
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{
@@ -2530,4 +2682,5 @@ wordsplit_free (struct wordsplit *ws)
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
@@ -2558,5 +2711,7 @@ const char *_wordsplit_errstr[] = {
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 =
diff --git a/tests/wordsplit.at b/tests/wordsplit.at
index 1f2e80d..ebd168b 100644
--- a/tests/wordsplit.at
+++ b/tests/wordsplit.at
@@ -109,5 +109,5 @@ dnl ------------------------------------------------------------
109dnl Test worsplit-specific behavior 109dnl Test worsplit-specific behavior
110dnl ------------------------------------------------------------ 110dnl ------------------------------------------------------------
111TESTWSP([append],[wsp-append],[append], 111TESTWSP([append],[wsp-append],[-append],
112[jeden dwa trzy 112[jeden dwa trzy
113cztery 113cztery
@@ -134,5 +134,5 @@ TOTAL: 2
134]) 134])
135 135
136TESTWSP([dooffs],[wsp-doofs ],[dooffs 3 jeden dwa trzy], 136TESTWSP([dooffs],[wsp-doofs ],[-dooffs jeden dwa trzy],
137[cztery piec], 137[cztery piec],
138[NF: 2 (3) 138[NF: 2 (3)
@@ -215,5 +215,5 @@ TOTAL: 3
215[unset FOO;]) 215[unset FOO;])
216 216
217TESTWSP([undefined variables 2],[],[keepundef], 217TESTWSP([undefined variables 2],[],[-keepundef],
218[a $FOO test a${FOO}b], 218[a $FOO test a${FOO}b],
219[NF: 4 219[NF: 4
@@ -227,5 +227,5 @@ TOTAL: 4
227[unset FOO;]) 227[unset FOO;])
228 228
229TESTWSP([warn about undefined variables],[],[warnundef], 229TESTWSP([warn about undefined variables],[],[-warnundef],
230[$FOO], 230[$FOO],
231[NF: 0 231[NF: 0
@@ -236,5 +236,5 @@ TOTAL: 0
236[unset FOO;]) 236[unset FOO;])
237 237
238TESTWSP([bail out on undefined variables],[],[undef], 238TESTWSP([bail out on undefined variables],[],[-undef],
239[$FOO], 239[$FOO],
240[], 240[],
@@ -243,5 +243,5 @@ TESTWSP([bail out on undefined variables],[],[undef],
243[unset FOO;]) 243[unset FOO;])
244 244
245TESTWSP([disable variable expansion],[],[novar], 245TESTWSP([disable variable expansion],[],[-novar],
246[$FOO], 246[$FOO],
247[NF: 1 247[NF: 1
@@ -253,5 +253,5 @@ TOTAL: 1
253 253
254TESTWSP([K/V environment],[wsp-env-kv wsp-env_kv], 254TESTWSP([K/V environment],[wsp-env-kv wsp-env_kv],
255[env_kv], 255[-env_kv],
256[$FOO a$BAZ], 256[$FOO a$BAZ],
257[NF: 2 257[NF: 2
@@ -263,5 +263,5 @@ TOTAL: 2
263[FOO=bar BAZ=qux]) 263[FOO=bar BAZ=qux])
264 264
265TESTWSP([nosplit with variable expansion],[wsp-var-nosplit],[nosplit], 265TESTWSP([nosplit with variable expansion],[wsp-var-nosplit],[-nosplit],
266[a $FOO test], 266[a $FOO test],
267[NF: 1 267[NF: 1
@@ -272,5 +272,5 @@ TOTAL: 1
272[FOO="variable expansion"]) 272[FOO="variable expansion"])
273 273
274TESTWSP([nosplit without variable expansion],[],[nosplit novar], 274TESTWSP([nosplit without variable expansion],[],[-nosplit -novar],
275[a $FOO test], 275[a $FOO test],
276[NF: 1 276[NF: 1
@@ -281,5 +281,5 @@ TOTAL: 1
281[FOO="variable expansion"]) 281[FOO="variable expansion"])
282 282
283TESTWSP([nosplit: empty expansion],[],[nosplit trimnl], 283TESTWSP([nosplit: empty expansion],[],[-nosplit -trimnl],
284[$FOO], 284[$FOO],
285[NF: 1 285[NF: 1
@@ -290,13 +290,4 @@ TOTAL: 1
290[FOO=""]) 290[FOO=""])
291 291
292TESTWSP([default value (defined)],[],[],
293[${FOO:-bar}],
294[NF: 1
2950: qux
296TOTAL: 1
297],
298[],
299[FOO=qux])
300
301TESTWSP([default value],[],[], 292TESTWSP([default value],[],[],
302[${FOO:-bar}], 293[${FOO:-bar}],
@@ -452,5 +443,5 @@ TOTAL: 2
452WSPGROUP() 443WSPGROUP()
453 444
454TESTWSP([ignore quotes],[wsp-ignore-quotes ],[-quote], 445TESTWSP([ignore quotes],[wsp-ignore-quotes ],[-noquote],
455["a text"], 446["a text"],
456[NF: 2 447[NF: 2
@@ -463,5 +454,5 @@ WSPGROUP(wsp-delim)
463 454
464TESTWSP([custom delimiters (squeeze)],[], 455TESTWSP([custom delimiters (squeeze)],[],
465[delim : -ws trimnl], 456[-delim : -nows -trimnl],
466[semicolon: separated::list: of :words], 457[semicolon: separated::list: of :words],
467[NF: 5 458[NF: 5
@@ -475,5 +466,5 @@ TOTAL: 5
475 466
476TESTWSP([custom delimiters (no squeeze)],[], 467TESTWSP([custom delimiters (no squeeze)],[],
477[delim : -ws -squeeze_delims trimnl], 468[-delim : -nows -nosqueeze_delims -trimnl],
478[semicolon: separated::list: of :words], 469[semicolon: separated::list: of :words],
479[NF: 6 470[NF: 6
@@ -488,5 +479,5 @@ TOTAL: 6
488 479
489TESTWSP([custom, with returned delimiters],[], 480TESTWSP([custom, with returned delimiters],[],
490[delim : -ws trimnl return_delims], 481[-delim : -nows -trimnl -return_delims],
491[semicolon: separated::list: of :words], 482[semicolon: separated::list: of :words],
492[NF: 9 483[NF: 9
@@ -504,5 +495,5 @@ TOTAL: 9
504 495
505TESTWSP([custom, with returned & squeezed delimiters],[], 496TESTWSP([custom, with returned & squeezed delimiters],[],
506[delim : -ws trimnl return_delims -squeeze_delims], 497[-delim : -nows -trimnl -return_delims -nosqueeze_delims],
507[semicolon: separated::list: of :words], 498[semicolon: separated::list: of :words],
508[NF: 10 499[NF: 10
@@ -522,5 +513,5 @@ TOTAL: 10
522WSPGROUP(wsp-sed) 513WSPGROUP(wsp-sed)
523 514
524TESTWSP([sed expressions],[],[sed], 515TESTWSP([sed expressions],[],[-sed],
525[arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2], 516[arg1 s/foo/bar/g;s/bar baz/quz quux/ arg2],
526[NF: 3 517[NF: 3
@@ -533,5 +524,5 @@ TOTAL: 3
533WSPGROUP() 524WSPGROUP()
534 525
535TESTWSP([C escapes on],[wcp-c-escape],[cescapes], 526TESTWSP([C escapes on],[wcp-c-escape],[-cescapes],
536[a\ttab form\ffeed and new\nline], 527[a\ttab form\ffeed and new\nline],
537[NF: 4 528[NF: 4
@@ -543,5 +534,5 @@ TOTAL: 4
543]) 534])
544 535
545TESTWSP([C escapes off],[wcp-c-escape-off],[-cescapes], 536TESTWSP([C escapes off],[wcp-c-escape-off],[-nocescapes],
546[a\ttab form\ffeed and new\nline], 537[a\ttab form\ffeed and new\nline],
547[NF: 4 538[NF: 4
@@ -553,5 +544,5 @@ TOTAL: 4
553]) 544])
554 545
555TESTWSP([ws elimination],[wsp-ws-elim],[delim ' ()' ws return_delims], 546TESTWSP([ws elimination],[wsp-ws-elim],[-delim ' ()' -ws -return_delims],
556[( list items )], 547[( list items )],
557[NF: 4 548[NF: 4
@@ -564,5 +555,5 @@ TOTAL: 4
564 555
565TESTWSP([ws elimination + return delim],[wsp-ws-elim-ret], 556TESTWSP([ws elimination + return delim],[wsp-ws-elim-ret],
566[-default novar nocmd delim ":," return_delims ws dquote], 557[-nodefault -novar -nocmd -delim ":," -return_delims -ws -dquote],
567["foo" : "bar", "quux" : "baaz" ], 558["foo" : "bar", "quux" : "baaz" ],
568[NF: 7 559[NF: 7
@@ -577,5 +568,5 @@ TOTAL: 7
577]) 568])
578 569
579TESTWSP([empty quotes],[wsp-empty-quotes],[delim : ws return_delims], 570TESTWSP([empty quotes],[wsp-empty-quotes],[-delim : -ws -return_delims],
580[t=""], 571[t=""],
581[NF: 1 572[NF: 1
@@ -585,5 +576,5 @@ TOTAL: 1
585 576
586TESTWSP([delimiter following empty quotes], 577TESTWSP([delimiter following empty quotes],
587[],[delim : ws return_delims], 578[],[-delim : -ws -return_delims],
588[t="":r], 579[t="":r],
589[NF: 3 580[NF: 3
@@ -596,5 +587,5 @@ TOTAL: 3
596TESTWSP([suppress ws trimming within quotes], 587TESTWSP([suppress ws trimming within quotes],
597[], 588[],
598[default delim , ws return_delims], 589[-default -delim , -ws -return_delims],
599[nocomponent,nonewline, formatfield="In message %{text}, "], 590[nocomponent,nonewline, formatfield="In message %{text}, "],
600[NF: 5 591[NF: 5
@@ -609,5 +600,5 @@ TOTAL: 5
609TESTWSP([unescape], 600TESTWSP([unescape],
610[wsp-unescape wsp-unescape-simple], 601[wsp-unescape wsp-unescape-simple],
611[-default novar nocmd quote escape ':+:\\""'], 602[-nodefault -novar -nocmd -quote -escape ':+:\\""'],
612[\Seen "quote \"" "bs \\"], 603[\Seen "quote \"" "bs \\"],
613[NF: 3 604[NF: 3
@@ -620,5 +611,5 @@ TOTAL: 3
620TESTWSP([unescape: word/quote], 611TESTWSP([unescape: word/quote],
621[wsp-unescape wsp-unescape-word], 612[wsp-unescape wsp-unescape-word],
622[-default novar nocmd quote escape-word '\\""' escape-quote ':+0x:\\""'], 613[-nodefault -novar -nocmd -quote -escape-word '\\""' -escape-quote ':+0x:\\""'],
623[\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101], 614[\Seen "quote \"" "bs \\" "3\x31 \101" 3\x31 \101],
624[NF: 6 615[NF: 6
@@ -632,5 +623,5 @@ TOTAL: 6
632]) 623])
633 624
634TESTWSP([dquote],[],[-default novar nocmd dquote], 625TESTWSP([dquote],[],[-nodefault -novar -nocmd -dquote],
635[a "quoted example" isn't it], 626[a "quoted example" isn't it],
636[NF: 4 627[NF: 4
@@ -642,5 +633,5 @@ TOTAL: 4
642]) 633])
643 634
644TESTWSP([squote],[],[-default novar nocmd squote], 635TESTWSP([squote],[],[-nodefault -novar -nocmd -squote],
645[a 'quoted example' isn"t it], 636[a 'quoted example' isn"t it],
646[NF: 4 637[NF: 4
@@ -654,5 +645,5 @@ TOTAL: 4
654WSPGROUP(wsp-incr) 645WSPGROUP(wsp-incr)
655 646
656TESTWSP([incremental],[],[incremental], 647TESTWSP([incremental],[],[-incremental],
657[incremental "input test" line 648[incremental "input test" line
658 649
@@ -672,5 +663,5 @@ TOTAL: 3
672]) 663])
673 664
674TESTWSP([incremental append],[],[incremental append], 665TESTWSP([incremental append],[],[-incremental -append],
675[incremental "input test" line 666[incremental "input test" line
676 667
@@ -694,5 +685,5 @@ TOTAL: 3
694 685
695TESTWSP([incremental ws], 686TESTWSP([incremental ws],
696[],[return_delims -squeeze_delims incremental ws], 687[],[-return_delims -nosqueeze_delims -incremental -ws],
697[a list test 688[a list test
698 689
@@ -712,5 +703,5 @@ TOTAL: 3
712]) 703])
713 704
714TESTWSP([incremental nosplit],[],[incremental nosplit], 705TESTWSP([incremental nosplit],[],[-incremental -nosplit],
715[incremental "input test" line 706[incremental "input test" line
716], 707],
@@ -722,5 +713,5 @@ TOTAL: 1
722]) 713])
723 714
724TESTWSP([simple command substitution],[],[-nocmd], 715TESTWSP([simple command substitution],[],[-cmd],
725[begin $(words a b) end], 716[begin $(words a b) end],
726[NF: 4 717[NF: 4
@@ -732,5 +723,5 @@ TOTAL: 4
732]) 723])
733 724
734TESTWSP([quoted command substitution],[],[-nocmd], 725TESTWSP([quoted command substitution],[],[-cmd],
735[begin "$(words a b)" end], 726[begin "$(words a b)" end],
736[NF: 3 727[NF: 3
@@ -741,5 +732,5 @@ TOTAL: 3
741]) 732])
742 733
743TESTWSP([coalesced command substitution],[],[-nocmd], 734TESTWSP([coalesced command substitution],[],[-cmd],
744[begin($(words a b))end], 735[begin($(words a b))end],
745[NF: 2 736[NF: 2
@@ -749,5 +740,5 @@ TOTAL: 2
749]) 740])
750 741
751TESTWSP([quoted coalesced command substitution],[],[-nocmd], 742TESTWSP([quoted coalesced command substitution],[],[-cmd],
752["begin($(words a b))end"], 743["begin($(words a b))end"],
753[NF: 1 744[NF: 1
@@ -756,5 +747,5 @@ TOTAL: 1
756]) 747])
757 748
758TESTWSP([variable and command substitution],[],[-nocmd -novar], 749TESTWSP([variable and command substitution],[],[-cmd -var],
759[begin $X $(words $X $Y) end], 750[begin $X $(words $X $Y) end],
760[NF: 5 751[NF: 5
@@ -767,5 +758,5 @@ TOTAL: 5
767],[],[X=a Y=b]) 758],[],[X=a Y=b])
768 759
769TESTWSP([variable expansion and command substitution in quotes],[],[-nocmd -novar], 760TESTWSP([variable expansion and command substitution in quotes],[],[-cmd -var],
770["${BEGIN}($(words $X $Y))end"], 761["${BEGIN}($(words $X $Y))end"],
771[NF: 1 762[NF: 1
@@ -774,5 +765,5 @@ TOTAL: 1
774],[],[X=a Y=b BEGIN=begin]) 765],[],[X=a Y=b BEGIN=begin])
775 766
776TESTWSP([nested commands],[],[-nocmd -novar], 767TESTWSP([nested commands],[],[-cmd -var],
777[$(words output $(words in$SUFFIX text) end)], 768[$(words output $(words in$SUFFIX text) end)],
778[NF: 4 769[NF: 4
@@ -793,5 +784,5 @@ mkdir dir
793> dir/3.b 784> dir/3.b
794 785
795wsp pathexpand<<'EOT' 786wsp -pathexpand<<'EOT'
796begin dir/*.c end 787begin dir/*.c end
797EOT 788EOT
@@ -814,5 +805,5 @@ mkdir dir
814> dir/2.b 805> dir/2.b
815 806
816wsp pathexpand<<'EOT' 807wsp -pathexpand<<'EOT'
817begin dir/*.d end 808begin dir/*.d end
818EOT 809EOT
@@ -834,5 +825,5 @@ mkdir dir
834> dir/2.b 825> dir/2.b
835 826
836wsp pathexpand nullglob<<'EOT' 827wsp -pathexpand -nullglob<<'EOT'
837begin dir/*.d end 828begin dir/*.d end
838EOT 829EOT
@@ -853,5 +844,5 @@ mkdir dir
853> dir/2.b 844> dir/2.b
854 845
855wsp pathexpand failglob<<'EOT' 846wsp -pathexpand -failglob<<'EOT'
856begin dir/*.d end 847begin dir/*.d end
857EOT 848EOT
@@ -863,5 +854,5 @@ EOT
863AT_CLEANUP 854AT_CLEANUP
864 855
865TESTWSP([append],[],[-- extra arguments follow], 856TESTWSP([append],[],[-append-args extra arguments follow],
866[some words and], 857[some words and],
867[NF: 6 858[NF: 6
@@ -876,5 +867,5 @@ TOTAL: 3
876 867
877TESTWSP([append + dooffs + env],[], 868TESTWSP([append + dooffs + env],[],
878[-env dooffs 2 preface words V=2 -- extra arguments follow], 869[-env none -dooffs preface words -- V=2 -append-args extra arguments follow],
879[some words and var=$V], 870[some words and var=$V],
880[NF: 7 (2) 871[NF: 7 (2)
@@ -893,5 +884,5 @@ TOTAL: 4
893# Maxwords 884# Maxwords
894TESTWSP([maxwords],[], 885TESTWSP([maxwords],[],
895[trimnl maxwords 3], 886[-trimnl -maxwords 3],
896[ws_maxwords limits the number of returned words], 887[ws_maxwords limits the number of returned words],
897[NF: 3 888[NF: 3
@@ -903,5 +894,5 @@ TOTAL: 3
903 894
904TESTWSP([maxwords return_delims],[], 895TESTWSP([maxwords return_delims],[],
905[trimnl maxwords 8 return_delims delim :-], 896[-trimnl -maxwords 8 -return_delims -delim :-],
906[foo:::bar-:baz-quux:ux:zu], 897[foo:::bar-:baz-quux:ux:zu],
907[NF: 8 898[NF: 8
@@ -918,5 +909,5 @@ TOTAL: 8
918 909
919TESTWSP([maxwords return_delims -squeeze_delims],[], 910TESTWSP([maxwords return_delims -squeeze_delims],[],
920[trimnl maxwords 8 return_delims -squeeze_delims delim :-], 911[-trimnl -maxwords 8 -return_delims -nosqueeze_delims -delim :-],
921[foo:::bar-:baz:qux-], 912[foo:::bar-:baz:qux-],
922[NF: 8 913[NF: 8
@@ -933,5 +924,5 @@ TOTAL: 8
933 924
934TESTWSP([maxwords incremental],[], 925TESTWSP([maxwords incremental],[],
935[trimnl maxwords 3 incremental], 926[-trimnl -maxwords 3 -incremental],
936 [foo barbaz qux uz 927 [foo barbaz qux uz
937 928
@@ -951,5 +942,5 @@ TOTAL: 3
951])) 942]))
952 943
953TESTWSP([variable nosplit],[],[novar novarsplit], 944TESTWSP([variable nosplit],[],[-novar -novarsplit],
954[begin ${VAR:- a b} end], 945[begin ${VAR:- a b} end],
955[NF: 3 946[NF: 3
@@ -960,5 +951,5 @@ TOTAL: 3
960]) 951])
961 952
962TESTWSP([command nosplit],[],[nocmd nocmdsplit], 953TESTWSP([command nosplit],[],[-nocmd -nocmdsplit],
963[begin $(words a b) end], 954[begin $(words a b) end],
964[NF: 3 955[NF: 3
@@ -969,4 +960,17 @@ TOTAL: 3
969]) 960])
970 961
962TESTWSP([positional parameters],[],[one two three four five six seven eight nine ten eleven twelve],
963[$0 $5 ${10}
964$#],
965[NF: 3
9660: one
9671: six
9682: eleven
969TOTAL: 3
970NF: 1
9710: 12
972TOTAL: 1
973])
974
971m4_popdef([TESTWSP]) 975m4_popdef([TESTWSP])
972m4_popdef([wspnum]) 976m4_popdef([wspnum])
diff --git a/tests/wsp.c b/tests/wsp.c
index bd13e63..958d01f 100644
--- a/tests/wsp.c
+++ b/tests/wsp.c
@@ -1,4 +1,4 @@
1/* grecs - Gray's Extensible Configuration System 1/* grecs - Gray's Extensible Configuration System
2 Copyright (C) 2014-2016 Sergey Poznyakoff 2 Copyright (C) 2014-2019 Sergey Poznyakoff
3 3
4 Grecs is free software; you can redistribute it and/or modify it 4 Grecs is free software; you can redistribute it and/or modify it
@@ -30,68 +30,378 @@ extern char **environ;
30char *progname; 30char *progname;
31 31
32struct kwd 32/* Global options */
33enum
34 {
35 TRIMNL_OPTION = 0x01, /* Remove trailing newline */
36 PLAINTEXT_OPTION = 0x02 /* Print intput verbatim (no escapes) */
37 };
38
39/* Environment types */
40enum env_type
41 {
42 env_none, /* No environment */
43 env_null, /* Null environment */
44 env_sys /* Use system environment */
45 };
46
47struct wsclosure
33{ 48{
34 const char *name; 49 int options; /* Global options */
35 int tok; 50 struct wordsplit ws; /* The wordsplit structure */
51 int wsflags; /* Wordsplit flags */
52 enum env_type env_type; /* Environment type */
53 int offarg; /* Index of the first of the initial words in
54 the argv array. The ws.ws_dooffs field gives
55 the number of such variables. Forces the
56 WRDSF_DOOFFS flag. */
57 char **fenvbase; /* Environment for testing the ws_getenv function */
58 int fenvidx; /* Number of variables in fenvbase */
59 int fenvmax; /* Size of fenbase (entries) */
60 int append_start; /* First argument to append (index in argv) */
61 int append_count; /* Number of arguments to append */
36}; 62};
37 63
38struct kwd bool_keytab[] = { 64/* Command line option types */
39 { "append", WRDSF_APPEND }, 65enum
40 /*{ "reuse", WRDSF_REUSE },*/ 66 {
41 { "undef", WRDSF_UNDEF }, 67 ws_no_argument, /* Option requires no arguments */
42 { "novar", WRDSF_NOVAR }, 68 ws_boolean, /* Option is boolean (can be prefixed with -no) */
43 { "nocmd", WRDSF_NOCMD }, 69 ws_required_argument, /* Option requires one argument */
44 { "ws", WRDSF_WS }, 70 ws_multiple_arguments /* Option takes multiple arguments, terminated with
45 { "quote", WRDSF_QUOTE }, 71 "--" or end of argument list */
46 { "squote", WRDSF_SQUOTE }, 72 };
47 { "dquote", WRDSF_DQUOTE },
48 { "squeeze_delims", WRDSF_SQUEEZE_DELIMS },
49 { "return_delims", WRDSF_RETURN_DELIMS },
50 { "sed", WRDSF_SED_EXPR },
51 { "debug", WRDSF_SHOWDBG },
52 { "nosplit", WRDSF_NOSPLIT },
53 { "keepundef", WRDSF_KEEPUNDEF },
54 { "warnundef", WRDSF_WARNUNDEF },
55 { "cescapes", WRDSF_CESCAPES },
56 { "default", WRDSF_DEFFLAGS },
57 { "env_kv", WRDSF_ENV_KV },
58 { "incremental", WRDSF_INCREMENTAL },
59 { "pathexpand", WRDSF_PATHEXPAND },
60 { NULL, 0 }
61};
62 73
63struct kwd opt_keytab[] = { 74/* Structure describing a single command-line option */
64 { "nullglob", WRDSO_NULLGLOB }, 75struct wsopt
65 { "failglob", WRDSO_FAILGLOB }, 76{
66 { "dotglob", WRDSO_DOTGLOB }, 77 const char *name; /* Option name */
67 { "bskeep_words", WRDSO_BSKEEP_WORD }, 78 int tok; /* Corresponding flag */
68 { "bskeep_quote", WRDSO_BSKEEP_QUOTE }, 79 int arg; /* Option type (see the enum above) */
69 { "bskeep", WRDSO_BSKEEP_WORD|WRDSO_BSKEEP_QUOTE }, 80 void (*setfn) (int tok, int neg, char *arg, struct wsclosure *wsc);
70 { "novarsplit", WRDSO_NOVARSPLIT }, 81 /* Setter function */
71 { "nocmdsplit", WRDSO_NOCMDSPLIT },
72 { NULL, 0 }
73}; 82};
74 83
75struct kwd string_keytab[] = { 84/* Index of the next argument in the argv */
76 { "delim", WRDSF_DELIM }, 85static int wsoptind = -1;
77 { "comment", WRDSF_COMMENT },
78 { "escape", WRDSF_ESCAPE },
79 { NULL, 0 }
80};
81 86
87/* Parse next argument from the command line. Return EOF on end of arguments
88 or when the "--" argument is seen. */
82static int 89static int
83kwxlat (struct kwd *kwp, const char *str, int *res) 90getwsopt (int argc, char **argv, struct wsopt *wso, struct wsclosure *wsc)
84{ 91{
85 for (; kwp->name; kwp++) 92 int negate = 0;
86 if (strcmp (kwp->name, str) == 0) 93 char *opt;
87 { 94
88 *res = kwp->tok; 95 if (wsoptind == -1)
89 return 0; 96 wsoptind = 1;
90 } 97 if (wsoptind == argc)
91 return -1; 98 return EOF;
99
100 opt = argv[wsoptind++];
101 if (strcmp (opt, "--") == 0)
102 return EOF;
103 if (*opt != '-')
104 {
105 if (strchr (opt, '='))
106 {
107 assert (wsc->fenvidx < wsc->fenvmax - 1);
108 wsc->fenvbase[wsc->fenvidx++] = opt;
109 return 0;
110 }
111 wsoptind--;
112 return EOF;
113 }
114 opt++; /* skip past initial dash */
115 if (strncmp (opt, "no-", 3) == 0)
116 {
117 negate = 1;
118 opt += 3;
119 }
120 else if (strncmp (opt, "no", 2) == 0)
121 {
122 negate = 1;
123 opt += 2;
124 }
125
126 for (; wso->name; wso++)
127 {
128 if (wso->arg == ws_boolean && wso->name[0] == 'n' && wso->name[1] == 'o'
129 && strcmp (wso->name + 2, opt) == 0)
130 {
131 negate ^= 1;
132 break;
133 }
134 if (strcmp (wso->name, opt) == 0)
135 break;
136 }
137
138 if (wso->name)
139 {
140 char *arg;
141 if (wso->arg == ws_multiple_arguments)
142 {
143 while (1)
144 {
145 if (wsoptind == argc)
146 break;
147 arg = argv[wsoptind++];
148 if (strcmp (arg, "--") == 0)
149 break;
150 wso->setfn (wso->tok, negate, arg, wsc);
151 }
152 }
153 else
154 {
155 if (wso->arg == ws_required_argument)
156 {
157 if (wsoptind == argc)
158 {
159 fprintf (stderr, "%s: missing arguments for -%s\n",
160 progname, opt);
161 exit (1);
162 }
163 arg = argv[wsoptind++];
164 }
165 wso->setfn (wso->tok, negate, arg, wsc);
166 }
167 return 0;
168 }
169
170 fprintf (stderr, "%s: unrecognized option: -%s\n",
171 progname, opt);
172 fprintf (stderr, "%s: try %s -help for more detail\n",
173 progname, progname);
174 exit (1);
175}
176
177/* Setter functions for various options */
178
179static void
180setfn_flag (int flag, int neg, char *arg, struct wsclosure *wsc)
181{
182 if (neg)
183 wsc->wsflags &= ~flag;
184 else
185 wsc->wsflags |= flag;
186}
187
188static void
189setfn_option (int flag, int neg, char *arg, struct wsclosure *wsc)
190{
191 wsc->wsflags |= WRDSF_OPTIONS;
192 if (neg)
193 wsc->ws.ws_options &= ~flag;
194 else
195 wsc->ws.ws_options |= flag;
196}
197
198static void
199setfn_delim (int flag, int neg, char *arg, struct wsclosure *wsc)
200{
201 wsc->wsflags |= flag;
202 wsc->ws.ws_delim = arg;
203}
204
205static void
206setfn_comment (int flag, int neg, char *arg, struct wsclosure *wsc)
207{
208 wsc->wsflags |= flag;
209 wsc->ws.ws_comment = arg;
92} 210}
93 211
94static void 212static void
95help () 213set_escape_string (wordsplit_t *ws, int *wsflags, int q, const char *str)
214{
215 if (*str == ':')
216 {
217 while (*++str != ':')
218 {
219 int f;
220 switch (*str)
221 {
222 case '+':
223 f = WRDSO_BSKEEP;
224 break;
225
226 case '0':
227 f = WRDSO_OESC;
228 break;
229
230 case 'x':
231 f = WRDSO_XESC;
232 break;
233
234 default:
235 fprintf (stderr, "%s: invalid escape flag near %s\n",
236 progname, str);
237 abort ();
238 }
239 WRDSO_ESC_SET (ws, q, f);
240 }
241 *wsflags |= WRDSF_OPTIONS;
242 ++str;
243 }
244 ws->ws_escape[q] = str;
245}
246
247static void
248setfn_escape (int flag, int neg, char *arg, struct wsclosure *wsc)
249{
250 wsc->wsflags |= flag;
251 set_escape_string (&wsc->ws, &wsc->wsflags, 0, arg);
252 set_escape_string (&wsc->ws, &wsc->wsflags, 1, arg);
253}
254
255static void
256setfn_escape_qw (char *arg, int quote, struct wsclosure *wsc)
257{
258 if (!(wsc->wsflags & WRDSF_ESCAPE))
259 {
260 wsc->wsflags |= WRDSF_ESCAPE;
261 wsc->ws.ws_escape[!quote] = NULL;
262 }
263 set_escape_string (&wsc->ws, &wsc->wsflags, quote, arg);
264}
265
266static void
267setfn_escape_word (int flag, int neg, char *arg, struct wsclosure *wsc)
268{
269 setfn_escape_qw (arg, 0, wsc);
270}
271
272static void
273setfn_escape_quote (int flag, int neg, char *arg, struct wsclosure *wsc)
274{
275 setfn_escape_qw (arg, 1, wsc);
276}
277
278static void
279setfn_maxwords (int flag, int neg, char *arg, struct wsclosure *wsc)
280{
281 char *p;
282
283 wsc->wsflags |= WRDSF_OPTIONS;
284 wsc->ws.ws_options |= WRDSO_MAXWORDS;
285
286 wsc->ws.ws_maxwords = strtoul (arg, &p, 10);
287 if (*p)
288 {
289 fprintf (stderr, "%s: invalid number: %s\n", progname, arg);
290 exit (1);
291 }
292}
293
294static void
295setfn_global (int flag, int neg, char *arg, struct wsclosure *wsc)
296{
297 if (neg)
298 wsc->options &= ~flag;
299 else
300 wsc->options |= flag;
301}
302
303static void
304setfn_env (int flag, int neg, char *arg, struct wsclosure *wsc)
305{
306 if (strcmp (arg, "none") == 0)
307 wsc->env_type = env_none;
308 else if (strcmp (arg, "null") == 0)
309 wsc->env_type = env_null;
310 else if (strcmp (arg, "sys") == 0)
311 wsc->env_type = env_sys;
312 else
313 {
314 fprintf (stderr, "%s: environment flag: %s\n", progname, arg);
315 exit (1);
316 }
317}
318
319static void
320setfn_dooffs (int flag, int neg, char *arg, struct wsclosure *wsc)
321{
322 if (!(wsc->wsflags & flag))
323 {
324 wsc->wsflags |= flag;
325 wsc->offarg = wsoptind - 1;
326 wsc->ws.ws_offs = 0;
327 }
328 wsc->ws.ws_offs++;
329}
330
331static void
332setfn_append (int flag, int neg, char *arg, struct wsclosure *wsc)
333{
334 if (wsc->append_count == 0)
335 wsc->append_start = wsoptind - 1;
336 wsc->append_count++;
337}
338
339static void help (void);
340
341static void
342setfn_help (int flag, int neg, char *arg, struct wsclosure *wsc)
343{
344 help ();
345 exit (0);
346}
347
348/* Available options: */
349struct wsopt opttab[] = {
350 /* Global options */
351 { "trimnl", TRIMNL_OPTION, ws_boolean, setfn_global },
352 { "plaintext", PLAINTEXT_OPTION, ws_boolean, setfn_global },
353 { "env", 0, ws_required_argument, setfn_env },
354
355 /* Wordsplit flags */
356 { "append", WRDSF_APPEND, ws_boolean, setfn_flag },
357 /*{ "reuse", WRDSF_REUSE, ws_boolean, setfn_flag },*/
358 { "undef", WRDSF_UNDEF, ws_boolean, setfn_flag },
359 { "novar", WRDSF_NOVAR, ws_boolean, setfn_flag },
360 { "nocmd", WRDSF_NOCMD, ws_boolean, setfn_flag },
361 { "ws", WRDSF_WS, ws_boolean, setfn_flag },
362 { "quote", WRDSF_QUOTE, ws_boolean, setfn_flag },
363 { "squote", WRDSF_SQUOTE, ws_boolean, setfn_flag },
364 { "dquote", WRDSF_DQUOTE, ws_boolean, setfn_flag },
365 { "squeeze_delims", WRDSF_SQUEEZE_DELIMS, ws_boolean, setfn_flag },
366 { "return_delims", WRDSF_RETURN_DELIMS, ws_boolean, setfn_flag },
367 { "sed", WRDSF_SED_EXPR, ws_boolean, setfn_flag },
368 { "debug", WRDSF_SHOWDBG, ws_boolean, setfn_flag },
369 { "nosplit", WRDSF_NOSPLIT, ws_boolean, setfn_flag },
370 { "keepundef", WRDSF_KEEPUNDEF, ws_boolean, setfn_flag },
371 { "warnundef", WRDSF_WARNUNDEF, ws_boolean, setfn_flag },
372 { "cescapes", WRDSF_CESCAPES, ws_boolean, setfn_flag },
373 { "default", WRDSF_DEFFLAGS, ws_boolean, setfn_flag },
374 { "env_kv", WRDSF_ENV_KV, ws_boolean, setfn_flag },
375 { "incremental", WRDSF_INCREMENTAL, ws_boolean, setfn_flag },
376 { "pathexpand", WRDSF_PATHEXPAND, ws_boolean, setfn_flag },
377 { "default", WRDSF_DEFFLAGS, ws_boolean, setfn_flag },
378 /* Wordsplit options */
379 { "nullglob", WRDSO_NULLGLOB, ws_boolean, setfn_option },
380 { "failglob", WRDSO_FAILGLOB, ws_boolean, setfn_option },
381 { "dotglob", WRDSO_DOTGLOB, ws_boolean, setfn_option },
382 { "bskeep_words", WRDSO_BSKEEP_WORD, ws_boolean, setfn_option },
383 { "bskeep_quote", WRDSO_BSKEEP_QUOTE, ws_boolean, setfn_option },
384 { "bskeep", WRDSO_BSKEEP_WORD|WRDSO_BSKEEP_QUOTE,
385 ws_boolean, setfn_option },
386 { "novarsplit", WRDSO_NOVARSPLIT, ws_boolean, setfn_option },
387 { "nocmdsplit", WRDSO_NOCMDSPLIT, ws_boolean, setfn_option },
388 { "maxwords", WRDSO_MAXWORDS, ws_required_argument, setfn_maxwords },
389 /* String options */
390 { "delim", WRDSF_DELIM, ws_required_argument, setfn_delim },
391 { "comment", WRDSF_COMMENT,ws_required_argument, setfn_comment },
392 { "escape", WRDSF_ESCAPE, ws_required_argument, setfn_escape },
393 { "escape-word", WRDSF_ESCAPE, ws_required_argument, setfn_escape_word },
394 { "escape-quote", WRDSF_ESCAPE, ws_required_argument, setfn_escape_quote },
395
396 { "dooffs", WRDSF_DOOFFS, ws_multiple_arguments, setfn_dooffs },
397 { "append-args", 0, ws_multiple_arguments, setfn_append },
398
399 { "help", 0, ws_no_argument, setfn_help },
400
401 { NULL, 0 }
402};
403
404static void
405help (void)
96{ 406{
97 size_t i; 407 size_t i;
@@ -99,28 +409,27 @@ help ()
99 printf ("usage: %s [options] [VAR=VALUE...] [-- EXTRA...]\n", progname); 409 printf ("usage: %s [options] [VAR=VALUE...] [-- EXTRA...]\n", progname);
100 printf ("options are:\n"); 410 printf ("options are:\n");
101 printf (" [-]trimnl\n"); 411 for (i = 0; opttab[i].name; i++)
102 printf (" [-]plaintext\n");
103 printf (" -env\n");
104 printf (" env sys|none|null\n");
105 putchar ('\n');
106 for (i = 0; bool_keytab[i].name; i++)
107 printf (" [-]%s\n", bool_keytab[i].name);
108 putchar ('\n');
109 for (i = 0; string_keytab[i].name; i++)
110 { 412 {
111 printf (" -%s\n", string_keytab[i].name); 413 printf (" -");
112 printf (" %s ARG\n", string_keytab[i].name); 414 if (opttab[i].arg == ws_boolean)
113 } 415 printf ("[no]");
114 printf (" escape-word ARG\n"); 416 if (strncmp (opttab[i].name, "no", 2) == 0)
115 printf (" escape-quote ARG\n"); 417 printf ("%s", opttab[i].name + 2);
116 putchar ('\n'); 418 else
117 for (i = 0; opt_keytab[i].name; i++) 419 printf ("%s", opttab[i].name);
118 { 420 switch (opttab[i].arg)
119 printf (" [-]%s\n", opt_keytab[i].name); 421 {
422 case ws_no_argument:
423 case ws_boolean:
424 break;
425 case ws_required_argument:
426 printf(" ARG");
427 break;
428 case ws_multiple_arguments:
429 printf(" ARGS... --");
430 }
431 putchar ('\n');
120 } 432 }
121 putchar ('\n'); 433 putchar ('\n');
122 printf (" -dooffs\n");
123 printf (" dooffs COUNT ARGS...\n");
124 exit (0);
125} 434}
126 435
@@ -300,305 +609,50 @@ wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
300} 609}
301 610
302enum env_type
303 {
304 env_none,
305 env_null,
306 env_sys
307 };
308
309struct kwd env_keytab[] = {
310 { "none", env_none },
311 { "null", env_null },
312 { "sys", env_sys },
313 { NULL }
314};
315
316static void
317set_escape_string (wordsplit_t *ws, int *wsflags, int q, const char *str)
318{
319 if (*str == ':')
320 {
321 while (*++str != ':')
322 {
323 int f;
324 switch (*str)
325 {
326 case '+':
327 f = WRDSO_BSKEEP;
328 break;
329
330 case '0':
331 f = WRDSO_OESC;
332 break;
333
334 case 'x':
335 f = WRDSO_XESC;
336 break;
337
338 default:
339 fprintf (stderr, "%s: invalid escape flag near %s\n",
340 progname, str);
341 abort ();
342 }
343 WRDSO_ESC_SET (ws, q, f);
344 }
345 *wsflags |= WRDSF_OPTIONS;
346 ++str;
347 }
348 ws->ws_escape[q] = str;
349}
350
351int 611int
352main (int argc, char **argv) 612main (int argc, char **argv)
353{ 613{
614 struct wsclosure wsc;
615 char *fenvbase[128];
354 char buf[1024], *ptr, *saved_ptr; 616 char buf[1024], *ptr, *saved_ptr;
355 int i, offarg = 0; 617 int next_call = 0;
356 int trimnl_option = 0; 618
357 int plaintext_option = 0; 619 wsc.options = 0;
358 int wsflags = (WRDSF_DEFFLAGS & ~WRDSF_NOVAR) | 620 wsc.wsflags = 0;
621 wsc.env_type = env_sys;
622 wsc.offarg = 0;
623 wsc.fenvbase = fenvbase;
624 wsc.fenvmax = sizeof (fenvbase) / sizeof (fenvbase[0]);
625 wsc.fenvidx = 0;
626 wsc.ws.ws_options = 0;
627 wsc.wsflags = (WRDSF_DEFFLAGS & ~WRDSF_NOVAR) |
359 WRDSF_ENOMEMABRT | 628 WRDSF_ENOMEMABRT |
360 WRDSF_SHOWERR; 629 WRDSF_SHOWERR;
361 wordsplit_t ws; 630 wsc.append_count = 0;
362 int next_call = 0;
363 char *fenvbase[128];
364 size_t fenvidx = 0;
365 size_t fenvmax = sizeof (fenvbase) / sizeof (fenvbase[0]);
366 int use_env = env_sys;
367 int appendc = 0;
368 char **appendv = NULL;
369 631
370 progname = argv[0]; 632 progname = argv[0];
633 while (getwsopt (argc, argv, opttab, &wsc) != EOF)
634 ;
371 635
372 ws.ws_options = 0; 636 if (wsc.fenvidx > 0)
373 for (i = 1; i < argc; i++)
374 { 637 {
375 char *opt = argv[i]; 638 wsc.fenvbase[wsc.fenvidx] = NULL;
376 int negate; 639 wsc.wsflags |= WRDSF_GETVAR | WRDSF_CLOSURE;
377 int flag; 640 wsc.ws.ws_getvar = wsp_getvar;
378 641 wsc.ws.ws_closure = fenvbase;
379 if (opt[0] == '-')
380 {
381 if (opt[1] == '-' && opt[2] == 0)
382 {
383 appendc = argc - i - 1;
384 appendv = argv + i + 1;
385 break;
386 }
387 negate = 1;
388 opt++;
389 }
390 else if (opt[0] == '+')
391 {
392 negate = 0;
393 opt++;
394 }
395 else
396 negate = 0;
397
398 if (strcmp (opt, "h") == 0 ||
399 strcmp (opt, "help") == 0 ||
400 strcmp (opt, "-help") == 0)
401 {
402 help ();
403 }
404
405 if (strcmp (opt, "trimnl") == 0)
406 {
407 trimnl_option = !negate;
408 continue;
409 }
410
411 if (strcmp (opt, "plaintext") == 0)
412 {
413 plaintext_option = !negate;
414 continue;
415 }
416
417 if (strcmp (opt, "env") == 0)
418 {
419 if (negate)
420 use_env = env_none;
421 else
422 {
423 i++;
424 if (i == argc)
425 {
426 fprintf (stderr, "%s: missing argument for env\n",
427 progname);
428 exit (1);
429 }
430
431 if (kwxlat (env_keytab, argv[i], &use_env))
432 {
433 fprintf (stderr, "%s: invalid argument for env\n",
434 progname);
435 exit (1);
436 }
437 }
438 continue;
439 }
440
441 if (kwxlat (bool_keytab, opt, &flag) == 0)
442 {
443 if (negate)
444 wsflags &= ~flag;
445 else
446 wsflags |= flag;
447 continue;
448 }
449
450 if (kwxlat (string_keytab, opt, &flag) == 0)
451 {
452 if (negate)
453 wsflags &= ~flag;
454 else
455 {
456 i++;
457 if (i == argc)
458 {
459 fprintf (stderr, "%s: missing argument for %s\n",
460 progname, opt);
461 exit (1);
462 }
463
464 switch (flag)
465 {
466 case WRDSF_DELIM:
467 ws.ws_delim = argv[i];
468 break;
469
470 case WRDSF_COMMENT:
471 ws.ws_comment = argv[i];
472 break;
473
474 case WRDSF_ESCAPE:
475 set_escape_string (&ws, &wsflags, 0, argv[i]);
476 set_escape_string (&ws, &wsflags, 1, argv[i]);
477 break;
478 }
479
480 wsflags |= flag;
481 }
482 continue;
483 }
484
485 if (strcmp (opt, "escape-word") == 0
486 || strcmp (opt, "escape-quote") == 0)
487 {
488 int q = opt[7] == 'q';
489
490 i++;
491 if (i == argc)
492 {
493 fprintf (stderr, "%s: missing argument for %s\n",
494 progname, opt);
495 exit (1);
496 }
497 if (!(wsflags & WRDSF_ESCAPE))
498 {
499 wsflags |= WRDSF_ESCAPE;
500 ws.ws_escape[!q] = NULL;
501 }
502 set_escape_string (&ws, &wsflags, q, argv[i]);
503 continue;
504 }
505
506 if (strcmp (opt, "dooffs") == 0)
507 {
508 if (negate)
509 wsflags &= ~WRDSF_DOOFFS;
510 else
511 {
512 char *p;
513
514 i++;
515
516 if (i == argc)
517 {
518 fprintf (stderr, "%s: missing arguments for %s\n",
519 progname, opt);
520 exit (1);
521 }
522 ws.ws_offs = strtoul (argv[i], &p, 10);
523 if (*p)
524 {
525 fprintf (stderr, "%s: invalid number: %s\n",
526 progname, argv[i]);
527 exit (1);
528 }
529
530 i++;
531 if (i + ws.ws_offs > argc)
532 {
533 fprintf (stderr, "%s: not enough arguments for %s\n",
534 progname, opt);
535 exit (1);
536 }
537 offarg = i;
538 i += ws.ws_offs - 1;
539 wsflags |= WRDSF_DOOFFS;
540 }
541 continue;
542 }
543
544 if (kwxlat (opt_keytab, opt, &flag) == 0)
545 {
546 wsflags |= WRDSF_OPTIONS;
547 if (negate)
548 ws.ws_options &= ~flag;
549 else
550 ws.ws_options |= flag;
551 continue;
552 }
553
554 if (strcmp (opt, "maxwords") == 0)
555 {
556 char *p;
557 wsflags |= WRDSF_OPTIONS;
558 ws.ws_options |= WRDSO_MAXWORDS;
559
560 i++;
561
562 if (i == argc)
563 {
564 fprintf (stderr, "%s: missing arguments for %s\n",
565 progname, opt);
566 exit (1);
567 }
568 ws.ws_maxwords = strtoul (argv[i], &p, 10);
569 if (*p)
570 {
571 fprintf (stderr, "%s: invalid number: %s\n",
572 progname, argv[i]);
573 exit (1);
574 }
575 continue;
576 }
577
578 if (strchr (opt, '='))
579 {
580 assert (fenvidx < fenvmax - 1);
581 fenvbase[fenvidx++] = opt;
582 continue;
583 }
584
585 fprintf (stderr, "%s: unrecognized argument: %s\n",
586 progname, opt);
587 exit (1);
588 } 642 }
589 643
590 if (fenvidx) 644 if (wsoptind < argc)
591 { 645 {
592 fenvbase[fenvidx] = NULL; 646 wsc.ws.ws_paramc = argc - wsoptind;
593 wsflags |= WRDSF_GETVAR | WRDSF_CLOSURE; 647 wsc.ws.ws_paramv = (char const **) (argv + wsoptind);
594 ws.ws_getvar = wsp_getvar; 648 wsc.ws.ws_options |= WRDSO_PARAMV|WRDSO_PARAM_NEGIDX;
595 ws.ws_closure = fenvbase; 649 wsc.wsflags |= WRDSF_OPTIONS;
596 } 650 }
597 651
598 switch (use_env) 652 switch (wsc.env_type)
599 { 653 {
600 case env_null: 654 case env_null:
601 wsflags |= WRDSF_ENV; 655 wsc.wsflags |= WRDSF_ENV;
602 ws.ws_env = NULL; 656 wsc.ws.ws_env = NULL;
603 break; 657 break;
604 658
@@ -607,17 +661,17 @@ main (int argc, char **argv)
607 661
608 case env_sys: 662 case env_sys:
609 wsflags |= WRDSF_ENV; 663 wsc.wsflags |= WRDSF_ENV;
610 if (wsflags & WRDSF_ENV_KV) 664 if (wsc.wsflags & WRDSF_ENV_KV)
611 ws.ws_env = (const char **) make_env_kv (); 665 wsc.ws.ws_env = (const char **) make_env_kv ();
612 else 666 else
613 ws.ws_env = (const char **) environ; 667 wsc.ws.ws_env = (const char **) environ;
614 break; 668 break;
615 } 669 }
616 670
617 if (!(wsflags & WRDSF_NOCMD)) 671 if (!(wsc.wsflags & WRDSF_NOCMD))
618 ws.ws_command = wsp_runcmd; 672 wsc.ws.ws_command = wsp_runcmd;
619 673
620 if (wsflags & WRDSF_INCREMENTAL) 674 if (wsc.wsflags & WRDSF_INCREMENTAL)
621 trimnl_option = 1; 675 wsc.options |= TRIMNL_OPTION;
622 676
623 next_call = 0; 677 next_call = 0;
@@ -627,5 +681,5 @@ main (int argc, char **argv)
627 size_t i; 681 size_t i;
628 682
629 if (trimnl_option) 683 if (wsc.options & TRIMNL_OPTION)
630 { 684 {
631 size_t len = strlen (ptr); 685 size_t len = strlen (ptr);
@@ -634,5 +688,5 @@ main (int argc, char **argv)
634 } 688 }
635 689
636 if (wsflags & WRDSF_INCREMENTAL) 690 if (wsc.wsflags & WRDSF_INCREMENTAL)
637 { 691 {
638 if (next_call) 692 if (next_call)
@@ -652,48 +706,50 @@ main (int argc, char **argv)
652 } 706 }
653 707
654 rc = wordsplit (ptr, &ws, wsflags); 708 rc = wordsplit (ptr, &wsc.ws, wsc.wsflags);
655 if (rc) 709 if (rc)
656 { 710 {
657 if (!(wsflags & WRDSF_SHOWERR)) 711 if (!(wsc.wsflags & WRDSF_SHOWERR))
658 wordsplit_perror (&ws); 712 wordsplit_perror (&wsc.ws);
659 continue; 713 continue;
660 } 714 }
661 715
662 if (offarg) 716 if (wsc.offarg)
663 { 717 {
664 for (i = 0; i < ws.ws_offs; i++) 718 size_t i;
665 ws.ws_wordv[i] = argv[offarg + i]; 719 for (i = 0; i < wsc.ws.ws_offs; i++)
666 offarg = 0; 720 wsc.ws.ws_wordv[i] = argv[wsc.offarg + i];
721 wsc.offarg = 0;
667 } 722 }
668 723
669 if (appendc) 724 if (wsc.append_count)
670 { 725 {
671 rc = wordsplit_append (&ws, appendc, appendv); 726 rc = wordsplit_append (&wsc.ws, wsc.append_count,
727 argv + wsc.append_start);
672 if (rc) 728 if (rc)
673 { 729 {
674 if (!(wsflags & WRDSF_SHOWERR)) 730 if (!(wsc.wsflags & WRDSF_SHOWERR))
675 wordsplit_perror (&ws); 731 wordsplit_perror (&wsc.ws);
676 continue; 732 continue;
677 } 733 }
678 } 734 }
679 735
680 wsflags |= WRDSF_REUSE | (ws.ws_flags & WRDSF_ENV); 736 wsc.wsflags |= WRDSF_REUSE;
681 printf ("NF: %lu", (unsigned long) ws.ws_wordc); 737 printf ("NF: %lu", (unsigned long) wsc.ws.ws_wordc);
682 if (wsflags & WRDSF_DOOFFS) 738 if (wsc.wsflags & WRDSF_DOOFFS)
683 printf (" (%lu)", (unsigned long) ws.ws_offs); 739 printf (" (%lu)", (unsigned long) wsc.ws.ws_offs);
684 putchar ('\n'); 740 putchar ('\n');
685 for (i = 0; i < ws.ws_offs; i++) 741 for (i = 0; i < wsc.ws.ws_offs; i++)
686 { 742 {
687 printf ("(%lu): ", (unsigned long) i); 743 printf ("(%lu): ", (unsigned long) i);
688 print_qword (ws.ws_wordv[i], plaintext_option); 744 print_qword (wsc.ws.ws_wordv[i], wsc.options & PLAINTEXT_OPTION);
689 putchar ('\n'); 745 putchar ('\n');
690 } 746 }
691 for (; i < ws.ws_offs + ws.ws_wordc; i++) 747 for (; i < wsc.ws.ws_offs + wsc.ws.ws_wordc; i++)
692 { 748 {
693 printf ("%lu: ", (unsigned long) i); 749 printf ("%lu: ", (unsigned long) i);
694 print_qword (ws.ws_wordv[i], plaintext_option); 750 print_qword (wsc.ws.ws_wordv[i], wsc.options & PLAINTEXT_OPTION);
695 putchar ('\n'); 751 putchar ('\n');
696 } 752 }
697 printf ("TOTAL: %lu\n", (unsigned long) ws.ws_wordi); 753 printf ("TOTAL: %lu\n", (unsigned long) wsc.ws.ws_wordi);
698 } 754 }
699 return 0; 755 return 0;

Return to:

Send suggestions and report system problems to the System administrator.