diff options
-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 | |||
@@ -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); | |||
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); |
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 | |||
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 | { |
@@ -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 | ||
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 |
@@ -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 |