aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wordsplit.h1
-rw-r--r--src/wordsplit.c30
-rw-r--r--tests/wordsplit.at34
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
357struct wordsplit_node 360struct 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
432wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode) 435wsnode_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
441static void 444static void
442wsnode_free (struct wordsplit_node *p) 445wsnode_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
449static void 452static void
450wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node) 453wsnode_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
1244static int 1247static int
1245expand_paramv (struct wordsplit *wsp, struct wordsplit_node **ptail, int flg, 1248expand_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