]> git.ipfire.org Git - thirdparty/glibc.git/blame - posix/wordexp.c
Add pthread_attr_init to GLIBC_2.1.
[thirdparty/glibc.git] / posix / wordexp.c
CommitLineData
8f2ece69 1/* POSIX.2 wordexp implementation.
af69217f 2 Copyright (C) 1997, 1998 Free Software Foundation, Inc.
c84142e8 3 This file is part of the GNU C Library.
8f2ece69 4 Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>.
28f540f4 5
c84142e8
UD
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
28f540f4 10
c84142e8
UD
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
28f540f4 15
c84142e8
UD
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
28f540f4 20
28f540f4 21#include <wordexp.h>
28f540f4 22#include <signal.h>
8f2ece69
UD
23#include <stdlib.h>
24#include <pwd.h>
25#include <sys/types.h>
26#include <string.h>
27#include <glob.h>
28#include <ctype.h>
29#include <sys/time.h>
30#include <sys/types.h>
31#include <sys/wait.h>
32#include <unistd.h>
33#include <fcntl.h>
34#include <sys/stat.h>
35#include <paths.h>
36#include <errno.h>
40a55d20
UD
37#include <sys/param.h>
38#include <stdio.h>
af6f3906 39#include <fnmatch.h>
28f540f4 40
86187531
UD
41#include <stdio-common/_itoa.h>
42
af6f3906
UD
43/* Undefine the following line for the production version. */
44/* #define NDEBUG 1 */
8f2ece69 45#include <assert.h>
28f540f4 46
8f2ece69
UD
47/*
48 * This is a recursive-descent-style word expansion routine.
49 */
50
2bcf29ba
UD
51/* This variable is defined and initialized in the startup code. */
52extern char **__libc_argv;
53
8f2ece69 54/* Some forward declarations */
40a55d20
UD
55static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
56 const char *words, size_t *offset, int flags,
af69217f 57 wordexp_t *pwordexp, const char *ifs,
2bcf29ba 58 const char *ifs_white, int quoted)
dfd2257a 59 internal_function;
40a55d20
UD
60static int parse_backtick (char **word, size_t *word_length,
61 size_t *max_length, const char *words,
af69217f
UD
62 size_t *offset, int flags, wordexp_t *pwordexp,
63 const char *ifs, const char *ifs_white)
dfd2257a 64 internal_function;
3db52d94 65static int eval_expr (char *expr, long int *result) internal_function;
8f2ece69 66
55c14926 67/* The w_*() functions manipulate word lists. */
8f2ece69 68
40a55d20
UD
69#define W_CHUNK (100)
70
71static inline char *
72w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
73 /* (lengths exclude trailing zero) */
8f2ece69 74{
40a55d20 75 /* Add a character to the buffer, allocating room for it if needed.
28f540f4
RM
76 */
77
40a55d20 78 if (*actlen == *maxlen)
8f2ece69 79 {
40a55d20
UD
80 char *old_buffer = buffer;
81 assert (buffer == NULL || *maxlen != 0);
82 *maxlen += W_CHUNK;
83 buffer = realloc (buffer, 1 + *maxlen);
84
85 if (buffer == NULL)
86 free (old_buffer);
87 }
28f540f4 88
40a55d20
UD
89 if (buffer != NULL)
90 {
91 buffer[*actlen] = ch;
92 buffer[++(*actlen)] = '\0';
8f2ece69 93 }
40a55d20
UD
94
95 return buffer;
8f2ece69
UD
96}
97
40a55d20 98static char *
3db52d94
UD
99internal_function
100w_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str,
101 size_t len)
8f2ece69 102{
40a55d20 103 /* Add a string to the buffer, allocating room for it if needed.
8f2ece69 104 */
40a55d20 105 if (*actlen + len > *maxlen)
8f2ece69 106 {
40a55d20
UD
107 char *old_buffer = buffer;
108 assert (buffer == NULL || *maxlen != 0);
109 *maxlen += MAX (2 * len, W_CHUNK);
110 buffer = realloc (old_buffer, 1 + *maxlen);
111
112 if (buffer == NULL)
113 free (old_buffer);
8f2ece69 114 }
8f2ece69 115
40a55d20
UD
116 if (buffer != NULL)
117 {
86187531 118 *((char *) __mempcpy (&buffer[*actlen], str, len)) = '\0';
40a55d20 119 *actlen += len;
40a55d20 120 }
8f2ece69 121
40a55d20 122 return buffer;
8f2ece69
UD
123}
124
3db52d94
UD
125
126static char *
127internal_function
128w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
129 /* (lengths exclude trailing zero) */
130{
131 /* Add a string to the buffer, allocating room for it if needed.
132 */
133 size_t len;
134
135 assert (str != NULL); /* w_addstr only called from this file */
136 len = strlen (str);
137
138 return w_addmem (buffer, actlen, maxlen, str, len);
139}
140
8f2ece69 141static int
3db52d94 142internal_function
8f2ece69
UD
143w_addword (wordexp_t *pwordexp, char *word)
144{
145 /* Add a word to the wordlist */
146 size_t num_p;
147
148 num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
149 pwordexp->we_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
150 if (pwordexp->we_wordv != NULL)
151 {
152 pwordexp->we_wordv[pwordexp->we_wordc++] = word;
153 pwordexp->we_wordv[pwordexp->we_wordc] = NULL;
154 return 0;
155 }
156
157 return WRDE_NOSPACE;
158}
159
160/* The parse_*() functions should leave *offset being the offset in 'words'
161 * to the last character processed.
162 */
163
164static int
dfd2257a 165internal_function
40a55d20
UD
166parse_backslash (char **word, size_t *word_length, size_t *max_length,
167 const char *words, size_t *offset)
8f2ece69
UD
168{
169 /* We are poised _at_ a backslash, not in quotes */
170
171 switch (words[1 + *offset])
172 {
173 case 0:
174 /* Backslash is last character of input words */
175 return WRDE_SYNTAX;
176
177 case '\n':
86187531 178 ++(*offset);
8f2ece69
UD
179 break;
180
181 default:
40a55d20 182 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
8f2ece69
UD
183 if (*word == NULL)
184 return WRDE_NOSPACE;
185
86187531 186 ++(*offset);
8f2ece69
UD
187 break;
188 }
189
190 return 0;
191}
192
193static int
dfd2257a 194internal_function
40a55d20
UD
195parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
196 const char *words, size_t *offset)
8f2ece69
UD
197{
198 /* We are poised _at_ a backslash, inside quotes */
199
200 switch (words[1 + *offset])
201 {
202 case 0:
203 /* Backslash is last character of input words */
204 return WRDE_SYNTAX;
205
206 case '\n':
207 ++(*offset);
208 break;
209
210 case '$':
211 case '`':
212 case '"':
213 case '\\':
40a55d20 214 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
8f2ece69
UD
215 if (*word == NULL)
216 return WRDE_NOSPACE;
217
40a55d20 218 ++(*offset);
8f2ece69
UD
219 break;
220
221 default:
40a55d20
UD
222 *word = w_addchar (*word, word_length, max_length, words[*offset]);
223 if (*word != NULL)
224 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
225
8f2ece69
UD
226 if (*word == NULL)
227 return WRDE_NOSPACE;
228
40a55d20 229 ++(*offset);
8f2ece69
UD
230 break;
231 }
232
233 return 0;
234}
235
236static int
dfd2257a 237internal_function
40a55d20
UD
238parse_tilde (char **word, size_t *word_length, size_t *max_length,
239 const char *words, size_t *offset, size_t wordc)
8f2ece69
UD
240{
241 /* We are poised _at_ a tilde */
55c14926 242 size_t i;
8f2ece69
UD
243
244 if (*word_length != 0)
245 {
246 if (!((*word)[*word_length - 1] == '=' && wordc == 0))
247 {
3db52d94
UD
248 if (!((*word)[*word_length - 1] == ':'
249 && strchr (*word, '=') && wordc == 0))
8f2ece69 250 {
40a55d20 251 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69
UD
252 return *word ? 0 : WRDE_NOSPACE;
253 }
254 }
255 }
256
257 for (i = 1 + *offset; words[i]; i++)
258 {
259 if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
40a55d20 260 words[i] == '\t' || words[i] == 0 )
8f2ece69
UD
261 break;
262
263 if (words[i] == '\\')
264 {
40a55d20 265 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69
UD
266 return *word ? 0 : WRDE_NOSPACE;
267 }
268 }
269
270 if (i == 1 + *offset)
271 {
272 /* Tilde appears on its own */
273 uid_t uid;
274 struct passwd pwd, *tpwd;
275 int buflen = 1000;
276 char* buffer = __alloca (buflen);
277 int result;
278
279 uid = getuid ();
280
55c14926 281 while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
8f2ece69
UD
282 && errno == ERANGE)
283 {
284 buflen += 1000;
285 buffer = __alloca (buflen);
286 }
287
288 if (result == 0 && pwd.pw_dir != NULL)
289 {
40a55d20 290 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
8f2ece69
UD
291 if (*word == NULL)
292 return WRDE_NOSPACE;
293 }
294 else
295 {
40a55d20 296 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69
UD
297 if (*word == NULL)
298 return WRDE_NOSPACE;
299 }
300 }
301 else
302 {
303 /* Look up user name in database to get home directory */
40a55d20 304 char *user = __strndup (&words[1 + *offset], i - *offset);
8f2ece69
UD
305 struct passwd pwd, *tpwd;
306 int buflen = 1000;
307 char* buffer = __alloca (buflen);
308 int result;
309
55c14926 310 while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
8f2ece69
UD
311 && errno == ERANGE)
312 {
313 buflen += 1000;
314 buffer = __alloca (buflen);
315 }
316
317 if (result == 0 && pwd.pw_dir)
40a55d20 318 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
8f2ece69
UD
319 else
320 {
321 /* (invalid login name) */
40a55d20 322 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69 323 if (*word != NULL)
40a55d20 324 *word = w_addstr (*word, word_length, max_length, user);
8f2ece69
UD
325 }
326
327 *offset = i - 1;
328 }
329 return *word ? 0 : WRDE_NOSPACE;
330}
331
332static int
dfd2257a 333internal_function
40a55d20
UD
334parse_glob (char **word, size_t *word_length, size_t *max_length,
335 const char *words, size_t *offset, int flags,
af69217f 336 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
8f2ece69 337{
2bcf29ba 338 /* We are poised just after a '*', a '[' or a '?'. */
8f2ece69
UD
339 int error;
340 glob_t globbuf;
341 int match;
40a55d20 342 char *matching_word;
2bcf29ba 343 int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
8f2ece69
UD
344
345 for (; words[*offset]; (*offset)++)
2bcf29ba
UD
346 {
347 if ((ifs && strchr (ifs, words[*offset])) ||
348 (!ifs && strchr (" \t\n", words[*offset])))
349 /* Reached IFS */
8f2ece69
UD
350 break;
351
2bcf29ba
UD
352 /* Sort out quoting */
353 if (words[*offset] == '\'')
354 if (quoted == 0)
355 {
356 quoted = 1;
357 continue;
358 }
359 else if (quoted == 1)
360 {
361 quoted = 0;
362 continue;
363 }
364 else if (words[*offset] == '"')
365 if (quoted == 0)
8f2ece69 366 {
2bcf29ba
UD
367 quoted = 2;
368 continue;
369 }
370 else if (quoted == 2)
371 {
372 quoted = 0;
8f2ece69
UD
373 continue;
374 }
375
2bcf29ba
UD
376 /* Sort out other special characters */
377 if (quoted != 1 && words[*offset] == '$')
378 {
379 error = parse_dollars (word, word_length, max_length, words, offset,
380 flags, pwordexp, ifs, ifs_white, quoted == 2);
381 if (error)
382 return error;
383
384 continue;
385 }
386 else if (words[*offset] == '\\')
387 {
388 if (quoted)
389 error = parse_qtd_backslash (word, word_length, max_length, words,
390 offset);
391 else
392 error = parse_backslash (word, word_length, max_length, words,
393 offset);
394
395 if (error)
396 return error;
397
398 continue;
399 }
400
401 *word = w_addchar (*word, word_length, max_length, words[*offset]);
402 if (*word == NULL)
403 return WRDE_NOSPACE;
404 }
8f2ece69
UD
405
406 error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
407
408 if (error != 0)
409 {
410 /* We can only run into memory problems. */
411 assert (error == GLOB_NOSPACE);
412
413 return WRDE_NOSPACE;
414 }
415
416 if (ifs && !*ifs)
417 {
418 /* No field splitting allowed */
86187531
UD
419 size_t length = strlen (globbuf.gl_pathv[0]);
420 *word = realloc (*word, length + 1);
8f2ece69
UD
421 if (*word == NULL)
422 goto no_space;
423
86187531
UD
424 memcpy (*word, globbuf.gl_pathv[0], length + 1);
425 *word_length = length;
8f2ece69 426
40a55d20 427 for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
8f2ece69 428 {
40a55d20 429 *word = w_addchar (*word, word_length, max_length, ' ');
8f2ece69 430 if (*word != NULL)
40a55d20
UD
431 *word = w_addstr (*word, word_length, max_length,
432 globbuf.gl_pathv[match]);
8f2ece69
UD
433 }
434
435 /* Re-parse white space on return */
436 globfree (&globbuf);
437 --(*offset);
438 return *word ? 0 : WRDE_NOSPACE;
439 }
440
441 /* here ifs != "" */
442 free (*word);
443 *word = NULL;
444 *word_length = 0;
445
86187531 446 matching_word = __strdup (globbuf.gl_pathv[0]);
8f2ece69
UD
447 if (matching_word == NULL)
448 goto no_space;
449
8f2ece69
UD
450 if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
451 goto no_space;
452
453 for (match = 1; match < globbuf.gl_pathc; ++match)
454 {
40a55d20 455 matching_word = __strdup (globbuf.gl_pathv[match]);
8f2ece69
UD
456 if (matching_word == NULL)
457 goto no_space;
458
8f2ece69
UD
459 if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
460 goto no_space;
461 }
462
463 globfree (&globbuf);
464
465 /* Re-parse white space on return */
466 --(*offset);
467 return 0;
468
469no_space:
470 globfree (&globbuf);
471 return WRDE_NOSPACE;
472}
473
474static int
3db52d94 475internal_function
40a55d20
UD
476parse_squote (char **word, size_t *word_length, size_t *max_length,
477 const char *words, size_t *offset)
8f2ece69
UD
478{
479 /* We are poised just after a single quote */
480 for (; words[*offset]; ++(*offset))
481 {
482 if (words[*offset] != '\'')
483 {
40a55d20 484 *word = w_addchar (*word, word_length, max_length, words[*offset]);
8f2ece69
UD
485 if (*word == NULL)
486 return WRDE_NOSPACE;
487 }
488 else return 0;
489 }
490
491 /* Unterminated string */
492 return WRDE_SYNTAX;
493}
494
495/* Functions to evaluate an arithmetic expression */
496static int
dfd2257a 497internal_function
3db52d94 498eval_expr_val (char **expr, long int *result)
28f540f4 499{
8f2ece69
UD
500 int sgn = +1;
501 char *digit;
502
503 /* Skip white space */
504 for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
505
506 switch (*digit)
507 {
508 case '(':
509
510 /* Scan for closing paren */
511 for (++digit; **expr && **expr != ')'; ++(*expr));
512
513 /* Is there one? */
514 if (!**expr)
515 return WRDE_SYNTAX;
516
517 *(*expr)++ = 0;
518
40a55d20 519 if (eval_expr (digit, result))
8f2ece69
UD
520 return WRDE_SYNTAX;
521
522 return 0;
523
524 case '+': /* Positive value */
525 ++digit;
526 break;
527
528 case '-': /* Negative value */
529 ++digit;
530 sgn = -1;
531 break;
532
533 default:
534 if (!isdigit (*digit))
535 return WRDE_SYNTAX;
536 }
537
538 *result = 0;
40a55d20 539 for (; *digit && isdigit (*digit); ++digit)
8f2ece69
UD
540 *result = (*result * 10) + (*digit - '0');
541
542 *expr = digit;
543 *result *= sgn;
544 return 0;
545}
546
547static int
dfd2257a 548internal_function
3db52d94 549eval_expr_multdiv (char **expr, long int *result)
8f2ece69 550{
3db52d94 551 long int arg;
8f2ece69
UD
552
553 /* Read a Value */
3db52d94 554 if (eval_expr_val (expr, result) != 0)
8f2ece69
UD
555 return WRDE_SYNTAX;
556
557 while (**expr)
558 {
559 /* Skip white space */
560 for (; *expr && **expr && isspace (**expr); ++(*expr));
561
562 if (**expr == '*')
563 {
3db52d94
UD
564 ++(*expr);
565 if (eval_expr_val (expr, &arg) != 0)
8f2ece69
UD
566 return WRDE_SYNTAX;
567
568 *result *= arg;
569 }
570 else if (**expr == '/')
571 {
3db52d94
UD
572 ++(*expr);
573 if (eval_expr_val (expr, &arg) != 0)
8f2ece69
UD
574 return WRDE_SYNTAX;
575
576 *result /= arg;
577 }
578 else break;
579 }
580
581 return 0;
582}
583
584static int
dfd2257a 585internal_function
3db52d94 586eval_expr (char *expr, long int *result)
8f2ece69 587{
3db52d94 588 long int arg;
8f2ece69
UD
589
590 /* Read a Multdiv */
3db52d94 591 if (eval_expr_multdiv (&expr, result) != 0)
8f2ece69
UD
592 return WRDE_SYNTAX;
593
594 while (*expr)
595 {
596 /* Skip white space */
597 for (; expr && *expr && isspace (*expr); ++expr);
598
599 if (*expr == '+')
600 {
3db52d94
UD
601 ++expr;
602 if (eval_expr_multdiv (&expr, &arg) != 0)
8f2ece69
UD
603 return WRDE_SYNTAX;
604
605 *result += arg;
606 }
607 else if (*expr == '-')
608 {
3db52d94
UD
609 ++expr;
610 if (eval_expr_multdiv (&expr, &arg) != 0)
8f2ece69
UD
611 return WRDE_SYNTAX;
612
613 *result -= arg;
614 }
615 else break;
616 }
617
618 return 0;
619}
620
621static int
dfd2257a 622internal_function
40a55d20
UD
623parse_arith (char **word, size_t *word_length, size_t *max_length,
624 const char *words, size_t *offset, int flags, int bracket)
8f2ece69
UD
625{
626 /* We are poised just after "$((" or "$[" */
28f540f4 627 int error;
8f2ece69
UD
628 int paren_depth = 1;
629 size_t expr_length = 0;
40a55d20
UD
630 size_t expr_maxlen = 0;
631 char *expr = NULL;
8f2ece69
UD
632
633 for (; words[*offset]; ++(*offset))
634 {
635 switch (words[*offset])
636 {
637 case '$':
40a55d20 638 error = parse_dollars (&expr, &expr_length, &expr_maxlen,
2bcf29ba
UD
639 words, offset, flags, NULL, NULL, NULL, 1);
640 /* The ``1'' here is to tell parse_dollars not to
8f2ece69
UD
641 * split the fields.
642 */
643 if (error)
644 {
645 free (expr);
646 return error;
647 }
648 break;
649
650 case '`':
651 (*offset)++;
40a55d20 652 error = parse_backtick (&expr, &expr_length, &expr_maxlen,
af69217f
UD
653 words, offset, flags, NULL, NULL, NULL);
654 /* The first NULL here is to tell parse_backtick not to
8f2ece69
UD
655 * split the fields.
656 */
657 if (error)
658 {
659 free (expr);
660 return error;
661 }
662 break;
663
664 case '\\':
40a55d20
UD
665 error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
666 words, offset);
8f2ece69
UD
667 if (error)
668 {
669 free (expr);
670 return error;
671 }
672 /* I think that a backslash within an
673 * arithmetic expansion is bound to
674 * cause an error sooner or later anyway though.
675 */
676 break;
677
678 case ')':
679 if (--paren_depth == 0)
680 {
86187531 681 char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
3db52d94
UD
682 long int numresult = 0;
683 long long int convertme;
8f2ece69
UD
684
685 if (bracket || words[1 + *offset] != ')')
686 return WRDE_SYNTAX;
687
688 ++(*offset);
689
690 /* Go - evaluate. */
3db52d94 691 if (*expr && eval_expr (expr, &numresult) != 0)
8f2ece69
UD
692 return WRDE_SYNTAX;
693
3db52d94
UD
694 if (numresult < 0)
695 {
696 convertme = -numresult;
697 *word = w_addchar (*word, word_length, max_length, '-');
698 if (!*word)
699 {
700 free (expr);
701 return WRDE_NOSPACE;
702 }
703 }
704 else
705 convertme = numresult;
706
86187531
UD
707 result[20] = '\0';
708 *word = w_addstr (*word, word_length, max_length,
3db52d94 709 _itoa (convertme, &result[20], 10, 0));
8f2ece69
UD
710 free (expr);
711 return *word ? 0 : WRDE_NOSPACE;
712 }
40a55d20 713 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
8f2ece69
UD
714 if (expr == NULL)
715 return WRDE_NOSPACE;
716
717 break;
718
719 case ']':
720 if (bracket && paren_depth == 1)
721 {
86187531 722 char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
3db52d94 723 long int numresult = 0;
8f2ece69
UD
724
725 /* Go - evaluate. */
726 if (*expr && eval_expr (expr, &numresult) != 0)
727 return WRDE_SYNTAX;
728
86187531
UD
729 result[20] = '\0';
730 *word = w_addstr (*word, word_length, max_length,
731 _itoa_word (numresult, &result[20], 10, 0));
8f2ece69
UD
732 free (expr);
733 return *word ? 0 : WRDE_NOSPACE;
734 }
735
736 free (expr);
737 return WRDE_SYNTAX;
738
739 case '\n':
740 case ';':
741 case '{':
742 case '}':
743 free (expr);
744 return WRDE_BADCHAR;
745
746 case '(':
747 ++paren_depth;
748 default:
40a55d20 749 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
8f2ece69
UD
750 if (expr == NULL)
751 return WRDE_NOSPACE;
752 }
753 }
754
755 /* Premature end */
756 free (expr);
757 return WRDE_SYNTAX;
758}
759
760/* Function to execute a command and retrieve the results */
761/* pwordexp contains NULL if field-splitting is forbidden */
762static int
dfd2257a 763internal_function
40a55d20 764exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
af69217f
UD
765 int flags, wordexp_t *pwordexp, const char *ifs,
766 const char *ifs_white)
8f2ece69 767{
40a55d20 768 int fildes[2];
8f2ece69
UD
769 int bufsize = 128;
770 int buflen;
8f2ece69 771 int i;
55c14926 772 char *buffer;
28f540f4 773 pid_t pid;
28f540f4 774
8f2ece69
UD
775 /* Don't fork() unless necessary */
776 if (!comm || !*comm)
777 return 0;
28f540f4 778
8f2ece69
UD
779 if (pipe (fildes))
780 /* Bad */
781 return WRDE_NOSPACE;
28f540f4 782
8f2ece69
UD
783 if ((pid = fork ()) < 0)
784 {
785 /* Bad */
786 return WRDE_NOSPACE;
787 }
28f540f4
RM
788
789 if (pid == 0)
790 {
8f2ece69 791 /* Child */
86187531
UD
792 const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
793
8f2ece69
UD
794 /* Redirect input and output */
795 dup2 (fildes[1], 1);
28f540f4 796
8f2ece69
UD
797 /* Close stderr if we have to */
798 if ((flags & WRDE_SHOWERR) == 0)
799 close (2);
28f540f4 800
86187531 801 __execve (_PATH_BSHELL, (char *const *) args, __environ);
40a55d20 802
86187531
UD
803 /* Bad. What now? */
804 abort ();
8f2ece69 805 }
28f540f4 806
8f2ece69
UD
807 /* Parent */
808
809 close (fildes[1]);
810 buffer = __alloca (bufsize);
28f540f4 811
8f2ece69
UD
812 if (!pwordexp)
813 { /* Quoted - no field splitting */
814
815 while (1)
816 {
817 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
818 {
86187531 819 if (__waitpid (pid, NULL, WNOHANG) == 0)
8f2ece69
UD
820 continue;
821 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
822 break;
823 }
824
3db52d94
UD
825 *word = w_addmem (*word, word_length, max_length, buffer, buflen);
826 if (*word == NULL)
8f2ece69 827 {
3db52d94
UD
828 close (fildes[0]);
829 return WRDE_NOSPACE;
8f2ece69
UD
830 }
831 }
832
833 close (fildes[0]);
8d9618b7
UD
834
835 /* bash chops off a terminating linefeed, which seems sensible */
836 if ((*word)[*word_length - 1] == '\n')
837 (*word)[--*word_length] = '\0';
838
8f2ece69 839 return 0;
28f540f4 840 }
af69217f
UD
841 else
842 /* Not quoted - split fields */
8f2ece69 843 {
af69217f
UD
844 int copying = 0;
845 /* 'copying' is:
846 * 0 when searching for first character in a field not IFS white space
847 * 1 when copying the text of a field
848 * 2 when searching for possible non-whitespace IFS
849 */
28f540f4 850
af69217f 851 while (1)
8f2ece69 852 {
af69217f 853 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
8f2ece69 854 {
af69217f
UD
855 if (__waitpid (pid, NULL, WNOHANG) == 0)
856 continue;
857 if ((read (fildes[0], buffer, bufsize)) < 1)
858 break;
8f2ece69 859 }
28f540f4 860
af69217f 861 for (i = 0; i < buflen; ++i)
8f2ece69 862 {
af69217f 863 if (strchr (ifs, buffer[i]) != NULL)
8f2ece69 864 {
af69217f
UD
865 /* Current character is IFS */
866 if (strchr (ifs_white, buffer[i]) == NULL)
867 {
868 /* Current character is IFS but not whitespace */
869 if (copying == 2)
870 {
871 /* current character
872 * |
873 * V
874 * eg: text<space><comma><space>moretext
875 *
876 * So, strip whitespace IFS (like at the start)
877 */
878 copying = 0;
879 continue;
880 }
881
882 copying = 0;
883 /* fall through and delimit field.. */
884 }
885 else
886 {
887 /* Current character is IFS white space */
28f540f4 888
af69217f
UD
889 /* If not copying a field, ignore it */
890 if (copying != 1)
891 continue;
28f540f4 892
af69217f
UD
893 /* End of field (search for non-IFS afterwards) */
894 copying = 2;
895 }
896
897 /* First IFS white space, or IFS non-whitespace.
898 * Delimit the field. */
899 if (!*word)
900 {
901 /* This field is null, so make it an empty string */
902 *word = w_addchar (*word, word_length, max_length, 0);
903 if (*word == NULL)
904 {
905 close (fildes[0]);
906 return WRDE_NOSPACE;
907 }
908 }
909
910 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
911 {
912 /* Should do __waitpid? */
913 close (fildes[0]);
914 return WRDE_NOSPACE;
915 }
916
917 *word = NULL;
918 *word_length = 0;
919 *max_length = 0;
920 /* fall back round the loop.. */
921 }
922 else
923 {
924 /* Not IFS character */
925 copying = 1;
926 *word = w_addchar (*word, word_length, max_length,
927 buffer[i]);
928 if (*word == NULL)
929 {
930 close (fildes[0]);
931 return WRDE_NOSPACE;
932 }
933 }
8f2ece69
UD
934 }
935 }
936 }
28f540f4 937
8f2ece69
UD
938 close (fildes[0]);
939 return 0;
940}
941
942static int
3db52d94 943internal_function
40a55d20 944parse_comm (char **word, size_t *word_length, size_t *max_length,
af69217f
UD
945 const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
946 const char *ifs, const char *ifs_white)
8f2ece69
UD
947{
948 /* We are poised just after "$(" */
949 int paren_depth = 1;
950 int error;
951 size_t comm_length = 0;
40a55d20
UD
952 size_t comm_maxlen = 0;
953 char *comm = NULL;
8f2ece69
UD
954
955 for (; words[*offset]; ++(*offset))
28f540f4 956 {
8f2ece69 957 switch (words[*offset])
28f540f4 958 {
8f2ece69
UD
959 case ')':
960 if (--paren_depth == 0)
961 {
962 /* Go -- give script to the shell */
40a55d20 963 error = exec_comm (comm, word, word_length, max_length, flags,
af69217f 964 pwordexp, ifs, ifs_white);
8f2ece69
UD
965 free (comm);
966 return error;
967 }
968
969 /* This is just part of the script */
40a55d20 970 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
8f2ece69
UD
971 if (comm == NULL)
972 return WRDE_NOSPACE;
973
974 break;
975
976 case '(':
86187531 977 ++paren_depth;
8f2ece69 978 default:
40a55d20 979 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
8f2ece69
UD
980 if (comm == NULL)
981 return WRDE_NOSPACE;
982
983 break;
28f540f4
RM
984 }
985 }
28f540f4 986
8f2ece69
UD
987 /* Premature end */
988 free (comm);
989 return WRDE_SYNTAX;
990}
28f540f4 991
8f2ece69 992static int
dfd2257a 993internal_function
40a55d20 994parse_param (char **word, size_t *word_length, size_t *max_length,
af69217f 995 const char *words, size_t *offset, int flags, wordexp_t *pwordexp,
2bcf29ba 996 const char *ifs, const char *ifs_white, int quoted)
8f2ece69
UD
997{
998 /* We are poised just after "$" */
af6f3906
UD
999 enum remove_pattern_enum
1000 {
1001 RP_NONE = 0,
1002 RP_SHORT_LEFT,
1003 RP_LONG_LEFT,
1004 RP_SHORT_RIGHT,
1005 RP_LONG_RIGHT
1006 };
8f2ece69
UD
1007 size_t start = *offset;
1008 size_t env_length = 0;
40a55d20 1009 size_t env_maxlen = 0;
8f2ece69 1010 size_t pat_length = 0;
40a55d20
UD
1011 size_t pat_maxlen = 0;
1012 char *env = NULL;
1013 char *pattern = NULL;
2bcf29ba 1014 char *value = NULL;
af6f3906
UD
1015 char action = '\0';
1016 enum remove_pattern_enum remove = RP_NONE;
8f2ece69
UD
1017 int colon_seen = 0;
1018 int depth = 0;
3db52d94 1019 int substitute_length = 0;
8f2ece69 1020 int error;
2bcf29ba 1021 int star = 0;
8f2ece69 1022
8f2ece69
UD
1023 for (; words[*offset]; ++(*offset))
1024 {
1025 switch (words[*offset])
1026 {
1027 case '{':
af6f3906
UD
1028 ++depth;
1029
1030 if (action != '\0' || remove != RP_NONE)
8f2ece69 1031 {
40a55d20
UD
1032 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1033 words[*offset]);
8f2ece69
UD
1034 if (pattern == NULL)
1035 goto no_space;
1036
1037 break;
1038 }
1039
1040 if (*offset == start)
1041 break;
af6f3906 1042
8f2ece69
UD
1043 /* Otherwise evaluate */
1044 /* (and re-parse this character) */
1045 --(*offset);
1046 goto envsubst;
1047
1048 case '}':
1049 if (words[start] != '{')
8f2ece69 1050 --(*offset);
8f2ece69 1051
af6f3906 1052 if (action != '\0' || remove != RP_NONE)
8f2ece69
UD
1053 {
1054 if (--depth)
1055 {
40a55d20
UD
1056 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1057 words[*offset]);
8f2ece69
UD
1058 if (pattern == NULL)
1059 goto no_space;
1060
1061 break;
1062 }
1063 }
1064
1065 /* Evaluate */
1066 goto envsubst;
1067
1068 case '#':
3db52d94 1069 /* '#' only has special meaning inside braces */
af6f3906
UD
1070 if (words[start] != '{')
1071 {
1072 /* Evaluate */
1073 /* (and re-parse this character) */
1074 --(*offset);
1075 goto envsubst;
1076 }
8f2ece69 1077
3db52d94
UD
1078 /* At the start? (i.e. 'string length') */
1079 if (*offset == start + 1)
1080 {
1081 substitute_length = 1;
1082 break;
1083 }
1084 else if (substitute_length)
1085 goto syntax;
8f2ece69 1086
3db52d94 1087 /* Separating variable name from prefix pattern? */
af6f3906
UD
1088 if (remove == RP_NONE)
1089 {
1090 remove = RP_SHORT_LEFT;
1091 break;
1092 }
1093 else if (remove == RP_SHORT_LEFT)
1094 {
1095 remove = RP_LONG_LEFT;
8f2ece69
UD
1096 break;
1097 }
8f2ece69 1098
af6f3906
UD
1099 /* Must be part of prefix/suffix pattern. */
1100 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1101 words[*offset]);
1102 if (pattern == NULL)
1103 goto no_space;
1104
1105 break;
1106
1107 case '%':
8d9618b7 1108 if (!env || !*env)
af6f3906
UD
1109 goto syntax;
1110
1111 /* Separating variable name from suffix pattern? */
1112 if (remove == RP_NONE)
8f2ece69 1113 {
af6f3906
UD
1114 remove = RP_SHORT_RIGHT;
1115 break;
1116 }
1117 else if (remove == RP_SHORT_RIGHT)
1118 {
1119 remove = RP_LONG_RIGHT;
1120 break;
8f2ece69
UD
1121 }
1122
af6f3906
UD
1123 /* Must be part of prefix/suffix pattern. */
1124 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1125 words[*offset]);
1126 if (pattern == NULL)
1127 goto no_space;
1128
1129 break;
1130
1131 case ':':
8d9618b7 1132 if (!env || !*env)
af6f3906
UD
1133 goto syntax;
1134
1135 if (action != '\0' || remove != RP_NONE)
8f2ece69 1136 {
40a55d20
UD
1137 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1138 words[*offset]);
8f2ece69
UD
1139 if (pattern == NULL)
1140 goto no_space;
1141
1142 break;
1143 }
1144
3db52d94
UD
1145 if ((words[1 + *offset] == '-') || (words[1 + *offset] == '=')
1146 || (words[1 + *offset] == '?') || (words[1 + *offset] == '+'))
8f2ece69
UD
1147 {
1148 colon_seen = 1;
1149 break;
1150 }
1151
af6f3906 1152 goto syntax;
8f2ece69
UD
1153
1154 case '-':
1155 case '=':
1156 case '?':
1157 case '+':
8d9618b7 1158 if (!env || !*env)
af6f3906 1159 goto syntax;
8f2ece69 1160
3db52d94
UD
1161 if (substitute_length)
1162 goto syntax;
1163
af6f3906 1164 if (action != '\0' || remove != RP_NONE)
8f2ece69 1165 {
40a55d20
UD
1166 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1167 words[*offset]);
8f2ece69 1168 if (pattern == NULL)
af6f3906 1169 goto no_space;
8f2ece69
UD
1170
1171 break;
1172 }
1173
1174 action = words[*offset];
1175 break;
1176
1177 case '\\':
af6f3906 1178 if (action != '\0' || remove != RP_NONE)
8f2ece69 1179 {
af6f3906 1180 /* Um. Is this right? */
40a55d20
UD
1181 error = parse_qtd_backslash (word, word_length, max_length,
1182 words, offset);
8f2ece69
UD
1183 if (error == 0)
1184 break;
1185 }
1186 else
1187 {
1188 error = WRDE_SYNTAX;
1189 }
1190
af6f3906
UD
1191 if (env)
1192 free (env);
1193
1194 if (pattern != NULL)
1195 free (pattern);
1196
8f2ece69
UD
1197 return error;
1198
1199 default:
af6f3906 1200 if (action != '\0' || remove != RP_NONE)
8f2ece69 1201 {
40a55d20
UD
1202 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1203 words[*offset]);
8f2ece69
UD
1204 if (pattern == NULL)
1205 goto no_space;
1206
1207 break;
1208 }
1209
2bcf29ba
UD
1210 star = strchr ("*@", words[*offset]) != NULL;
1211 if (isalnum (words[*offset]) || star)
8f2ece69 1212 {
40a55d20 1213 env = w_addchar (env, &env_length, &env_maxlen, words[*offset]);
8f2ece69
UD
1214 if (env == NULL)
1215 goto no_space;
1216
2bcf29ba
UD
1217 if (star)
1218 goto envsubst;
1219
8f2ece69
UD
1220 break;
1221 }
1222
1223 --(*offset);
1224 goto envsubst;
1225 }
1226 }
1227
2bcf29ba
UD
1228 /* End of input string -- remember to reparse the character that we stopped
1229 * at. */
8f2ece69
UD
1230 --(*offset);
1231
1232envsubst:
1233 if (words[start] == '{' && words[*offset] != '}')
af6f3906 1234 goto syntax;
8f2ece69
UD
1235
1236 if (!env || !*env)
1237 {
1238 *offset = start - 1;
40a55d20 1239 *word = w_addchar (*word, word_length, max_length, '$');
8f2ece69 1240 free (env);
8f2ece69
UD
1241 return *word ? 0 : WRDE_NOSPACE;
1242 }
1243
2bcf29ba
UD
1244 /* Is it `$*' or `$@' ? */
1245 if (strpbrk (env, "*@") != NULL)
1246 {
1247 size_t plist_len = 1;
1248 int p;
1249
1250 if (env[1] != '\0')
1251 {
1252 /* Bad substitution if there is more than one character */
1253 fprintf (stderr, "${%s}: bad substitution\n", env);
1254 return WRDE_SYNTAX;
1255 }
1256
1257 if (!quoted || *env == '*')
1258 {
1259 /* Build up value parameter by parameter (copy them) */
8d9618b7 1260 for (p = 1; __libc_argv[p]; ++p)
2bcf29ba 1261 {
8d9618b7
UD
1262 char *old_pointer = value;
1263 size_t argv_len = strlen (__libc_argv[p]);
1264 size_t old_plist_len = plist_len;
2bcf29ba
UD
1265
1266 if (value)
1267 value[plist_len - 1] = 0;
1268
8d9618b7 1269 plist_len += 1 + argv_len;
2bcf29ba
UD
1270
1271 /* First realloc will act as malloc because value is
1272 * initialised to NULL. */
1273 value = realloc (value, plist_len);
1274 if (value == NULL)
1275 {
1276 free (old_pointer);
1277 return WRDE_NOSPACE;
1278 }
1279
8d9618b7 1280 memcpy (&value[old_plist_len - 1], __libc_argv[p], argv_len + 1);
2bcf29ba
UD
1281 if (__libc_argv[p + 1])
1282 {
1283 value[plist_len - 1] = '\0';
1284 value[plist_len - 2] = ' ';
1285 }
1286 }
1287
1288 if (value)
1289 goto maybe_fieldsplit;
1290 }
1291
1292 /* Each parameter is a separate word ("$@") */
1293 if (__libc_argv[0] == NULL)
1294 {
1295 /* This can happen if the application is started without any
1296 parameter, not even a name. This is legal according to
1297 POSIX since the giving parameters is only a "should" rule. */
1298 *word = __strdup ("");
1299 *max_length = *word_length = 0;
1300 }
1301 else
1302 {
1303 for (p = 1; __libc_argv[p + 1]; p++)
1304 {
1305 char *copy = __strdup (__libc_argv[p]);
1306 if (copy == NULL)
1307 return WRDE_NOSPACE;
1308
1309 strcpy (copy, __libc_argv[p]);
1310 error = w_addword (pwordexp, copy);
1311 if (error)
1312 {
1313 free (copy);
1314 return error;
1315 }
1316 }
1317
1318 /* Last parameter becomes current word */
1319 if (__libc_argv[p])
1320 {
1321 *word = __strdup (__libc_argv[p]);
1322 *max_length = *word_length = strlen (*word);
1323 }
1324 }
1325
1326 return 0;
1327 }
1328
8f2ece69
UD
1329 value = getenv (env);
1330
af6f3906 1331 if (action != '\0' || remove != RP_NONE)
8f2ece69
UD
1332 {
1333 switch (action)
1334 {
1335 case 0:
af6f3906
UD
1336 {
1337 char *p;
1338 char c;
1339 char *end;
1340
1341 if (!pattern || !*pattern)
1342 break;
1343
1344 end = value + strlen (value);
1345
1346 if (value == NULL)
1347 break;
1348
1349 switch (remove)
1350 {
1351 case RP_SHORT_LEFT:
3db52d94 1352 for (p = value; p <= end; ++p)
af6f3906
UD
1353 {
1354 c = *p;
1355 *p = '\0';
1356 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1357 {
1358 *p = c;
1359 value = p;
1360 break;
1361 }
1362 *p = c;
1363 }
1364
1365 break;
1366
1367 case RP_LONG_LEFT:
3db52d94 1368 for (p = end; p >= value; --p)
af6f3906
UD
1369 {
1370 c = *p;
1371 *p = '\0';
1372 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1373 {
1374 *p = c;
1375 value = p;
1376 break;
1377 }
1378 *p = c;
1379 }
1380
1381 break;
1382
1383 case RP_SHORT_RIGHT:
3db52d94 1384 for (p = end; p >= value; --p)
af6f3906
UD
1385 {
1386 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1387 {
1388 *p = '\0';
1389 break;
1390 }
1391 }
1392
1393 break;
1394
1395 case RP_LONG_RIGHT:
3db52d94 1396 for (p = value; p <= end; ++p)
af6f3906
UD
1397 {
1398 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1399 {
1400 *p = '\0';
1401 break;
1402 }
1403 }
1404
1405 break;
1406
1407 default:
1408 assert (! "Unexpected `remove' value\n");
1409 }
1410
1411 break;
1412 }
8f2ece69
UD
1413
1414 case '?':
1415 if (value && *value)
3db52d94 1416 /* Substitute parameter */
8f2ece69
UD
1417 break;
1418
1419 if (!colon_seen && value)
1420 {
1421 /* Substitute NULL */
1422 free (env);
1423 free (pattern);
1424 return 0;
1425 }
1426
1427 /* Error - exit */
1428 fprintf (stderr, "%s: ", env);
1429
1430 if (*pattern)
1431 {
1432 /* Expand 'pattern' and write it to stderr */
1433 wordexp_t we;
1434
1435 error = wordexp (pattern, &we, flags);
1436
1437 if (error == 0)
1438 {
1439 int i;
1440
1441 for (i = 0; i < we.we_wordc; ++i)
1442 {
1443 fprintf (stderr, "%s%s", i ? " " : "", we.we_wordv[i]);
1444 }
1445
1446 fprintf (stderr, "\n");
1447 error = WRDE_BADVAL;
1448 }
1449
1450 wordfree (&we);
1451 free (env);
1452 free (pattern);
1453 return error;
1454 }
1455
1456 fprintf (stderr, "parameter null or not set\n");
1457 free (env);
1458 free (pattern);
1459 return WRDE_BADVAL;
1460
3db52d94
UD
1461 case '-':
1462 if (value && *value)
1463 /* Substitute parameter */
1464 break;
1465
1466 if (!colon_seen && value)
1467 {
1468 /* Substitute NULL */
1469 free (env);
1470 free (pattern);
1471 return 0;
1472 }
1473
1474 subst_word:
1475 {
1476 /* Substitute word */
1477 wordexp_t we;
3db52d94
UD
1478 int i;
1479
2bcf29ba 1480 if (quoted)
3db52d94
UD
1481 {
1482 /* No field-splitting is allowed, so imagine
1483 quotes around the word. */
2bcf29ba
UD
1484 char *qtd_pattern = malloc (3 + strlen (pattern));
1485 sprintf (qtd_pattern, "\"%s\"", pattern);
1486 free (pattern);
1487 pattern = qtd_pattern;
3db52d94
UD
1488 }
1489
2bcf29ba 1490 error = wordexp (pattern, &we, flags);
3db52d94
UD
1491 if (error)
1492 {
1493 free (env);
1494 free (pattern);
1495 return error;
1496 }
1497
1498 /* Fingers crossed that the quotes worked.. */
2bcf29ba 1499 assert (!quoted || we.we_wordc == 1);
3db52d94
UD
1500
1501 /* Substitute */
1502 for (i = 0; i < we.we_wordc; i++)
1503 if (w_addword (pwordexp, __strdup(we.we_wordv[i]))
1504 == WRDE_NOSPACE)
1505 break;
1506
8d9618b7
UD
1507 if (i < we.we_wordc)
1508 {
1509 /* Ran out of space */
1510 wordfree (&we);
1511 goto no_space;
1512 }
1513
3db52d94 1514 if (action == '=')
8d9618b7
UD
1515 {
1516 char *words;
1517 char *cp;
1518 size_t words_size = 0;
3db52d94 1519
8d9618b7
UD
1520 for (i = 0; i < we.we_wordc; i++)
1521 words_size += strlen (we.we_wordv[i]) + 1; /* for <space> */
1522 words_size++;
3db52d94 1523
8d9618b7
UD
1524 cp = words = __alloca (words_size);
1525 *words = 0;
1526 for (i = 0; i < we.we_wordc - 1; i++)
1527 {
1528 cp = __stpcpy (cp, we.we_wordv[i]);
1529 *cp++ = ' ';
1530 }
3db52d94 1531
8d9618b7
UD
1532 __stpcpy (cp, we.we_wordv[i]);
1533
1534 /* Also assign */
1535 setenv (env, words, 1);
1536 }
1537
1538 wordfree (&we);
3db52d94
UD
1539 return 0;
1540 }
1541
1542 case '+':
1543 if (value && *value)
1544 goto subst_word;
1545
1546 if (!colon_seen && value)
1547 goto subst_word;
1548
1549 /* Substitute NULL */
1550 free (env);
1551 free (pattern);
1552 return 0;
1553
1554 case '=':
1555 if (value && *value)
1556 /* Substitute parameter */
1557 break;
1558
1559 if (!colon_seen && value)
1560 {
1561 /* Substitute NULL */
1562 free (env);
1563 free (pattern);
1564 return 0;
1565 }
1566
1567 /* This checks for '=' so it knows to assign */
1568 goto subst_word;
1569
8f2ece69 1570 default:
3db52d94 1571 assert (! "Unrecognised action!");
8f2ece69
UD
1572 }
1573 }
1574
1575 free (env);
1576 free (pattern);
1577
40a55d20 1578 if (value == NULL)
8f2ece69
UD
1579 {
1580 /* Variable not defined */
1581 if (flags & WRDE_UNDEF)
8d9618b7 1582 return WRDE_BADVAL;
8f2ece69
UD
1583
1584 return 0;
1585 }
1586
3db52d94
UD
1587 if (substitute_length)
1588 {
1589 char param_length[21];
1590 param_length[20] = '\0';
1591 *word = w_addstr (*word, word_length, max_length,
1592 _itoa_word (strlen (value), &param_length[20], 10, 0));
1593 return *word ? 0 : WRDE_NOSPACE;
1594 }
1595
1596
2bcf29ba
UD
1597 maybe_fieldsplit:
1598 if (quoted || !pwordexp)
3db52d94
UD
1599 {
1600 /* Quoted - no field split */
1601 *word = w_addstr (*word, word_length, max_length, value);
1602 return *word ? 0 : WRDE_NOSPACE;
1603 }
28f540f4 1604 else
af69217f
UD
1605 {
1606 /* Need to field-split */
1607 char *field_begin = value;
1608 int seen_nonws_ifs = 0;
1609
1610 do
1611 {
1612 char *field_end = field_begin;
af69217f
UD
1613 char *next_field;
1614 char ch;
1615
2bcf29ba
UD
1616 /* If this isn't the first field, start a new word */
1617 if (field_begin != value)
1618 {
1619 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
1620 return WRDE_NOSPACE;
1621
1622 *word = NULL;
1623 *word_length = *max_length = 0;
1624 }
1625
af69217f
UD
1626 /* Skip IFS whitespace before the field */
1627 while (*field_begin && strchr (ifs_white, *field_begin) != NULL)
1628 field_begin++;
1629
1630 if (!seen_nonws_ifs && *field_begin == 0)
1631 /* Nothing but whitespace */
3db52d94 1632 break;
af69217f
UD
1633
1634 /* Search for the end of the field */
1635 field_end = field_begin;
1636 while (*field_end && strchr (ifs, *field_end) == NULL)
1637 field_end++;
1638
1639 /* Set up pointer to the character after end of field */
1640 ch = *field_end;
1641 next_field = ch ? field_end : NULL;
1642
1643 /* Skip whitespace IFS after the field */
1644 while (next_field && *next_field && strchr (ifs_white, *next_field))
1645 next_field++;
1646
1647 /* Skip at most one non-whitespace IFS character after the field */
1648 seen_nonws_ifs = 0;
1649 if (next_field && *next_field && strchr (ifs, *next_field))
1650 {
1651 seen_nonws_ifs = 1;
1652 next_field++;
1653 }
1654
2bcf29ba 1655 /* Null-terminate it */
af69217f 1656 *field_end = 0;
af69217f 1657
2bcf29ba
UD
1658 /* Tag a copy onto the current word */
1659 *word = w_addstr (*word, word_length, max_length,
1660 __strdup (field_begin));
1661 if (*word == NULL)
1662 return WRDE_NOSPACE;
af69217f
UD
1663
1664 field_begin = next_field;
1665 } while (seen_nonws_ifs || (field_begin && *field_begin));
af69217f 1666 }
28f540f4 1667
3db52d94 1668 return 0;
8f2ece69
UD
1669
1670no_space:
1671 if (env)
1672 free (env);
1673
1674 if (pattern)
1675 free (pattern);
28f540f4 1676
8f2ece69 1677 return WRDE_NOSPACE;
af6f3906
UD
1678
1679syntax:
1680 if (env)
1681 free (env);
1682
1683 if (pattern)
1684 free (pattern);
1685
1686 return WRDE_SYNTAX;
8f2ece69
UD
1687}
1688
1689static int
dfd2257a 1690internal_function
40a55d20
UD
1691parse_dollars (char **word, size_t *word_length, size_t *max_length,
1692 const char *words, size_t *offset, int flags,
2bcf29ba
UD
1693 wordexp_t *pwordexp, const char *ifs, const char *ifs_white,
1694 int quoted)
8f2ece69
UD
1695{
1696 /* We are poised _at_ "$" */
1697 switch (words[1 + *offset])
28f540f4 1698 {
8f2ece69
UD
1699 case '"':
1700 case '\'':
1701 case 0:
40a55d20 1702 *word = w_addchar (*word, word_length, max_length, '$');
8f2ece69
UD
1703 return *word ? 0 : WRDE_NOSPACE;
1704
1705 case '(':
1706 if (words[2 + *offset] == '(')
1707 {
2bcf29ba
UD
1708 /* Differentiate between $((1+3)) and $((echo);(ls)) */
1709 int i = 3 + *offset;
1710 while (words[i] && words[i] != ')')
1711 ++i;
1712 if (words[i] == ')' && words[i + 1] == ')')
1713 {
1714 (*offset) += 3;
1715 /* Call parse_arith -- 0 is for "no brackets" */
1716 return parse_arith (word, word_length, max_length, words, offset,
1717 flags, 0);
1718 }
8f2ece69
UD
1719 }
1720
1721 if (flags & WRDE_NOCMD)
1722 return WRDE_CMDSUB;
1723
1724 (*offset) += 2;
40a55d20 1725 return parse_comm (word, word_length, max_length, words, offset, flags,
8d9618b7 1726 quoted? NULL : pwordexp, ifs, ifs_white);
8f2ece69
UD
1727
1728 case '[':
1729 (*offset) += 2;
1730 /* Call parse_arith -- 1 is for "brackets" */
40a55d20
UD
1731 return parse_arith (word, word_length, max_length, words, offset, flags,
1732 1);
8f2ece69
UD
1733
1734 case '{':
1735 default:
1736 ++(*offset); /* parse_param needs to know if "{" is there */
40a55d20 1737 return parse_param (word, word_length, max_length, words, offset, flags,
2bcf29ba 1738 pwordexp, ifs, ifs_white, quoted);
28f540f4 1739 }
8f2ece69 1740}
28f540f4 1741
8f2ece69 1742static int
40a55d20
UD
1743parse_backtick (char **word, size_t *word_length, size_t *max_length,
1744 const char *words, size_t *offset, int flags,
af69217f 1745 wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
8f2ece69
UD
1746{
1747 /* We are poised just after "`" */
1748 int error;
1749 size_t comm_length = 0;
40a55d20
UD
1750 size_t comm_maxlen = 0;
1751 char *comm = NULL;
8f2ece69
UD
1752 int squoting = 0;
1753
1754 for (; words[*offset]; ++(*offset))
28f540f4 1755 {
8f2ece69
UD
1756 switch (words[*offset])
1757 {
1758 case '`':
1759 /* Go -- give the script to the shell */
40a55d20 1760 error = exec_comm (comm, word, word_length, max_length, flags,
af69217f 1761 pwordexp, ifs, ifs_white);
8f2ece69
UD
1762 free (comm);
1763 return error;
1764
1765 case '\\':
1766 if (squoting)
1767 {
40a55d20
UD
1768 error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
1769 words, offset);
8f2ece69
UD
1770
1771 if (error)
1772 {
1773 free (comm);
1774 return error;
1775 }
1776
1777 break;
1778 }
1779
1780 ++(*offset);
40a55d20
UD
1781 error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
1782 offset);
8f2ece69
UD
1783
1784 if (error)
1785 {
1786 free (comm);
1787 return error;
1788 }
1789
1790 break;
1791
1792 case '\'':
1793 squoting = 1 - squoting;
1794 default:
40a55d20 1795 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
8f2ece69
UD
1796 if (comm == NULL)
1797 return WRDE_NOSPACE;
1798 }
28f540f4
RM
1799 }
1800
8f2ece69
UD
1801 /* Premature end */
1802 free (comm);
1803 return WRDE_SYNTAX;
1804}
28f540f4 1805
8f2ece69 1806static int
dfd2257a 1807internal_function
40a55d20 1808parse_dquote (char **word, size_t *word_length, size_t *max_length,
2bcf29ba
UD
1809 const char *words, size_t *offset, int flags,
1810 wordexp_t *pwordexp, const char * ifs, const char * ifs_white)
8f2ece69
UD
1811{
1812 /* We are poised just after a double-quote */
1813 int error;
1814
1815 for (; words[*offset]; ++(*offset))
1816 {
1817 switch (words[*offset])
1818 {
1819 case '"':
1820 return 0;
1821
1822 case '$':
40a55d20 1823 error = parse_dollars (word, word_length, max_length, words, offset,
2bcf29ba
UD
1824 flags, pwordexp, ifs, ifs_white, 1);
1825 /* The ``1'' here is to tell parse_dollars not to
1826 * split the fields. It may need to, however ("$@").
8f2ece69
UD
1827 */
1828 if (error)
1829 return error;
28f540f4 1830
8f2ece69
UD
1831 break;
1832
1833 case '`':
1834 if (flags & WRDE_NOCMD)
40a55d20 1835 return WRDE_CMDSUB;
8f2ece69
UD
1836
1837 ++(*offset);
40a55d20 1838 error = parse_backtick (word, word_length, max_length, words,
af69217f
UD
1839 offset, flags, NULL, NULL, NULL);
1840 /* The first NULL here is to tell parse_backtick not to
8f2ece69
UD
1841 * split the fields.
1842 */
1843 if (error)
1844 return error;
1845
1846 break;
1847
1848 case '\\':
40a55d20
UD
1849 error = parse_qtd_backslash (word, word_length, max_length, words,
1850 offset);
8f2ece69
UD
1851
1852 if (error)
1853 return error;
1854
1855 break;
1856
1857 default:
40a55d20 1858 *word = w_addchar (*word, word_length, max_length, words[*offset]);
8f2ece69
UD
1859 if (*word == NULL)
1860 return WRDE_NOSPACE;
1861 }
1862 }
1863
1864 /* Unterminated string */
1865 return WRDE_SYNTAX;
28f540f4
RM
1866}
1867
8f2ece69
UD
1868/*
1869 * wordfree() is to be called after pwordexp is finished with.
1870 */
28f540f4
RM
1871
1872void
8f2ece69 1873wordfree (wordexp_t *pwordexp)
28f540f4 1874{
8f2ece69
UD
1875
1876 /* wordexp can set pwordexp to NULL */
1877 if (pwordexp && pwordexp->we_wordv)
1878 {
1879 char **wordv = pwordexp->we_wordv;
1880
1881 for (wordv += pwordexp->we_offs; *wordv; ++wordv)
1882 free (*wordv);
1883
1884 free (pwordexp->we_wordv);
1885 pwordexp->we_wordv = NULL;
1886 }
1887}
1888
1889/*
1890 * wordexp()
1891 */
1892
1893int
1894wordexp (const char *words, wordexp_t *pwordexp, int flags)
1895{
1896 size_t wordv_offset;
1897 size_t words_offset;
1898 size_t word_length = 0;
40a55d20 1899 size_t max_length = 0;
8f2ece69 1900 char *word = NULL;
40a55d20 1901 int error;
8f2ece69
UD
1902 char *ifs;
1903 char ifs_white[4];
1904 char **old_wordv = pwordexp->we_wordv;
2bcf29ba 1905 size_t old_wordc = (flags & WRDE_REUSE) ? pwordexp->we_wordc : 0;
8f2ece69
UD
1906
1907 if (flags & WRDE_REUSE)
1908 /* Minimal implementation of WRDE_REUSE for now */
1909 wordfree (pwordexp);
1910
1911 if (flags & WRDE_DOOFFS)
1912 {
1913 pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
1914 if (pwordexp->we_wordv == NULL)
1915 return WRDE_NOSPACE;
1916 }
1917 else
1918 {
1919 pwordexp->we_wordv = calloc (1, sizeof (char *));
1920 if (pwordexp->we_wordv == NULL)
1921 return WRDE_NOSPACE;
1922
1923 pwordexp->we_offs = 0;
1924 }
1925
1926 if ((flags & WRDE_APPEND) == 0)
1927 pwordexp->we_wordc = 0;
1928
1929 wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
1930
1931 /* Find out what the field separators are.
1932 * There are two types: whitespace and non-whitespace.
1933 */
1934 ifs = getenv ("IFS");
1935
1936 if (!ifs)
af69217f
UD
1937 /* NULL IFS means no field-splitting is to be performed */
1938 ifs = strcpy (ifs_white, "");
8f2ece69
UD
1939 else
1940 {
1941 char *ifsch = ifs;
1942 char *whch = ifs_white;
1943
af69217f
UD
1944 /* Start off with no whitespace IFS characters */
1945 ifs_white[0] = '\0';
1946
8f2ece69 1947 while (*ifsch != '\0')
af69217f
UD
1948 {
1949 if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
1950 {
1951 /* Whitespace IFS. See first whether it is already in our
1952 collection. */
1953 char *runp = ifs_white;
8f2ece69 1954
af69217f
UD
1955 while (runp < whch && *runp != '\0' && *runp != *ifsch)
1956 ++runp;
8f2ece69 1957
af69217f
UD
1958 if (runp == whch)
1959 *whch++ = *ifsch;
1960 }
1961
3db52d94 1962 ++ifsch;
af69217f 1963 }
8f2ece69
UD
1964 *whch = '\0';
1965 }
1966
1967 for (words_offset = 0 ; words[words_offset] ; ++words_offset)
1968 switch (words[words_offset])
1969 {
1970 case '\n':
1971 case '|':
1972 case '&':
1973 case ';':
1974 case '<':
1975 case '>':
1976 case '(':
1977 case ')':
8d9618b7 1978 case '{':
8f2ece69
UD
1979 case '}':
1980 /* Fail */
1981 wordfree (pwordexp);
1982 pwordexp->we_wordc = 0;
1983 pwordexp->we_wordv = old_wordv;
1984 return WRDE_BADCHAR;
1985
1986 case '\\':
40a55d20
UD
1987 error = parse_backslash (&word, &word_length, &max_length, words,
1988 &words_offset);
8f2ece69
UD
1989
1990 if (error)
1991 goto do_error;
1992
1993 break;
1994
1995 case '$':
40a55d20 1996 error = parse_dollars (&word, &word_length, &max_length, words,
2bcf29ba
UD
1997 &words_offset, flags, pwordexp, ifs, ifs_white,
1998 0);
8f2ece69
UD
1999
2000 if (error)
2001 goto do_error;
2002
2003 break;
2004
2005 case '`':
2006 if (flags & WRDE_NOCMD)
2007 return WRDE_CMDSUB;
2008
2009 ++words_offset;
40a55d20 2010 error = parse_backtick (&word, &word_length, &max_length, words,
af69217f
UD
2011 &words_offset, flags, pwordexp, ifs,
2012 ifs_white);
8f2ece69
UD
2013
2014 if (error)
2015 goto do_error;
2016
2017 break;
2018
2019 case '"':
2020 ++words_offset;
40a55d20 2021 error = parse_dquote (&word, &word_length, &max_length, words,
2bcf29ba 2022 &words_offset, flags, pwordexp, ifs, ifs_white);
8f2ece69
UD
2023
2024 if (error)
2025 goto do_error;
2026
2027 break;
2028
2029 case '\'':
2030 ++words_offset;
40a55d20
UD
2031 error = parse_squote (&word, &word_length, &max_length, words,
2032 &words_offset);
8f2ece69
UD
2033
2034 if (error)
2035 goto do_error;
2036
2037 break;
2038
2039 case '~':
40a55d20
UD
2040 error = parse_tilde (&word, &word_length, &max_length, words,
2041 &words_offset, pwordexp->we_wordc);
8f2ece69
UD
2042
2043 if (error)
2044 goto do_error;
2045
2046 break;
2047
2048 case '*':
2bcf29ba
UD
2049 case '[':
2050 case '?':
40a55d20 2051 error = parse_glob (&word, &word_length, &max_length, words,
af69217f 2052 &words_offset, flags, pwordexp, ifs, ifs_white);
8f2ece69
UD
2053
2054 if (error)
2055 goto do_error;
2056
2057 break;
2058
2059 default:
2060 /* Is it a field separator? */
2061 if (strchr (ifs, words[words_offset]) == NULL)
2062 {
2063 /* "Ordinary" character -- add it to word */
2064
40a55d20
UD
2065 word = w_addchar (word, &word_length, &max_length,
2066 words[words_offset]);
8f2ece69
UD
2067 if (word == NULL)
2068 {
2069 error = WRDE_NOSPACE;
2070 goto do_error;
2071 }
2072
2073 break;
2074 }
2075
2076 /* Field separator */
2077 if (strchr (ifs_white, words[words_offset]))
2078 {
2079 /* It's a whitespace IFS char. Ignore it at the beginning
2080 of a line and ignore multiple instances. */
2081 if (!word || !*word)
2082 break;
2083
2084 if (w_addword (pwordexp, word) == WRDE_NOSPACE)
2085 {
2086 error = WRDE_NOSPACE;
2087 goto do_error;
2088 }
2089
2090 word = NULL;
2091 word_length = 0;
af69217f 2092 max_length = 0;
8f2ece69
UD
2093 break;
2094 }
2095
2096 /* It's a non-whitespace IFS char */
40a55d20
UD
2097
2098 /* Multiple non-whitespace IFS chars are treated as one;
2099 * IS THIS CORRECT?
2100 */
2101 if (word != NULL)
8f2ece69 2102 {
40a55d20 2103 if (w_addword (pwordexp, word) == WRDE_NOSPACE)
8f2ece69
UD
2104 {
2105 error = WRDE_NOSPACE;
2106 goto do_error;
2107 }
2108 }
2109
8f2ece69
UD
2110 word = NULL;
2111 word_length = 0;
40a55d20 2112 max_length = 0;
8f2ece69
UD
2113 }
2114
2115 /* End of string */
2116
2117 /* There was a field separator at the end */
40a55d20 2118 if (word == NULL)
8f2ece69
UD
2119 return 0;
2120
2121 /* There was no field separator at the end */
2122 return w_addword (pwordexp, word);
2123
2124do_error:
2125 /* Error:
2bcf29ba
UD
2126 * free memory used (unless error is WRDE_NOSPACE), and
2127 * set we_wordc and wd_wordv back to what they were.
8f2ece69 2128 */
2bcf29ba
UD
2129
2130 if (error == WRDE_NOSPACE)
2131 return WRDE_NOSPACE;
2132
8f2ece69
UD
2133 if (word != NULL)
2134 free (word);
2135
2136 wordfree (pwordexp);
2137 pwordexp->we_wordv = old_wordv;
2138 pwordexp->we_wordc = old_wordc;
2139 return error;
28f540f4 2140}