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