aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
@@ -77,2 +77,12 @@ struct wordsplit
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
@@ -101,3 +111,3 @@ struct wordsplit
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. */
@@ -228,2 +238,8 @@ struct wordsplit
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
@@ -252,2 +268,3 @@ struct wordsplit
252#define WRDSE_USERERR 9 268#define WRDSE_USERERR 9
269#define WRDSE_BADPARAM 10
253 270
@@ -258,2 +275,3 @@ void 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);
diff --git a/src/wordsplit.c b/src/wordsplit.c
index 521a1eb..6a33636 100644
--- a/src/wordsplit.c
+++ b/src/wordsplit.c
@@ -1,3 +1,3 @@
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
@@ -29,2 +29,3 @@
29#include <glob.h> 29#include <glob.h>
30#include <limits.h>
30 31
@@ -58,2 +59,5 @@
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
@@ -286,2 +290,10 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len,
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
@@ -1038,3 +1050,3 @@ static 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{
@@ -1073,3 +1085,3 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
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);
@@ -1144,2 +1156,66 @@ wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
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
@@ -1179,2 +1255,4 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1179 struct wordsplit ws; 1255 struct wordsplit ws;
1256 int is_param = 0;
1257 long param_idx = 0;
1180 1258
@@ -1187,3 +1265,3 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1187 } 1265 }
1188 else if (ISDIGIT (str[0])) 1266 else if ((wsp->ws_options & WRDSO_PARAMV) && ISDIGIT (str[0]))
1189 { 1267 {
@@ -1191,4 +1269,27 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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 {
@@ -1196,3 +1297,3 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
1196 len--; 1297 len--;
1197 for (i = 1; i < len; i++) 1298 for (i = str[0] == '-' ? 1 : 0; i < len; i++)
1198 { 1299 {
@@ -1224,5 +1325,12 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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 {
@@ -1236,2 +1344,6 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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)
@@ -1256,10 +1368,11 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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 }
@@ -1268,7 +1381,22 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
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