diff options
-rw-r--r-- | include/wordsplit.h | 1 | ||||
-rw-r--r-- | src/wordsplit.c | 30 | ||||
-rw-r--r-- | tests/wordsplit.at | 34 |
3 files changed, 62 insertions, 3 deletions
diff --git a/include/wordsplit.h b/include/wordsplit.h index d4975b3..2fac3c6 100644 --- a/include/wordsplit.h +++ b/include/wordsplit.h | |||
@@ -111,24 +111,25 @@ struct wordsplit | |||
111 | return values. */ | 111 | return values. */ |
112 | 112 | ||
113 | const char *ws_input; /* Input string (the S argument to wordsplit. */ | 113 | const char *ws_input; /* Input string (the S argument to wordsplit. */ |
114 | size_t ws_len; /* Length of ws_input. */ | 114 | size_t ws_len; /* Length of ws_input. */ |
115 | size_t ws_endp; /* Points past the last processed byte in | 115 | size_t ws_endp; /* Points past the last processed byte in |
116 | ws_input. */ | 116 | ws_input. */ |
117 | int ws_errno; /* [Output] Error code, if an error occurred. */ | 117 | int ws_errno; /* [Output] Error code, if an error occurred. */ |
118 | char *ws_usererr; /* Points to textual description of | 118 | char *ws_usererr; /* Points to textual description of |
119 | the error, if ws_errno is WRDSE_USERERR. Must | 119 | the error, if ws_errno is WRDSE_USERERR. Must |
120 | be allocated with malloc(3). */ | 120 | be allocated with malloc(3). */ |
121 | struct wordsplit_node *ws_head, *ws_tail; | 121 | struct wordsplit_node *ws_head, *ws_tail; |
122 | /* Doubly-linked list of parsed out nodes. */ | 122 | /* Doubly-linked list of parsed out nodes. */ |
123 | char ws_sep[2]; /* Temporary storage used during splitting */ | ||
123 | int ws_lvl; /* Invocation nesting level. */ | 124 | int ws_lvl; /* Invocation nesting level. */ |
124 | }; | 125 | }; |
125 | 126 | ||
126 | /* Initial size for ws_env, if allocated automatically */ | 127 | /* Initial size for ws_env, if allocated automatically */ |
127 | #define WORDSPLIT_ENV_INIT 16 | 128 | #define WORDSPLIT_ENV_INIT 16 |
128 | 129 | ||
129 | /* Wordsplit flags. */ | 130 | /* Wordsplit flags. */ |
130 | /* Append the words found to the array resulting from a previous | 131 | /* Append the words found to the array resulting from a previous |
131 | call. */ | 132 | call. */ |
132 | #define WRDSF_APPEND 0x00000001 | 133 | #define WRDSF_APPEND 0x00000001 |
133 | /* Insert ws_offs initial NULLs in the array ws_wordv. | 134 | /* Insert ws_offs initial NULLs in the array ws_wordv. |
134 | (These are not counted in the returned ws_wordc.) */ | 135 | (These are not counted in the returned ws_wordc.) */ |
diff --git a/src/wordsplit.c b/src/wordsplit.c index f563725..4e633fa 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c | |||
@@ -247,24 +247,27 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | 249 | ||
250 | wsp->ws_input = input; | 250 | wsp->ws_input = input; |
251 | wsp->ws_len = len; | 251 | wsp->ws_len = len; |
252 | 252 | ||
253 | if (!(wsp->ws_flags & WRDSF_DOOFFS)) | 253 | if (!(wsp->ws_flags & WRDSF_DOOFFS)) |
254 | wsp->ws_offs = 0; | 254 | wsp->ws_offs = 0; |
255 | 255 | ||
256 | if (!(wsp->ws_flags & WRDSF_DELIM)) | 256 | if (!(wsp->ws_flags & WRDSF_DELIM)) |
257 | wsp->ws_delim = " \t\n"; | 257 | wsp->ws_delim = " \t\n"; |
258 | 258 | ||
259 | wsp->ws_sep[0] = wsp->ws_delim[0]; | ||
260 | wsp->ws_sep[1] = 0; | ||
261 | |||
259 | if (!(wsp->ws_flags & WRDSF_COMMENT)) | 262 | if (!(wsp->ws_flags & WRDSF_COMMENT)) |
260 | wsp->ws_comment = NULL; | 263 | wsp->ws_comment = NULL; |
261 | 264 | ||
262 | if (!(wsp->ws_flags & WRDSF_CLOSURE)) | 265 | if (!(wsp->ws_flags & WRDSF_CLOSURE)) |
263 | wsp->ws_closure = NULL; | 266 | wsp->ws_closure = NULL; |
264 | 267 | ||
265 | if (!(wsp->ws_flags & WRDSF_OPTIONS)) | 268 | if (!(wsp->ws_flags & WRDSF_OPTIONS)) |
266 | wsp->ws_options = 0; | 269 | wsp->ws_options = 0; |
267 | 270 | ||
268 | if (wsp->ws_flags & WRDSF_ESCAPE) | 271 | if (wsp->ws_flags & WRDSF_ESCAPE) |
269 | { | 272 | { |
270 | if (!wsp->ws_escape[WRDSX_WORD]) | 273 | if (!wsp->ws_escape[WRDSX_WORD]) |
@@ -340,25 +343,25 @@ alloc_space (struct wordsplit *wsp, size_t count) | |||
340 | return 0; | 343 | return 0; |
341 | } | 344 | } |
342 | 345 | ||
343 | 346 | ||
344 | /* Node state flags */ | 347 | /* Node state flags */ |
345 | #define _WSNF_NULL 0x01 /* null node (a noop) */ | 348 | #define _WSNF_NULL 0x01 /* null node (a noop) */ |
346 | #define _WSNF_WORD 0x02 /* node contains word in v.word */ | 349 | #define _WSNF_WORD 0x02 /* node contains word in v.word */ |
347 | #define _WSNF_QUOTE 0x04 /* text is quoted */ | 350 | #define _WSNF_QUOTE 0x04 /* text is quoted */ |
348 | #define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */ | 351 | #define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */ |
349 | #define _WSNF_JOIN 0x10 /* node must be joined with the next node */ | 352 | #define _WSNF_JOIN 0x10 /* node must be joined with the next node */ |
350 | #define _WSNF_SEXP 0x20 /* is a sed expression */ | 353 | #define _WSNF_SEXP 0x20 /* is a sed expression */ |
351 | #define _WSNF_DELIM 0x40 /* node is a delimiter */ | 354 | #define _WSNF_DELIM 0x40 /* node is a delimiter */ |
352 | 355 | #define _WSNF_CONST 0x80 /* with _WSNF_WORD: v.word is constant */ | |
353 | #define _WSNF_EMPTYOK 0x0100 /* special flag indicating that | 356 | #define _WSNF_EMPTYOK 0x0100 /* special flag indicating that |
354 | wordsplit_add_segm must add the | 357 | wordsplit_add_segm must add the |
355 | segment even if it is empty */ | 358 | segment even if it is empty */ |
356 | 359 | ||
357 | struct wordsplit_node | 360 | struct wordsplit_node |
358 | { | 361 | { |
359 | struct wordsplit_node *prev; /* Previous element */ | 362 | struct wordsplit_node *prev; /* Previous element */ |
360 | struct wordsplit_node *next; /* Next element */ | 363 | struct wordsplit_node *next; /* Next element */ |
361 | int flags; /* Node flags */ | 364 | int flags; /* Node flags */ |
362 | union | 365 | union |
363 | { | 366 | { |
364 | struct | 367 | struct |
@@ -432,25 +435,25 @@ static int | |||
432 | wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode) | 435 | wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode) |
433 | { | 436 | { |
434 | struct wordsplit_node *node = calloc (1, sizeof (*node)); | 437 | struct wordsplit_node *node = calloc (1, sizeof (*node)); |
435 | if (!node) | 438 | if (!node) |
436 | return _wsplt_nomem (wsp); | 439 | return _wsplt_nomem (wsp); |
437 | *pnode = node; | 440 | *pnode = node; |
438 | return 0; | 441 | return 0; |
439 | } | 442 | } |
440 | 443 | ||
441 | static void | 444 | static void |
442 | wsnode_free (struct wordsplit_node *p) | 445 | wsnode_free (struct wordsplit_node *p) |
443 | { | 446 | { |
444 | if (p->flags & _WSNF_WORD) | 447 | if ((p->flags & (_WSNF_WORD|_WSNF_CONST)) == _WSNF_WORD) |
445 | free (p->v.word); | 448 | free (p->v.word); |
446 | free (p); | 449 | free (p); |
447 | } | 450 | } |
448 | 451 | ||
449 | static void | 452 | static void |
450 | wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node) | 453 | wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node) |
451 | { | 454 | { |
452 | node->next = NULL; | 455 | node->next = NULL; |
453 | node->prev = wsp->ws_tail; | 456 | node->prev = wsp->ws_tail; |
454 | if (wsp->ws_tail) | 457 | if (wsp->ws_tail) |
455 | wsp->ws_tail->next = node; | 458 | wsp->ws_tail->next = node; |
456 | else | 459 | else |
@@ -1241,24 +1244,25 @@ expvar_recover (struct wordsplit *wsp, const char *str, | |||
1241 | return 0; | 1244 | return 0; |
1242 | } | 1245 | } |
1243 | 1246 | ||
1244 | static int | 1247 | static int |
1245 | expand_paramv (struct wordsplit *wsp, struct wordsplit_node **ptail, int flg, | 1248 | expand_paramv (struct wordsplit *wsp, struct wordsplit_node **ptail, int flg, |
1246 | int q) | 1249 | int q) |
1247 | { | 1250 | { |
1248 | struct wordsplit ws; | 1251 | struct wordsplit ws; |
1249 | int wsflags = WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE | 1252 | int wsflags = WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE |
1250 | | (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0) | 1253 | | (WSP_RETURN_DELIMS (wsp) ? WRDSF_RETURN_DELIMS : 0) |
1251 | | (q ? WRDSF_NOSPLIT : 0); | 1254 | | (q ? WRDSF_NOSPLIT : 0); |
1252 | size_t i; | 1255 | size_t i; |
1256 | struct wordsplit_node *tail = *ptail; | ||
1253 | 1257 | ||
1254 | for (i = 0; i < wsp->ws_paramc; i++) | 1258 | for (i = 0; i < wsp->ws_paramc; i++) |
1255 | { | 1259 | { |
1256 | struct wordsplit_node *np; | 1260 | struct wordsplit_node *np; |
1257 | int rc = _wsplt_subsplit (wsp, &ws, | 1261 | int rc = _wsplt_subsplit (wsp, &ws, |
1258 | wsp->ws_paramv[i], strlen (wsp->ws_paramv[i]), | 1262 | wsp->ws_paramv[i], strlen (wsp->ws_paramv[i]), |
1259 | wsflags, q); | 1263 | wsflags, q); |
1260 | if (rc) | 1264 | if (rc) |
1261 | { | 1265 | { |
1262 | _wsplt_seterr_sub (wsp, &ws); | 1266 | _wsplt_seterr_sub (wsp, &ws); |
1263 | wordsplit_free (&ws); | 1267 | wordsplit_free (&ws); |
1264 | return 1; | 1268 | return 1; |
@@ -1279,24 +1283,46 @@ expand_paramv (struct wordsplit *wsp, struct wordsplit_node **ptail, int flg, | |||
1279 | { | 1283 | { |
1280 | for (np = ws.ws_head; np; np = np->next) | 1284 | for (np = ws.ws_head; np; np = np->next) |
1281 | np->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; | 1285 | np->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; |
1282 | wsnode_insert (wsp, ws.ws_head, *ptail, 0); | 1286 | wsnode_insert (wsp, ws.ws_head, *ptail, 0); |
1283 | *ptail = ws.ws_tail; | 1287 | *ptail = ws.ws_tail; |
1284 | ws.ws_head = ws.ws_tail = NULL; | 1288 | ws.ws_head = ws.ws_tail = NULL; |
1285 | } | 1289 | } |
1286 | 1290 | ||
1287 | wsflags |= WRDSF_REUSE; | 1291 | wsflags |= WRDSF_REUSE; |
1288 | } | 1292 | } |
1289 | if (wsflags & WRDSF_REUSE) | 1293 | if (wsflags & WRDSF_REUSE) |
1290 | wordsplit_free (&ws); | 1294 | wordsplit_free (&ws); |
1295 | |||
1296 | if (flg & _WSNF_QUOTE) | ||
1297 | { | ||
1298 | tail = tail->next; | ||
1299 | /* Insert delimiters, mark nodes as joinable */ | ||
1300 | while (tail != *ptail) | ||
1301 | { | ||
1302 | struct wordsplit_node *next = tail->next; | ||
1303 | struct wordsplit_node *newnode; | ||
1304 | |||
1305 | tail->flags |= _WSNF_JOIN; | ||
1306 | |||
1307 | if (wsnode_new (wsp, &newnode)) | ||
1308 | return 1; | ||
1309 | newnode->flags = _WSNF_WORD | _WSNF_CONST | _WSNF_NOEXPAND | _WSNF_JOIN; | ||
1310 | newnode->v.word = wsp->ws_sep; | ||
1311 | |||
1312 | wsnode_insert (wsp, newnode, tail, 0); | ||
1313 | tail = next; | ||
1314 | } | ||
1315 | } | ||
1316 | |||