]> sourceware.org Git - glibc.git/blame - posix/wordexp.c
Update.
[glibc.git] / posix / wordexp.c
CommitLineData
8f2ece69
UD
1/* POSIX.2 wordexp implementation.
2 Copyright (C) 1997 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
af6f3906
UD
41/* Undefine the following line for the production version. */
42/* #define NDEBUG 1 */
8f2ece69 43#include <assert.h>
28f540f4 44
8f2ece69
UD
45/*
46 * This is a recursive-descent-style word expansion routine.
47 */
48
49/* Some forward declarations */
40a55d20
UD
50static int parse_dollars (char **word, size_t *word_length, size_t *max_length,
51 const char *words, size_t *offset, int flags,
dfd2257a
UD
52 wordexp_t *pwordexp)
53 internal_function;
40a55d20
UD
54static int parse_backtick (char **word, size_t *word_length,
55 size_t *max_length, const char *words,
dfd2257a
UD
56 size_t *offset, int flags, wordexp_t *pwordexp)
57 internal_function;
58static int eval_expr (char *expr, int *result) internal_function;
8f2ece69 59
55c14926 60/* The w_*() functions manipulate word lists. */
8f2ece69 61
40a55d20
UD
62#define W_CHUNK (100)
63
64static inline char *
65w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
66 /* (lengths exclude trailing zero) */
8f2ece69 67{
40a55d20 68 /* Add a character to the buffer, allocating room for it if needed.
28f540f4
RM
69 */
70
40a55d20 71 if (*actlen == *maxlen)
8f2ece69 72 {
40a55d20
UD
73 char *old_buffer = buffer;
74 assert (buffer == NULL || *maxlen != 0);
75 *maxlen += W_CHUNK;
76 buffer = realloc (buffer, 1 + *maxlen);
77
78 if (buffer == NULL)
79 free (old_buffer);
80 }
28f540f4 81
40a55d20
UD
82 if (buffer != NULL)
83 {
84 buffer[*actlen] = ch;
85 buffer[++(*actlen)] = '\0';
8f2ece69 86 }
40a55d20
UD
87
88 return buffer;
8f2ece69
UD
89}
90
40a55d20
UD
91static char *
92w_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str)
93 /* (lengths exclude trailing zero) */
8f2ece69 94{
40a55d20 95 /* Add a string to the buffer, allocating room for it if needed.
8f2ece69 96 */
40a55d20 97 size_t len;
8f2ece69 98
40a55d20
UD
99 assert (str != NULL); /* w_addstr only called from this file */
100 len = strlen (str);
8f2ece69 101
40a55d20 102 if (*actlen + len > *maxlen)
8f2ece69 103 {
40a55d20
UD
104 char *old_buffer = buffer;
105 assert (buffer == NULL || *maxlen != 0);
106 *maxlen += MAX (2 * len, W_CHUNK);
107 buffer = realloc (old_buffer, 1 + *maxlen);
108
109 if (buffer == NULL)
110 free (old_buffer);
8f2ece69 111 }
8f2ece69 112
40a55d20
UD
113 if (buffer != NULL)
114 {
115 memcpy (&buffer[*actlen], str, len);
116 *actlen += len;
117 buffer[*actlen] = '\0';
118 }
8f2ece69 119
40a55d20 120 return buffer;
8f2ece69
UD
121}
122
123static int
124w_addword (wordexp_t *pwordexp, char *word)
125{
126 /* Add a word to the wordlist */
127 size_t num_p;
128
129 num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
130 pwordexp->we_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p);
131 if (pwordexp->we_wordv != NULL)
132 {
133 pwordexp->we_wordv[pwordexp->we_wordc++] = word;
134 pwordexp->we_wordv[pwordexp->we_wordc] = NULL;
135 return 0;
136 }
137
138 return WRDE_NOSPACE;
139}
140
141/* The parse_*() functions should leave *offset being the offset in 'words'
142 * to the last character processed.
143 */
144
145static int
dfd2257a 146internal_function
40a55d20
UD
147parse_backslash (char **word, size_t *word_length, size_t *max_length,
148 const char *words, size_t *offset)
8f2ece69
UD
149{
150 /* We are poised _at_ a backslash, not in quotes */
151
152 switch (words[1 + *offset])
153 {
154 case 0:
155 /* Backslash is last character of input words */
156 return WRDE_SYNTAX;
157
158 case '\n':
40a55d20 159 (*offset)++;
8f2ece69
UD
160 break;
161
162 default:
40a55d20 163 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
8f2ece69
UD
164 if (*word == NULL)
165 return WRDE_NOSPACE;
166
40a55d20 167 (*offset)++;
8f2ece69
UD
168 break;
169 }
170
171 return 0;
172}
173
174static int
dfd2257a 175internal_function
40a55d20
UD
176parse_qtd_backslash (char **word, size_t *word_length, size_t *max_length,
177 const char *words, size_t *offset)
8f2ece69
UD
178{
179 /* We are poised _at_ a backslash, inside quotes */
180
181 switch (words[1 + *offset])
182 {
183 case 0:
184 /* Backslash is last character of input words */
185 return WRDE_SYNTAX;
186
187 case '\n':
188 ++(*offset);
189 break;
190
191 case '$':
192 case '`':
193 case '"':
194 case '\\':
40a55d20 195 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
8f2ece69
UD
196 if (*word == NULL)
197 return WRDE_NOSPACE;
198
40a55d20 199 ++(*offset);
8f2ece69
UD
200 break;
201
202 default:
40a55d20
UD
203 *word = w_addchar (*word, word_length, max_length, words[*offset]);
204 if (*word != NULL)
205 *word = w_addchar (*word, word_length, max_length, words[1 + *offset]);
206
8f2ece69
UD
207 if (*word == NULL)
208 return WRDE_NOSPACE;
209
40a55d20 210 ++(*offset);
8f2ece69
UD
211 break;
212 }
213
214 return 0;
215}
216
217static int
dfd2257a 218internal_function
40a55d20
UD
219parse_tilde (char **word, size_t *word_length, size_t *max_length,
220 const char *words, size_t *offset, size_t wordc)
8f2ece69
UD
221{
222 /* We are poised _at_ a tilde */
55c14926 223 size_t i;
8f2ece69
UD
224
225 if (*word_length != 0)
226 {
227 if (!((*word)[*word_length - 1] == '=' && wordc == 0))
228 {
229 if (!((*word)[*word_length - 1] == ':' &&
40a55d20 230 strchr (*word, '=') && wordc == 0))
8f2ece69 231 {
40a55d20 232 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69
UD
233 return *word ? 0 : WRDE_NOSPACE;
234 }
235 }
236 }
237
238 for (i = 1 + *offset; words[i]; i++)
239 {
240 if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
40a55d20 241 words[i] == '\t' || words[i] == 0 )
8f2ece69
UD
242 break;
243
244 if (words[i] == '\\')
245 {
40a55d20 246 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69
UD
247 return *word ? 0 : WRDE_NOSPACE;
248 }
249 }
250
251 if (i == 1 + *offset)
252 {
253 /* Tilde appears on its own */
254 uid_t uid;
255 struct passwd pwd, *tpwd;
256 int buflen = 1000;
257 char* buffer = __alloca (buflen);
258 int result;
259
260 uid = getuid ();
261
55c14926 262 while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
8f2ece69
UD
263 && errno == ERANGE)
264 {
265 buflen += 1000;
266 buffer = __alloca (buflen);
267 }
268
269 if (result == 0 && pwd.pw_dir != NULL)
270 {
40a55d20 271 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
8f2ece69
UD
272 if (*word == NULL)
273 return WRDE_NOSPACE;
274 }
275 else
276 {
40a55d20 277 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69
UD
278 if (*word == NULL)
279 return WRDE_NOSPACE;
280 }
281 }
282 else
283 {
284 /* Look up user name in database to get home directory */
40a55d20 285 char *user = __strndup (&words[1 + *offset], i - *offset);
8f2ece69
UD
286 struct passwd pwd, *tpwd;
287 int buflen = 1000;
288 char* buffer = __alloca (buflen);
289 int result;
290
55c14926 291 while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
8f2ece69
UD
292 && errno == ERANGE)
293 {
294 buflen += 1000;
295 buffer = __alloca (buflen);
296 }
297
298 if (result == 0 && pwd.pw_dir)
40a55d20 299 *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
8f2ece69
UD
300 else
301 {
302 /* (invalid login name) */
40a55d20 303 *word = w_addchar (*word, word_length, max_length, '~');
8f2ece69 304 if (*word != NULL)
40a55d20 305 *word = w_addstr (*word, word_length, max_length, user);
8f2ece69
UD
306 }
307
308 *offset = i - 1;
309 }
310 return *word ? 0 : WRDE_NOSPACE;
311}
312
313static int
dfd2257a 314internal_function
40a55d20
UD
315parse_glob (char **word, size_t *word_length, size_t *max_length,
316 const char *words, size_t *offset, int flags,
317 wordexp_t *pwordexp, char *ifs)
8f2ece69
UD
318{
319 /* We are poised just after a '*' or a '{'. */
320 int error;
321 glob_t globbuf;
322 int match;
40a55d20 323 char *matching_word;
8f2ece69
UD
324
325 for (; words[*offset]; (*offset)++)
326 switch (words[*offset])
327 {
328 case ' ':
329 case '\t':
330 break;
331
332 case '$':
40a55d20
UD
333 error = parse_dollars (word, word_length, max_length, words, offset,
334 flags, pwordexp);
8f2ece69
UD
335 if (error)
336 return error;
337
338 continue;
339
340 default:
341 if (ifs == NULL || strchr (ifs, words[*offset]) == NULL)
342 {
40a55d20 343 *word = w_addchar (*word, word_length, max_length, words[*offset]);
8f2ece69
UD
344 if (*word == NULL)
345 return WRDE_NOSPACE;
346
347 continue;
348 }
349
350 break;
351 }
352
353 error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
354
355 if (error != 0)
356 {
357 /* We can only run into memory problems. */
358 assert (error == GLOB_NOSPACE);
359
360 return WRDE_NOSPACE;
361 }
362
363 if (ifs && !*ifs)
364 {
365 /* No field splitting allowed */
366 *word_length = strlen (globbuf.gl_pathv[0]);
367 *word = realloc (*word, 1 + *word_length);
368 if (*word == NULL)
369 goto no_space;
370
371 strcpy (*word, globbuf.gl_pathv[0]);
372
40a55d20 373 for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
8f2ece69 374 {
40a55d20 375 *word = w_addchar (*word, word_length, max_length, ' ');
8f2ece69 376 if (*word != NULL)
40a55d20
UD
377 *word = w_addstr (*word, word_length, max_length,
378 globbuf.gl_pathv[match]);
8f2ece69
UD
379 }
380
381 /* Re-parse white space on return */
382 globfree (&globbuf);
383 --(*offset);
384 return *word ? 0 : WRDE_NOSPACE;
385 }
386
387 /* here ifs != "" */
388 free (*word);
389 *word = NULL;
390 *word_length = 0;
391
392 matching_word = malloc (1 + strlen (globbuf.gl_pathv[0]));
393 if (matching_word == NULL)
394 goto no_space;
395
396 strcpy (matching_word, globbuf.gl_pathv[0]);
397 if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
398 goto no_space;
399
400 for (match = 1; match < globbuf.gl_pathc; ++match)
401 {
40a55d20 402 matching_word = __strdup (globbuf.gl_pathv[match]);
8f2ece69
UD
403 if (matching_word == NULL)
404 goto no_space;
405
8f2ece69
UD
406 if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
407 goto no_space;
408 }
409
410 globfree (&globbuf);
411
412 /* Re-parse white space on return */
413 --(*offset);
414 return 0;
415
416no_space:
417 globfree (&globbuf);
418 return WRDE_NOSPACE;
419}
420
421static int
40a55d20
UD
422parse_squote (char **word, size_t *word_length, size_t *max_length,
423 const char *words, size_t *offset)
8f2ece69
UD
424{
425 /* We are poised just after a single quote */
426 for (; words[*offset]; ++(*offset))
427 {
428 if (words[*offset] != '\'')
429 {
40a55d20 430 *word = w_addchar (*word, word_length, max_length, words[*offset]);
8f2ece69
UD
431 if (*word == NULL)
432 return WRDE_NOSPACE;
433 }
434 else return 0;
435 }
436
437 /* Unterminated string */
438 return WRDE_SYNTAX;
439}
440
441/* Functions to evaluate an arithmetic expression */
442static int
dfd2257a 443internal_function
8f2ece69 444eval_expr_val (char **expr, int *result)
28f540f4 445{
8f2ece69
UD
446 int sgn = +1;
447 char *digit;
448
449 /* Skip white space */
450 for (digit = *expr; digit && *digit && isspace (*digit); ++digit);
451
452 switch (*digit)
453 {
454 case '(':
455
456 /* Scan for closing paren */
457 for (++digit; **expr && **expr != ')'; ++(*expr));
458
459 /* Is there one? */
460 if (!**expr)
461 return WRDE_SYNTAX;
462
463 *(*expr)++ = 0;
464
40a55d20 465 if (eval_expr (digit, result))
8f2ece69
UD
466 return WRDE_SYNTAX;
467
468 return 0;
469
470 case '+': /* Positive value */
471 ++digit;
472 break;
473
474 case '-': /* Negative value */
475 ++digit;
476 sgn = -1;
477 break;
478
479 default:
480 if (!isdigit (*digit))
481 return WRDE_SYNTAX;
482 }
483
484 *result = 0;
40a55d20 485 for (; *digit && isdigit (*digit); ++digit)
8f2ece69
UD
486 *result = (*result * 10) + (*digit - '0');
487
488 *expr = digit;
489 *result *= sgn;
490 return 0;
491}
492
493static int
dfd2257a 494internal_function
8f2ece69
UD
495eval_expr_multdiv (char **expr, int *result)
496{
497 int arg;
498
499 /* Read a Value */
500 if (eval_expr_val (expr, result))
501 return WRDE_SYNTAX;
502
503 while (**expr)
504 {
505 /* Skip white space */
506 for (; *expr && **expr && isspace (**expr); ++(*expr));
507
508 if (**expr == '*')
509 {
510 (*expr)++;
511 if ((eval_expr_val (expr, &arg)) != 0)
512 return WRDE_SYNTAX;
513
514 *result *= arg;
515 }
516 else if (**expr == '/')
517 {
518 (*expr)++;
519 if ((eval_expr_val (expr, &arg)) != 0)
520 return WRDE_SYNTAX;
521
522 *result /= arg;
523 }
524 else break;
525 }
526
527 return 0;
528}
529
530static int
dfd2257a 531internal_function
8f2ece69
UD
532eval_expr (char *expr, int *result)
533{
534 int arg;
535
536 /* Read a Multdiv */
537 if ((eval_expr_multdiv (&expr, result)) != 0)
538 return WRDE_SYNTAX;
539
540 while (*expr)
541 {
542 /* Skip white space */
543 for (; expr && *expr && isspace (*expr); ++expr);
544
545 if (*expr == '+')
546 {
547 expr++;
548 if ((eval_expr_multdiv (&expr, &arg)) != 0)
549 return WRDE_SYNTAX;
550
551 *result += arg;
552 }
553 else if (*expr == '-')
554 {
555 expr++;
556 if ((eval_expr_multdiv (&expr, &arg)) != 0)
557 return WRDE_SYNTAX;
558
559 *result -= arg;
560 }
561 else break;
562 }
563
564 return 0;
565}
566
567static int
dfd2257a 568internal_function
40a55d20
UD
569parse_arith (char **word, size_t *word_length, size_t *max_length,
570 const char *words, size_t *offset, int flags, int bracket)
8f2ece69
UD
571{
572 /* We are poised just after "$((" or "$[" */
28f540f4 573 int error;
8f2ece69
UD
574 int paren_depth = 1;
575 size_t expr_length = 0;
40a55d20
UD
576 size_t expr_maxlen = 0;
577 char *expr = NULL;
8f2ece69
UD
578
579 for (; words[*offset]; ++(*offset))
580 {
581 switch (words[*offset])
582 {
583 case '$':
40a55d20 584 error = parse_dollars (&expr, &expr_length, &expr_maxlen,
8f2ece69
UD
585 words, offset, flags, NULL);
586 /* The NULL here is to tell parse_dollars not to
587 * split the fields.
588 */
589 if (error)
590 {
591 free (expr);
592 return error;
593 }
594 break;
595
596 case '`':
597 (*offset)++;
40a55d20 598 error = parse_backtick (&expr, &expr_length, &expr_maxlen,
8f2ece69
UD
599 words, offset, flags, NULL);
600 /* The NULL here is to tell parse_backtick not to
601 * split the fields.
602 */
603 if (error)
604 {
605 free (expr);
606 return error;
607 }
608 break;
609
610 case '\\':
40a55d20
UD
611 error = parse_qtd_backslash (&expr, &expr_length, &expr_maxlen,
612 words, offset);
8f2ece69
UD
613 if (error)
614 {
615 free (expr);
616 return error;
617 }
618 /* I think that a backslash within an
619 * arithmetic expansion is bound to
620 * cause an error sooner or later anyway though.
621 */
622 break;
623
624 case ')':
625 if (--paren_depth == 0)
626 {
627 char *result;
628 int numresult = 0;
629
630 if (bracket || words[1 + *offset] != ')')
631 return WRDE_SYNTAX;
632
633 ++(*offset);
634
635 /* Go - evaluate. */
636 if (*expr &&
637 eval_expr (expr, &numresult) != 0)
638 return WRDE_SYNTAX;
639
640 result = __alloca (100);
641 __snprintf (result, 100, "%d", numresult);
40a55d20 642 *word = w_addstr (*word, word_length, max_length, result);
8f2ece69
UD
643 free (expr);
644 return *word ? 0 : WRDE_NOSPACE;
645 }
40a55d20 646 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
8f2ece69
UD
647 if (expr == NULL)
648 return WRDE_NOSPACE;
649
650 break;
651
652 case ']':
653 if (bracket && paren_depth == 1)
654 {
655 char *result;
656 int numresult = 0;
657
658 /* Go - evaluate. */
659 if (*expr && eval_expr (expr, &numresult) != 0)
660 return WRDE_SYNTAX;
661
662 result = __alloca (100);
663 __snprintf (result, 100, "%d", numresult);
40a55d20 664 *word = w_addstr (*word, word_length, max_length, result);
8f2ece69
UD
665 free (expr);
666 return *word ? 0 : WRDE_NOSPACE;
667 }
668
669 free (expr);
670 return WRDE_SYNTAX;
671
672 case '\n':
673 case ';':
674 case '{':
675 case '}':
676 free (expr);
677 return WRDE_BADCHAR;
678
679 case '(':
680 ++paren_depth;
681 default:
40a55d20 682 expr = w_addchar (expr, &expr_length, &expr_maxlen, words[*offset]);
8f2ece69
UD
683 if (expr == NULL)
684 return WRDE_NOSPACE;
685 }
686 }
687
688 /* Premature end */
689 free (expr);
690 return WRDE_SYNTAX;
691}
692
693/* Function to execute a command and retrieve the results */
694/* pwordexp contains NULL if field-splitting is forbidden */
695static int
dfd2257a 696internal_function
40a55d20
UD
697exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
698 int flags, wordexp_t *pwordexp)
8f2ece69 699{
40a55d20 700 int fildes[2];
8f2ece69
UD
701 int bufsize = 128;
702 int buflen;
703 int state = 0;
704 int i;
55c14926 705 char *buffer;
28f540f4 706 pid_t pid;
8f2ece69
UD
707 /* 'state' is:
708 * 0 until first non-(whitespace-ifs)
709 * 1 after a non-ifs
710 * 2 after non-(whitespace-ifs)
711 */
28f540f4 712
8f2ece69
UD
713 /* Don't fork() unless necessary */
714 if (!comm || !*comm)
715 return 0;
28f540f4 716
8f2ece69
UD
717 if (pipe (fildes))
718 /* Bad */
719 return WRDE_NOSPACE;
28f540f4 720
8f2ece69
UD
721 if ((pid = fork ()) < 0)
722 {
723 /* Bad */
724 return WRDE_NOSPACE;
725 }
28f540f4
RM
726
727 if (pid == 0)
728 {
8f2ece69
UD
729 /* Child */
730 /* Redirect input and output */
731 dup2 (fildes[1], 1);
28f540f4 732
8f2ece69
UD
733 /* Close stderr if we have to */
734 if ((flags & WRDE_SHOWERR) == 0)
735 close (2);
28f540f4 736
8f2ece69 737 execl (_PATH_BSHELL, _PATH_BSHELL, "-c", comm, NULL);
40a55d20
UD
738
739 /* Bad. What now? */
8f2ece69
UD
740 exit (1);
741 }
28f540f4 742
8f2ece69
UD
743 /* Parent */
744
745 close (fildes[1]);
746 buffer = __alloca (bufsize);
28f540f4 747
8f2ece69
UD
748 if (!pwordexp)
749 { /* Quoted - no field splitting */
750
751 while (1)
752 {
753 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
754 {
755 if (waitpid (pid, NULL, WNOHANG) == 0)
756 continue;
757 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
758 break;
759 }
760
761 for (i = 0; i < buflen; ++i)
762 {
40a55d20 763 *word = w_addchar (*word, word_length, max_length, buffer[i]);
8f2ece69
UD
764 if (*word == NULL)
765 {
766 close (fildes[0]);
767 return WRDE_NOSPACE;
768 }
769 }
770 }
771
772 close (fildes[0]);
773 return 0;
28f540f4
RM
774 }
775
8f2ece69
UD
776 /* Not quoted - split fields.
777 * NB. This isn't done properly yet.
778 */
779 while (1)
780 {
781 if ((buflen = read (fildes[0], buffer, bufsize)) < 1)
782 {
783 if (waitpid (pid, NULL, WNOHANG) == 0)
784 continue;
785 if ((read (fildes[0], buffer, bufsize)) < 1)
786 break;
787 }
28f540f4 788
8f2ece69
UD
789 for (i = 0; i < buflen; ++i)
790 {
791 /* What if these aren't field separators? FIX */
40a55d20 792 if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n')
8f2ece69
UD
793 {
794 if (state != 0)
795 state = 2;
796 continue;
797 }
28f540f4 798
8f2ece69
UD
799 if (state == 2)
800 {
801 /* End of word */
802 if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
803 {
804 close (fildes[0]);
805 return WRDE_NOSPACE;
806 }
28f540f4 807
8f2ece69
UD
808 *word = NULL;
809 *word_length = 0;
810 }
28f540f4 811
8f2ece69 812 state = 1;
40a55d20 813 *word = w_addchar (*word, word_length, max_length, buffer[i]);
8f2ece69
UD
814 if (*word == NULL)
815 {
816 close (fildes[0]);
817 return WRDE_NOSPACE;
818 }
819 }
820 }
28f540f4 821
8f2ece69
UD
822 close (fildes[0]);
823 return 0;
824}
825
826static int
40a55d20
UD
827parse_comm (char **word, size_t *word_length, size_t *max_length,
828 const char *words, size_t *offset, int flags, wordexp_t *pwordexp)
8f2ece69
UD
829{
830 /* We are poised just after "$(" */
831 int paren_depth = 1;
832 int error;
833 size_t comm_length = 0;
40a55d20
UD
834 size_t comm_maxlen = 0;
835 char *comm = NULL;
8f2ece69
UD
836
837 for (; words[*offset]; ++(*offset))
28f540f4 838 {
8f2ece69 839 switch (words[*offset])
28f540f4 840 {
8f2ece69
UD
841 case ')':
842 if (--paren_depth == 0)
843 {
844 /* Go -- give script to the shell */
40a55d20
UD
845 error = exec_comm (comm, word, word_length, max_length, flags,
846 pwordexp);
8f2ece69
UD
847 free (comm);
848 return error;
849 }
850
851 /* This is just part of the script */
40a55d20 852 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
8f2ece69
UD
853 if (comm == NULL)
854 return WRDE_NOSPACE;
855
856 break;
857
858 case '(':
859 paren_depth++;
860 default:
40a55d20 861 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
8f2ece69
UD
862 if (comm == NULL)
863 return WRDE_NOSPACE;
864
865 break;
28f540f4
RM
866 }
867 }
28f540f4 868
8f2ece69
UD
869 /* Premature end */
870 free (comm);
871 return WRDE_SYNTAX;
872}
28f540f4 873
8f2ece69 874static int
dfd2257a 875internal_function
40a55d20
UD
876parse_param (char **word, size_t *word_length, size_t *max_length,
877 const char *words, size_t *offset, int flags, wordexp_t *pwordexp)
8f2ece69
UD
878{
879 /* We are poised just after "$" */
af6f3906
UD
880 enum remove_pattern_enum
881 {
882 RP_NONE = 0,
883 RP_SHORT_LEFT,
884 RP_LONG_LEFT,
885 RP_SHORT_RIGHT,
886 RP_LONG_RIGHT
887 };
8f2ece69
UD
888 size_t start = *offset;
889 size_t env_length = 0;
40a55d20 890 size_t env_maxlen = 0;
8f2ece69 891 size_t pat_length = 0;
40a55d20
UD
892 size_t pat_maxlen = 0;
893 char *env = NULL;
894 char *pattern = NULL;
8f2ece69 895 char *value;
af6f3906
UD
896 char action = '\0';
897 enum remove_pattern_enum remove = RP_NONE;
8f2ece69
UD
898 int colon_seen = 0;
899 int depth = 0;
900 int error;
901
8f2ece69
UD
902 for (; words[*offset]; ++(*offset))
903 {
904 switch (words[*offset])
905 {
906 case '{':
af6f3906
UD
907 ++depth;
908
909 if (action != '\0' || remove != RP_NONE)
8f2ece69 910 {
40a55d20
UD
911 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
912 words[*offset]);
8f2ece69
UD
913 if (pattern == NULL)
914 goto no_space;
915
916 break;
917 }
918
919 if (*offset == start)
920 break;
af6f3906 921
8f2ece69
UD
922 /* Otherwise evaluate */
923 /* (and re-parse this character) */
924 --(*offset);
925 goto envsubst;
926
927 case '}':
928 if (words[start] != '{')
8f2ece69 929 --(*offset);
8f2ece69 930
af6f3906 931 if (action != '\0' || remove != RP_NONE)
8f2ece69
UD
932 {
933 if (--depth)
934 {
40a55d20
UD
935 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
936 words[*offset]);
8f2ece69
UD
937 if (pattern == NULL)
938 goto no_space;
939
940 break;
941 }
942 }
943
944 /* Evaluate */
945 goto envsubst;
946
947 case '#':
af6f3906
UD
948 /* At the start? (ie. 'string length') */
949 if (*offset == start + 1)
950 /* FIXME: This isn't written yet! */
951 break;
8f2ece69 952
af6f3906
UD
953 if (words[start] != '{')
954 {
955 /* Evaluate */
956 /* (and re-parse this character) */
957 --(*offset);
958 goto envsubst;
959 }
8f2ece69 960
af6f3906 961 /* Separating variable name from prefix pattern? */
8f2ece69 962
af6f3906
UD
963 if (remove == RP_NONE)
964 {
965 remove = RP_SHORT_LEFT;
966 break;
967 }
968 else if (remove == RP_SHORT_LEFT)
969 {
970 remove = RP_LONG_LEFT;
8f2ece69
UD
971 break;
972 }
8f2ece69 973
af6f3906
UD
974 /* Must be part of prefix/suffix pattern. */
975 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
976 words[*offset]);
977 if (pattern == NULL)
978 goto no_space;
979
980 break;
981
982 case '%':
8f2ece69 983 if (!*env)
af6f3906
UD
984 goto syntax;
985
986 /* Separating variable name from suffix pattern? */
987 if (remove == RP_NONE)
8f2ece69 988 {
af6f3906
UD
989 remove = RP_SHORT_RIGHT;
990 break;
991 }
992 else if (remove == RP_SHORT_RIGHT)
993 {
994 remove = RP_LONG_RIGHT;
995 break;
8f2ece69
UD
996 }
997
af6f3906
UD
998 /* Must be part of prefix/suffix pattern. */
999 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1000 words[*offset]);
1001 if (pattern == NULL)
1002 goto no_space;
1003
1004 break;
1005
1006 case ':':
1007 if (!*env)
1008 goto syntax;
1009
1010 if (action != '\0' || remove != RP_NONE)
8f2ece69 1011 {
40a55d20
UD
1012 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1013 words[*offset]);
8f2ece69
UD
1014 if (pattern == NULL)
1015 goto no_space;
1016
1017 break;
1018 }
1019
1020 if ((words[1 + *offset] == '-') || (words[1 + *offset] == '=') ||
1021 (words[1 + *offset] == '?') || (words[1 + *offset] == '+'))
1022 {
1023 colon_seen = 1;
1024 break;
1025 }
1026
af6f3906 1027 goto syntax;
8f2ece69
UD
1028
1029 case '-':
1030 case '=':
1031 case '?':
1032 case '+':
1033 if (!*env)
af6f3906 1034 goto syntax;
8f2ece69 1035
af6f3906 1036 if (action != '\0' || remove != RP_NONE)
8f2ece69 1037 {
40a55d20
UD
1038 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1039 words[*offset]);
8f2ece69 1040 if (pattern == NULL)
af6f3906 1041 goto no_space;
8f2ece69
UD
1042
1043 break;
1044 }
1045
1046 action = words[*offset];
1047 break;
1048
1049 case '\\':
af6f3906 1050 if (action != '\0' || remove != RP_NONE)
8f2ece69 1051 {
af6f3906 1052 /* Um. Is this right? */
40a55d20
UD
1053 error = parse_qtd_backslash (word, word_length, max_length,
1054 words, offset);
8f2ece69
UD
1055 if (error == 0)
1056 break;
1057 }
1058 else
1059 {
1060 error = WRDE_SYNTAX;
1061 }
1062
af6f3906
UD
1063 if (env)
1064 free (env);
1065
1066 if (pattern != NULL)
1067 free (pattern);
1068
8f2ece69
UD
1069 return error;
1070
1071 default:
af6f3906 1072 if (action != '\0' || remove != RP_NONE)
8f2ece69 1073 {
40a55d20
UD
1074 pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
1075 words[*offset]);
8f2ece69
UD
1076 if (pattern == NULL)
1077 goto no_space;
1078
1079 break;
1080 }
1081
1082 if ((words[start] == '{') || isalpha (words[*offset]))
1083 {
40a55d20 1084 env = w_addchar (env, &env_length, &env_maxlen, words[*offset]);
8f2ece69
UD
1085 if (env == NULL)
1086 goto no_space;
1087
1088 break;
1089 }
1090
1091 --(*offset);
1092 goto envsubst;
1093 }
1094 }
1095
1096 /* End of input string */
1097 --(*offset);
1098
1099envsubst:
1100 if (words[start] == '{' && words[*offset] != '}')
af6f3906 1101 goto syntax;
8f2ece69
UD
1102
1103 if (!env || !*env)
1104 {
1105 *offset = start - 1;
40a55d20 1106 *word = w_addchar (*word, word_length, max_length, '$');
8f2ece69
UD
1107 free (env);
1108 free (pattern);
1109 return *word ? 0 : WRDE_NOSPACE;
1110 }
1111
1112 value = getenv (env);
1113
af6f3906 1114 if (action != '\0' || remove != RP_NONE)
8f2ece69
UD
1115 {
1116 switch (action)
1117 {
1118 case 0:
af6f3906
UD
1119 {
1120 char *p;
1121 char c;
1122 char *end;
1123
1124 if (!pattern || !*pattern)
1125 break;
1126
1127 end = value + strlen (value);
1128
1129 if (value == NULL)
1130 break;
1131
1132 switch (remove)
1133 {
1134 case RP_SHORT_LEFT:
1135 for (p = value; p <= end; p++)
1136 {
1137 c = *p;
1138 *p = '\0';
1139 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1140 {
1141 *p = c;
1142 value = p;
1143 break;
1144 }
1145 *p = c;
1146 }
1147
1148 break;
1149
1150 case RP_LONG_LEFT:
1151 for (p = end; p >= value; p--)
1152 {
1153 c = *p;
1154 *p = '\0';
1155 if (fnmatch (pattern, value, 0) != FNM_NOMATCH)
1156 {
1157 *p = c;
1158 value = p;
1159 break;
1160 }
1161 *p = c;
1162 }
1163
1164 break;
1165
1166 case RP_SHORT_RIGHT:
1167 for (p = end; p >= value; p--)
1168 {
1169 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1170 {
1171 *p = '\0';
1172 break;
1173 }
1174 }
1175
1176 break;
1177
1178 case RP_LONG_RIGHT:
1179 for (p = value; p <= end; p++)
1180 {
1181 if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
1182 {
1183 *p = '\0';
1184 break;
1185 }
1186 }
1187
1188 break;
1189
1190 default:
1191 assert (! "Unexpected `remove' value\n");
1192 }
1193
1194 break;
1195 }
8f2ece69
UD
1196
1197 case '?':
1198 if (value && *value)
1199 break;
1200
1201 if (!colon_seen && value)
1202 {
1203 /* Substitute NULL */
1204 free (env);
1205 free (pattern);
1206 return 0;
1207 }
1208
1209 /* Error - exit */
1210 fprintf (stderr, "%s: ", env);
1211
1212 if (*pattern)
1213 {
1214 /* Expand 'pattern' and write it to stderr */
1215 wordexp_t we;
1216
1217 error = wordexp (pattern, &we, flags);
1218
1219 if (error == 0)
1220 {
1221 int i;
1222
1223 for (i = 0; i < we.we_wordc; ++i)
1224 {
1225 fprintf (stderr, "%s%s", i ? " " : "", we.we_wordv[i]);
1226 }
1227
1228 fprintf (stderr, "\n");
1229 error = WRDE_BADVAL;
1230 }
1231
1232 wordfree (&we);
1233 free (env);
1234 free (pattern);
1235 return error;
1236 }
1237
1238 fprintf (stderr, "parameter null or not set\n");
1239 free (env);
1240 free (pattern);
1241 return WRDE_BADVAL;
1242
1243 default:
1244 printf ("warning: parameter substitution does not yet support \"%s%c\"\n", colon_seen?":":"", action);
1245 }
1246 }
1247
1248 free (env);
1249 free (pattern);
1250
40a55d20 1251 if (value == NULL)
8f2ece69
UD
1252 {
1253 /* Variable not defined */
1254 if (flags & WRDE_UNDEF)
1255 return WRDE_SYNTAX;
1256
1257 return 0;
1258 }
1259
40a55d20 1260 if (pwordexp == NULL)
8f2ece69 1261 /* Quoted - no field split */
40a55d20 1262 *word = w_addstr (*word, word_length, max_length, value);
28f540f4 1263 else
8f2ece69 1264 /* Should field-split here - FIX */
40a55d20 1265 *word = w_addstr (*word, word_length, max_length, value);
28f540f4 1266
8f2ece69
UD
1267 return *word ? 0 : WRDE_NOSPACE;
1268
1269no_space:
1270 if (env)
1271 free (env);
1272
1273 if (pattern)
1274 free (pattern);
28f540f4 1275
8f2ece69 1276 return WRDE_NOSPACE;
af6f3906
UD
1277
1278syntax:
1279 if (env)
1280 free (env);
1281
1282 if (pattern)
1283 free (pattern);
1284
1285 return WRDE_SYNTAX;
8f2ece69
UD
1286}
1287
1288static int
dfd2257a 1289internal_function
40a55d20
UD
1290parse_dollars (char **word, size_t *word_length, size_t *max_length,
1291 const char *words, size_t *offset, int flags,
1292 wordexp_t *pwordexp)
8f2ece69
UD
1293{
1294 /* We are poised _at_ "$" */
1295 switch (words[1 + *offset])
28f540f4 1296 {
8f2ece69
UD
1297 case '"':
1298 case '\'':
1299 case 0:
40a55d20 1300 *word = w_addchar (*word, word_length, max_length, '$');
8f2ece69
UD
1301 return *word ? 0 : WRDE_NOSPACE;
1302
1303 case '(':
1304 if (words[2 + *offset] == '(')
1305 {
1306 (*offset) += 3;
1307 /* Call parse_arith -- 0 is for "no brackets" */
40a55d20
UD
1308 return parse_arith (word, word_length, max_length, words, offset,
1309 flags, 0);
8f2ece69
UD
1310 }
1311
1312 if (flags & WRDE_NOCMD)
1313 return WRDE_CMDSUB;
1314
1315 (*offset) += 2;
40a55d20
UD
1316 return parse_comm (word, word_length, max_length, words, offset, flags,
1317 pwordexp);
8f2ece69
UD
1318
1319 case '[':
1320 (*offset) += 2;
1321 /* Call parse_arith -- 1 is for "brackets" */
40a55d20
UD
1322 return parse_arith (word, word_length, max_length, words, offset, flags,
1323 1);
8f2ece69
UD
1324
1325 case '{':
1326 default:
1327 ++(*offset); /* parse_param needs to know if "{" is there */
40a55d20
UD
1328 return parse_param (word, word_length, max_length, words, offset, flags,
1329 pwordexp);
28f540f4 1330 }
8f2ece69 1331}
28f540f4 1332
8f2ece69 1333static int
40a55d20
UD
1334parse_backtick (char **word, size_t *word_length, size_t *max_length,
1335 const char *words, size_t *offset, int flags,
1336 wordexp_t *pwordexp)
8f2ece69
UD
1337{
1338 /* We are poised just after "`" */
1339 int error;
1340 size_t comm_length = 0;
40a55d20
UD
1341 size_t comm_maxlen = 0;
1342 char *comm = NULL;
8f2ece69
UD
1343 int squoting = 0;
1344
1345 for (; words[*offset]; ++(*offset))
28f540f4 1346 {
8f2ece69
UD
1347 switch (words[*offset])
1348 {
1349 case '`':
1350 /* Go -- give the script to the shell */
40a55d20
UD
1351 error = exec_comm (comm, word, word_length, max_length, flags,
1352 pwordexp);
8f2ece69
UD
1353 free (comm);
1354 return error;
1355
1356 case '\\':
1357 if (squoting)
1358 {
40a55d20
UD
1359 error = parse_qtd_backslash (&comm, &comm_length, &comm_maxlen,
1360 words, offset);
8f2ece69
UD
1361
1362 if (error)
1363 {
1364 free (comm);
1365 return error;
1366 }
1367
1368 break;
1369 }
1370
1371 ++(*offset);
40a55d20
UD
1372 error = parse_backslash (&comm, &comm_length, &comm_maxlen, words,
1373 offset);
8f2ece69
UD
1374
1375 if (error)
1376 {
1377 free (comm);
1378 return error;
1379 }
1380
1381 break;
1382
1383 case '\'':
1384 squoting = 1 - squoting;
1385 default:
40a55d20 1386 comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
8f2ece69
UD
1387 if (comm == NULL)
1388 return WRDE_NOSPACE;
1389 }
28f540f4
RM
1390 }
1391
8f2ece69
UD
1392 /* Premature end */
1393 free (comm);
1394 return WRDE_SYNTAX;
1395}
28f540f4 1396
8f2ece69 1397static int
dfd2257a 1398internal_function
40a55d20
UD
1399parse_dquote (char **word, size_t *word_length, size_t *max_length,
1400 const char *words, size_t *offset, int flags)
8f2ece69
UD
1401{
1402 /* We are poised just after a double-quote */
1403 int error;
1404
1405 for (; words[*offset]; ++(*offset))
1406 {
1407 switch (words[*offset])
1408 {
1409 case '"':
1410 return 0;
1411
1412 case '$':
40a55d20
UD
1413 error = parse_dollars (word, word_length, max_length, words, offset,
1414 flags, NULL);
8f2ece69
UD
1415 /* The NULL here is to tell parse_dollars not to
1416 * split the fields.
1417 */
1418 if (error)
1419 return error;
28f540f4 1420
8f2ece69
UD
1421 break;
1422
1423 case '`':
1424 if (flags & WRDE_NOCMD)
40a55d20 1425 return WRDE_CMDSUB;
8f2ece69
UD
1426
1427 ++(*offset);
40a55d20
UD
1428 error = parse_backtick (word, word_length, max_length, words,
1429 offset, flags, NULL);
8f2ece69
UD
1430 /* The NULL here is to tell parse_backtick not to
1431 * split the fields.
1432 */
1433 if (error)
1434 return error;
1435
1436 break;
1437
1438 case '\\':
40a55d20
UD
1439 error = parse_qtd_backslash (word, word_length, max_length, words,
1440 offset);
8f2ece69
UD
1441
1442 if (error)
1443 return error;
1444
1445 break;
1446
1447 default:
40a55d20 1448 *word = w_addchar (*word, word_length, max_length, words[*offset]);
8f2ece69
UD
1449 if (*word == NULL)
1450 return WRDE_NOSPACE;
1451 }
1452 }
1453
1454 /* Unterminated string */
1455 return WRDE_SYNTAX;
28f540f4
RM
1456}
1457
8f2ece69
UD
1458/*
1459 * wordfree() is to be called after pwordexp is finished with.
1460 */
28f540f4
RM
1461
1462void
8f2ece69 1463wordfree (wordexp_t *pwordexp)
28f540f4 1464{
8f2ece69
UD
1465
1466 /* wordexp can set pwordexp to NULL */
1467 if (pwordexp && pwordexp->we_wordv)
1468 {
1469 char **wordv = pwordexp->we_wordv;
1470
1471 for (wordv += pwordexp->we_offs; *wordv; ++wordv)
1472 free (*wordv);
1473
1474 free (pwordexp->we_wordv);
1475 pwordexp->we_wordv = NULL;
1476 }
1477}
1478
1479/*
1480 * wordexp()
1481 */
1482
1483int
1484wordexp (const char *words, wordexp_t *pwordexp, int flags)
1485{
1486 size_t wordv_offset;
1487 size_t words_offset;
1488 size_t word_length = 0;
40a55d20 1489 size_t max_length = 0;
8f2ece69 1490 char *word = NULL;
40a55d20 1491 int error;
8f2ece69
UD
1492 char *ifs;
1493 char ifs_white[4];
1494 char **old_wordv = pwordexp->we_wordv;
1495 size_t old_wordc = pwordexp->we_wordc;
1496
1497 if (flags & WRDE_REUSE)
1498 /* Minimal implementation of WRDE_REUSE for now */
1499 wordfree (pwordexp);
1500
1501 if (flags & WRDE_DOOFFS)
1502 {
1503 pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
1504 if (pwordexp->we_wordv == NULL)
1505 return WRDE_NOSPACE;
1506 }
1507 else
1508 {
1509 pwordexp->we_wordv = calloc (1, sizeof (char *));
1510 if (pwordexp->we_wordv == NULL)
1511 return WRDE_NOSPACE;
1512
1513 pwordexp->we_offs = 0;
1514 }
1515
1516 if ((flags & WRDE_APPEND) == 0)
1517 pwordexp->we_wordc = 0;
1518
1519 wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
1520
1521 /* Find out what the field separators are.
1522 * There are two types: whitespace and non-whitespace.
1523 */
1524 ifs = getenv ("IFS");
1525
1526 if (!ifs)
1527 ifs = strcpy (ifs_white, " \t\n");
1528 else
1529 {
1530 char *ifsch = ifs;
1531 char *whch = ifs_white;
1532
1533 while (*ifsch != '\0')
1534 if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
1535 {
55c14926 1536 /* White space IFS. See first whether it is already in our
8f2ece69
UD
1537 collection. */
1538 char *runp = ifs_white;
1539
40a55d20 1540 while (runp < whch && *runp != '\0' && *runp != *ifsch)
8f2ece69
UD
1541 ++runp;
1542
1543 if (runp == whch)
1544 *whch++ = *ifsch;
1545 }
1546 *whch = '\0';
1547 }
1548
1549 for (words_offset = 0 ; words[words_offset] ; ++words_offset)
1550 switch (words[words_offset])
1551 {
1552 case '\n':
1553 case '|':
1554 case '&':
1555 case ';':
1556 case '<':
1557 case '>':
1558 case '(':
1559 case ')':
1560 case '}':
1561 /* Fail */
1562 wordfree (pwordexp);
1563 pwordexp->we_wordc = 0;
1564 pwordexp->we_wordv = old_wordv;
1565 return WRDE_BADCHAR;
1566
1567 case '\\':
40a55d20
UD
1568 error = parse_backslash (&word, &word_length, &max_length, words,
1569 &words_offset);
8f2ece69
UD
1570
1571 if (error)
1572 goto do_error;
1573
1574 break;
1575
1576 case '$':
40a55d20
UD
1577 error = parse_dollars (&word, &word_length, &max_length, words,
1578 &words_offset, flags, pwordexp);
8f2ece69
UD
1579
1580 if (error)
1581 goto do_error;
1582
1583 break;
1584
1585 case '`':
1586 if (flags & WRDE_NOCMD)
1587 return WRDE_CMDSUB;
1588
1589 ++words_offset;
40a55d20
UD
1590 error = parse_backtick (&word, &word_length, &max_length, words,
1591 &words_offset, flags, pwordexp);
8f2ece69
UD
1592
1593 if (error)
1594 goto do_error;
1595
1596 break;
1597
1598 case '"':
1599 ++words_offset;
40a55d20
UD
1600 error = parse_dquote (&word, &word_length, &max_length, words,
1601 &words_offset, flags);
8f2ece69
UD
1602
1603 if (error)
1604 goto do_error;
1605
1606 break;
1607
1608 case '\'':
1609 ++words_offset;
40a55d20
UD
1610 error = parse_squote (&word, &word_length, &max_length, words,
1611 &words_offset);
8f2ece69
UD
1612
1613 if (error)
1614 goto do_error;
1615
1616 break;
1617
1618 case '~':
40a55d20
UD
1619 error = parse_tilde (&word, &word_length, &max_length, words,
1620 &words_offset, pwordexp->we_wordc);
8f2ece69
UD
1621
1622 if (error)
1623 goto do_error;
1624
1625 break;
1626
1627 case '*':
1628 case '{':
40a55d20
UD
1629 error = parse_glob (&word, &word_length, &max_length, words,
1630 &words_offset, flags, pwordexp, ifs);
8f2ece69
UD
1631
1632 if (error)
1633 goto do_error;
1634
1635 break;
1636
1637 default:
1638 /* Is it a field separator? */
1639 if (strchr (ifs, words[words_offset]) == NULL)
1640 {
1641 /* "Ordinary" character -- add it to word */
1642
40a55d20
UD
1643 word = w_addchar (word, &word_length, &max_length,
1644 words[words_offset]);
8f2ece69
UD
1645 if (word == NULL)
1646 {
1647 error = WRDE_NOSPACE;
1648 goto do_error;
1649 }
1650
1651 break;
1652 }
1653
1654 /* Field separator */
1655 if (strchr (ifs_white, words[words_offset]))
1656 {
1657 /* It's a whitespace IFS char. Ignore it at the beginning
1658 of a line and ignore multiple instances. */
1659 if (!word || !*word)
1660 break;
1661
1662 if (w_addword (pwordexp, word) == WRDE_NOSPACE)
1663 {
1664 error = WRDE_NOSPACE;
1665 goto do_error;
1666 }
1667
1668 word = NULL;
1669 word_length = 0;
1670 break;
1671 }
1672
1673 /* It's a non-whitespace IFS char */
40a55d20
UD
1674
1675 /* Multiple non-whitespace IFS chars are treated as one;
1676 * IS THIS CORRECT?
1677 */
1678 if (word != NULL)
8f2ece69 1679 {
40a55d20 1680 if (w_addword (pwordexp, word) == WRDE_NOSPACE)
8f2ece69
UD
1681 {
1682 error = WRDE_NOSPACE;
1683 goto do_error;
1684 }
1685 }
1686
8f2ece69
UD
1687 word = NULL;
1688 word_length = 0;
40a55d20 1689 max_length = 0;
8f2ece69
UD
1690 }
1691
1692 /* End of string */
1693
1694 /* There was a field separator at the end */
40a55d20 1695 if (word == NULL)
8f2ece69
UD
1696 return 0;
1697
1698 /* There was no field separator at the end */
1699 return w_addword (pwordexp, word);
1700
1701do_error:
1702 /* Error:
1703 free memory used, set we_wordc and wd_wordv back to what they were.
1704 */
1705 if (word != NULL)
1706 free (word);
1707
1708 wordfree (pwordexp);
1709 pwordexp->we_wordv = old_wordv;
1710 pwordexp->we_wordc = old_wordc;
1711 return error;
28f540f4 1712}
This page took 0.242887 seconds and 5 git commands to generate.