]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - bin/sh/expand.c
Reduce diff to 9-CURRENT.
[FreeBSD/stable/8.git] / bin / sh / expand.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *      Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)expand.c    8.5 (Berkeley) 5/15/95";
38 #endif
39 #endif /* not lint */
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <dirent.h>
48 #include <unistd.h>
49 #include <pwd.h>
50 #include <stdlib.h>
51 #include <limits.h>
52 #include <stdio.h>
53 #include <string.h>
54
55 /*
56  * Routines to expand arguments to commands.  We have to deal with
57  * backquotes, shell variables, and file metacharacters.
58  */
59
60 #include "shell.h"
61 #include "main.h"
62 #include "nodes.h"
63 #include "eval.h"
64 #include "expand.h"
65 #include "syntax.h"
66 #include "parser.h"
67 #include "jobs.h"
68 #include "options.h"
69 #include "var.h"
70 #include "input.h"
71 #include "output.h"
72 #include "memalloc.h"
73 #include "error.h"
74 #include "mystring.h"
75 #include "arith.h"
76 #include "show.h"
77
78 /*
79  * Structure specifying which parts of the string should be searched
80  * for IFS characters.
81  */
82
83 struct ifsregion {
84         struct ifsregion *next; /* next region in list */
85         int begoff;             /* offset of start of region */
86         int endoff;             /* offset of end of region */
87         int inquotes;           /* search for nul bytes only */
88 };
89
90
91 static char *expdest;                   /* output of current string */
92 static struct nodelist *argbackq;       /* list of back quote expressions */
93 static struct ifsregion ifsfirst;       /* first struct in list of ifs regions */
94 static struct ifsregion *ifslastp;      /* last struct in list */
95 static struct arglist exparg;           /* holds expanded arg list */
96
97 static void argstr(char *, int);
98 static char *exptilde(char *, int);
99 static void expbackq(union node *, int, int);
100 static int subevalvar(char *, char *, int, int, int, int);
101 static char *evalvar(char *, int);
102 static int varisset(char *, int);
103 static void varvalue(char *, int, int, int);
104 static void recordregion(int, int, int);
105 static void removerecordregions(int);
106 static void ifsbreakup(char *, struct arglist *);
107 static void expandmeta(struct strlist *, int);
108 static void expmeta(char *, char *);
109 static void addfname(char *);
110 static struct strlist *expsort(struct strlist *);
111 static struct strlist *msort(struct strlist *, int);
112 static int pmatch(const char *, const char *, int);
113 static char *cvtnum(int, char *);
114 static int collate_range_cmp(int, int);
115
116 static int
117 collate_range_cmp(int c1, int c2)
118 {
119         static char s1[2], s2[2];
120
121         s1[0] = c1;
122         s2[0] = c2;
123         return (strcoll(s1, s2));
124 }
125
126 /*
127  * Expand shell variables and backquotes inside a here document.
128  *      union node *arg         the document
129  *      int fd;                 where to write the expanded version
130  */
131
132 void
133 expandhere(union node *arg, int fd)
134 {
135         herefd = fd;
136         expandarg(arg, (struct arglist *)NULL, 0);
137         xwrite(fd, stackblock(), expdest - stackblock());
138 }
139
140
141 /*
142  * Perform expansions on an argument, placing the resulting list of arguments
143  * in arglist.  Parameter expansion, command substitution and arithmetic
144  * expansion are always performed; additional expansions can be requested
145  * via flag (EXP_*).
146  * The result is left in the stack string.
147  * When arglist is NULL, perform here document expansion.  A partial result
148  * may be written to herefd, which is then not included in the stack string.
149  *
150  * Caution: this function uses global state and is not reentrant.
151  * However, a new invocation after an interrupted invocation is safe
152  * and will reset the global state for the new call.
153  */
154 void
155 expandarg(union node *arg, struct arglist *arglist, int flag)
156 {
157         struct strlist *sp;
158         char *p;
159
160         argbackq = arg->narg.backquote;
161         STARTSTACKSTR(expdest);
162         ifsfirst.next = NULL;
163         ifslastp = NULL;
164         argstr(arg->narg.text, flag);
165         if (arglist == NULL) {
166                 return;                 /* here document expanded */
167         }
168         STPUTC('\0', expdest);
169         p = grabstackstr(expdest);
170         exparg.lastp = &exparg.list;
171         /*
172          * TODO - EXP_REDIR
173          */
174         if (flag & EXP_FULL) {
175                 ifsbreakup(p, &exparg);
176                 *exparg.lastp = NULL;
177                 exparg.lastp = &exparg.list;
178                 expandmeta(exparg.list, flag);
179         } else {
180                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
181                         rmescapes(p);
182                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
183                 sp->text = p;
184                 *exparg.lastp = sp;
185                 exparg.lastp = &sp->next;
186         }
187         while (ifsfirst.next != NULL) {
188                 struct ifsregion *ifsp;
189                 INTOFF;
190                 ifsp = ifsfirst.next->next;
191                 ckfree(ifsfirst.next);
192                 ifsfirst.next = ifsp;
193                 INTON;
194         }
195         *exparg.lastp = NULL;
196         if (exparg.list) {
197                 *arglist->lastp = exparg.list;
198                 arglist->lastp = exparg.lastp;
199         }
200 }
201
202
203
204 /*
205  * Perform parameter expansion, command substitution and arithmetic
206  * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
207  * Processing ends at a CTLENDVAR character as well as '\0'.
208  * This is used to expand word in ${var+word} etc.
209  * If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
210  * characters to allow for further processing.
211  * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
212  */
213 static void
214 argstr(char *p, int flag)
215 {
216         char c;
217         int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);  /* do CTLESC */
218         int firsteq = 1;
219
220         if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
221                 p = exptilde(p, flag);
222         for (;;) {
223                 switch (c = *p++) {
224                 case '\0':
225                 case CTLENDVAR:
226                         goto breakloop;
227                 case CTLQUOTEMARK:
228                         /* "$@" syntax adherence hack */
229                         if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
230                                 break;
231                         if ((flag & EXP_FULL) != 0)
232                                 STPUTC(c, expdest);
233                         break;
234                 case CTLESC:
235                         if (quotes)
236                                 STPUTC(c, expdest);
237                         c = *p++;
238                         STPUTC(c, expdest);
239                         break;
240                 case CTLVAR:
241                         p = evalvar(p, flag);
242                         break;
243                 case CTLBACKQ:
244                 case CTLBACKQ|CTLQUOTE:
245                         expbackq(argbackq->n, c & CTLQUOTE, flag);
246                         argbackq = argbackq->next;
247                         break;
248                 case CTLENDARI:
249                         expari(flag);
250                         break;
251                 case ':':
252                 case '=':
253                         /*
254                          * sort of a hack - expand tildes in variable
255                          * assignments (after the first '=' and after ':'s).
256                          */
257                         STPUTC(c, expdest);
258                         if (flag & EXP_VARTILDE && *p == '~') {
259                                 if (c == '=') {
260                                         if (firsteq)
261                                                 firsteq = 0;
262                                         else
263                                                 break;
264                                 }
265                                 p = exptilde(p, flag);
266                         }
267                         break;
268                 default:
269                         STPUTC(c, expdest);
270                 }
271         }
272 breakloop:;
273 }
274
275 /*
276  * Perform tilde expansion, placing the result in the stack string and
277  * returning the next position in the input string to process.
278  */
279 static char *
280 exptilde(char *p, int flag)
281 {
282         char c, *startp = p;
283         struct passwd *pw;
284         char *home;
285         int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
286
287         while ((c = *p) != '\0') {
288                 switch(c) {
289                 case CTLESC:
290                         return (startp);
291                 case CTLQUOTEMARK:
292                         return (startp);
293                 case ':':
294                         if (flag & EXP_VARTILDE)
295                                 goto done;
296                         break;
297                 case '/':
298                         goto done;
299                 }
300                 p++;
301         }
302 done:
303         *p = '\0';
304         if (*(startp+1) == '\0') {
305                 if ((home = lookupvar("HOME")) == NULL)
306                         goto lose;
307         } else {
308                 if ((pw = getpwnam(startp+1)) == NULL)
309                         goto lose;
310                 home = pw->pw_dir;
311         }
312         if (*home == '\0')
313                 goto lose;
314         *p = c;
315         while ((c = *home++) != '\0') {
316                 if (quotes && SQSYNTAX[(int)c] == CCTL)
317                         STPUTC(CTLESC, expdest);
318                 STPUTC(c, expdest);
319         }
320         return (p);
321 lose:
322         *p = c;
323         return (startp);
324 }
325
326
327 static void
328 removerecordregions(int endoff)
329 {
330         if (ifslastp == NULL)
331                 return;
332
333         if (ifsfirst.endoff > endoff) {
334                 while (ifsfirst.next != NULL) {
335                         struct ifsregion *ifsp;
336                         INTOFF;
337                         ifsp = ifsfirst.next->next;
338                         ckfree(ifsfirst.next);
339                         ifsfirst.next = ifsp;
340                         INTON;
341                 }
342                 if (ifsfirst.begoff > endoff)
343                         ifslastp = NULL;
344                 else {
345                         ifslastp = &ifsfirst;
346                         ifsfirst.endoff = endoff;
347                 }
348                 return;
349         }
350
351         ifslastp = &ifsfirst;
352         while (ifslastp->next && ifslastp->next->begoff < endoff)
353                 ifslastp=ifslastp->next;
354         while (ifslastp->next != NULL) {
355                 struct ifsregion *ifsp;
356                 INTOFF;
357                 ifsp = ifslastp->next->next;
358                 ckfree(ifslastp->next);
359                 ifslastp->next = ifsp;
360                 INTON;
361         }
362         if (ifslastp->endoff > endoff)
363                 ifslastp->endoff = endoff;
364 }
365
366 /*
367  * Expand arithmetic expression.  Backup to start of expression,
368  * evaluate, place result in (backed up) result, adjust string position.
369  */
370 void
371 expari(int flag)
372 {
373         char *p, *start;
374         arith_t result;
375         int begoff;
376         int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
377         int quoted;
378
379         /*
380          * This routine is slightly over-complicated for
381          * efficiency.  First we make sure there is
382          * enough space for the result, which may be bigger
383          * than the expression.  Next we
384          * scan backwards looking for the start of arithmetic.  If the
385          * next previous character is a CTLESC character, then we
386          * have to rescan starting from the beginning since CTLESC
387          * characters have to be processed left to right.
388          */
389         CHECKSTRSPACE(DIGITS(result) - 2, expdest);
390         USTPUTC('\0', expdest);
391         start = stackblock();
392         p = expdest - 2;
393         while (p >= start && *p != CTLARI)
394                 --p;
395         if (p < start || *p != CTLARI)
396                 error("missing CTLARI (shouldn't happen)");
397         if (p > start && *(p - 1) == CTLESC)
398                 for (p = start; *p != CTLARI; p++)
399                         if (*p == CTLESC)
400                                 p++;
401
402         if (p[1] == '"')
403                 quoted=1;
404         else
405                 quoted=0;
406         begoff = p - start;
407         removerecordregions(begoff);
408         if (quotes)
409                 rmescapes(p+2);
410         result = arith(p+2);
411         fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
412         while (*p++)
413                 ;
414         if (quoted == 0)
415                 recordregion(begoff, p - 1 - start, 0);
416         result = expdest - p + 1;
417         STADJUST(-result, expdest);
418 }
419
420
421 /*
422  * Perform command substitution.
423  */
424 static void
425 expbackq(union node *cmd, int quoted, int flag)
426 {
427         struct backcmd in;
428         int i;
429         char buf[128];
430         char *p;
431         char *dest = expdest;
432         struct ifsregion saveifs, *savelastp;
433         struct nodelist *saveargbackq;
434         char lastc;
435         int startloc = dest - stackblock();
436         char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
437         int saveherefd;
438         int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
439         int nnl;
440
441         INTOFF;
442         saveifs = ifsfirst;
443         savelastp = ifslastp;
444         saveargbackq = argbackq;
445         saveherefd = herefd;
446         herefd = -1;
447         p = grabstackstr(dest);
448         evalbackcmd(cmd, &in);
449         ungrabstackstr(p, dest);
450         ifsfirst = saveifs;
451         ifslastp = savelastp;
452         argbackq = saveargbackq;
453         herefd = saveherefd;
454
455         p = in.buf;
456         lastc = '\0';
457         nnl = 0;
458         /* Don't copy trailing newlines */
459         for (;;) {
460                 if (--in.nleft < 0) {
461                         if (in.fd < 0)
462                                 break;
463                         while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
464                         TRACE(("expbackq: read returns %d\n", i));
465                         if (i <= 0)
466                                 break;
467                         p = buf;
468                         in.nleft = i - 1;
469                 }
470                 lastc = *p++;
471                 if (lastc != '\0') {
472                         if (quotes && syntax[(int)lastc] == CCTL)
473                                 STPUTC(CTLESC, dest);
474                         if (lastc == '\n') {
475                                 nnl++;
476                         } else {
477                                 while (nnl > 0) {
478                                         nnl--;
479                                         STPUTC('\n', dest);
480                                 }
481                                 STPUTC(lastc, dest);
482                         }
483                 }
484         }
485
486         if (in.fd >= 0)
487                 close(in.fd);
488         if (in.buf)
489                 ckfree(in.buf);
490         if (in.jp)
491                 exitstatus = waitforjob(in.jp, (int *)NULL);
492         if (quoted == 0)
493                 recordregion(startloc, dest - stackblock(), 0);
494         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
495                 (dest - stackblock()) - startloc,
496                 (dest - stackblock()) - startloc,
497                 stackblock() + startloc));
498         expdest = dest;
499         INTON;
500 }
501
502
503
504 static int
505 subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
506   int varflags)
507 {
508         char *startp;
509         char *loc = NULL;
510         char *q;
511         int c = 0;
512         int saveherefd = herefd;
513         struct nodelist *saveargbackq = argbackq;
514         int amount;
515
516         herefd = -1;
517         argstr(p, 0);
518         STACKSTRNUL(expdest);
519         herefd = saveherefd;
520         argbackq = saveargbackq;
521         startp = stackblock() + startloc;
522         if (str == NULL)
523             str = stackblock() + strloc;
524
525         switch (subtype) {
526         case VSASSIGN:
527                 setvar(str, startp, 0);
528                 amount = startp - expdest;
529                 STADJUST(amount, expdest);
530                 varflags &= ~VSNUL;
531                 if (c != 0)
532                         *loc = c;
533                 return 1;
534
535         case VSQUESTION:
536                 if (*p != CTLENDVAR) {
537                         outfmt(&errout, "%s\n", startp);
538                         error((char *)NULL);
539                 }
540                 error("%.*s: parameter %snot set", (int)(p - str - 1),
541                       str, (varflags & VSNUL) ? "null or "
542                                               : nullstr);
543                 return 0;
544
545         case VSTRIMLEFT:
546                 for (loc = startp; loc < str; loc++) {
547                         c = *loc;
548                         *loc = '\0';
549                         if (patmatch(str, startp, varflags & VSQUOTE)) {
550                                 *loc = c;
551                                 goto recordleft;
552                         }
553                         *loc = c;
554                         if ((varflags & VSQUOTE) && *loc == CTLESC)
555                                 loc++;
556                 }
557                 return 0;
558
559         case VSTRIMLEFTMAX:
560                 for (loc = str - 1; loc >= startp;) {
561                         c = *loc;
562                         *loc = '\0';
563                         if (patmatch(str, startp, varflags & VSQUOTE)) {
564                                 *loc = c;
565                                 goto recordleft;
566                         }
567                         *loc = c;
568                         loc--;
569                         if ((varflags & VSQUOTE) && loc > startp &&
570                             *(loc - 1) == CTLESC) {
571                                 for (q = startp; q < loc; q++)
572                                         if (*q == CTLESC)
573                                                 q++;
574                                 if (q > loc)
575                                         loc--;
576                         }
577                 }
578                 return 0;
579
580         case VSTRIMRIGHT:
581                 for (loc = str - 1; loc >= startp;) {
582                         if (patmatch(str, loc, varflags & VSQUOTE)) {
583                                 amount = loc - expdest;
584                                 STADJUST(amount, expdest);
585                                 return 1;
586                         }
587                         loc--;
588                         if ((varflags & VSQUOTE) && loc > startp &&
589                             *(loc - 1) == CTLESC) {
590                                 for (q = startp; q < loc; q++)
591                                         if (*q == CTLESC)
592                                                 q++;
593                                 if (q > loc)
594                                         loc--;
595                         }
596                 }
597                 return 0;
598
599         case VSTRIMRIGHTMAX:
600                 for (loc = startp; loc < str - 1; loc++) {
601                         if (patmatch(str, loc, varflags & VSQUOTE)) {
602                                 amount = loc - expdest;
603                                 STADJUST(amount, expdest);
604                                 return 1;
605                         }
606                         if ((varflags & VSQUOTE) && *loc == CTLESC)
607                                 loc++;
608                 }
609                 return 0;
610
611
612         default:
613                 abort();
614         }
615
616 recordleft:
617         amount = ((str - 1) - (loc - startp)) - expdest;
618         STADJUST(amount, expdest);
619         while (loc != str - 1)
620                 *startp++ = *loc++;
621         return 1;
622 }
623
624
625 /*
626  * Expand a variable, and return a pointer to the next character in the
627  * input string.
628  */
629
630 static char *
631 evalvar(char *p, int flag)
632 {
633         int subtype;
634         int varflags;
635         char *var;
636         char *val;
637         int patloc;
638         int c;
639         int set;
640         int special;
641         int startloc;
642         int varlen;
643         int easy;
644         int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
645
646         varflags = (unsigned char)*p++;
647         subtype = varflags & VSTYPE;
648         var = p;
649         special = 0;
650         if (! is_name(*p))
651                 special = 1;
652         p = strchr(p, '=') + 1;
653 again: /* jump here after setting a variable with ${var=text} */
654         if (varflags & VSLINENO) {
655                 set = 1;
656                 special = 0;
657                 val = var;
658                 p[-1] = '\0';   /* temporarily overwrite '=' to have \0
659                                    terminated string */
660         } else if (special) {
661                 set = varisset(var, varflags & VSNUL);
662                 val = NULL;
663         } else {
664                 val = bltinlookup(var, 1);
665                 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
666                         val = NULL;
667                         set = 0;
668                 } else
669                         set = 1;
670         }
671         varlen = 0;
672         startloc = expdest - stackblock();
673         if (!set && uflag) {
674                 switch (subtype) {
675                 case VSNORMAL:
676                 case VSTRIMLEFT:
677                 case VSTRIMLEFTMAX:
678                 case VSTRIMRIGHT:
679                 case VSTRIMRIGHTMAX:
680                 case VSLENGTH:
681                         error("%.*s: parameter not set", (int)(p - var - 1),
682                             var);
683                 }
684         }
685         if (set && subtype != VSPLUS) {
686                 /* insert the value of the variable */
687                 if (special) {
688                         varvalue(var, varflags & VSQUOTE, subtype, flag);
689                         if (subtype == VSLENGTH) {
690                                 varlen = expdest - stackblock() - startloc;
691                                 STADJUST(-varlen, expdest);
692                         }
693                 } else {
694                         char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
695                                                                   : BASESYNTAX;
696
697                         if (subtype == VSLENGTH) {
698                                 for (;*val; val++)
699                                         varlen++;
700                         }
701                         else {
702                                 while (*val) {
703                                         if (quotes &&
704                                             syntax[(int)*val] == CCTL)
705                                                 STPUTC(CTLESC, expdest);
706                                         STPUTC(*val++, expdest);
707                                 }
708
709                         }
710                 }
711         }
712
713         if (subtype == VSPLUS)
714                 set = ! set;
715
716         easy = ((varflags & VSQUOTE) == 0 ||
717                 (*var == '@' && shellparam.nparam != 1));
718
719
720         switch (subtype) {
721         case VSLENGTH:
722                 expdest = cvtnum(varlen, expdest);
723                 goto record;
724
725         case VSNORMAL:
726                 if (!easy)
727                         break;
728 record:
729                 recordregion(startloc, expdest - stackblock(),
730                              varflags & VSQUOTE);
731                 break;
732
733         case VSPLUS:
734         case VSMINUS:
735                 if (!set) {
736                         argstr(p, flag);
737                         break;
738                 }
739                 if (easy)
740                         goto record;
741                 break;
742
743         case VSTRIMLEFT:
744         case VSTRIMLEFTMAX:
745         case VSTRIMRIGHT:
746         case VSTRIMRIGHTMAX:
747                 if (!set)
748                         break;
749                 /*
750                  * Terminate the string and start recording the pattern
751                  * right after it
752                  */
753                 STPUTC('\0', expdest);
754                 patloc = expdest - stackblock();
755                 if (subevalvar(p, NULL, patloc, subtype,
756                                startloc, varflags) == 0) {
757                         int amount = (expdest - stackblock() - patloc) + 1;
758                         STADJUST(-amount, expdest);
759                 }
760                 /* Remove any recorded regions beyond start of variable */
761                 removerecordregions(startloc);
762                 goto record;
763
764         case VSASSIGN:
765         case VSQUESTION:
766                 if (!set) {
767                         if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
768                                 varflags &= ~VSNUL;
769                                 /*
770                                  * Remove any recorded regions beyond
771                                  * start of variable
772                                  */
773                                 removerecordregions(startloc);
774                                 goto again;
775                         }
776                         break;
777                 }
778                 if (easy)
779                         goto record;
780                 break;
781
782         case VSERROR:
783                 c = p - var - 1;
784                 error("${%.*s%s}: Bad substitution", c, var,
785                     (c > 0 && *p != CTLENDVAR) ? "..." : "");
786
787         default:
788                 abort();
789         }
790         p[-1] = '=';    /* recover overwritten '=' */
791
792         if (subtype != VSNORMAL) {      /* skip to end of alternative */
793                 int nesting = 1;
794                 for (;;) {
795                         if ((c = *p++) == CTLESC)
796                                 p++;
797                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
798                                 if (set)
799                                         argbackq = argbackq->next;
800                         } else if (c == CTLVAR) {
801                                 if ((*p++ & VSTYPE) != VSNORMAL)
802                                         nesting++;
803                         } else if (c == CTLENDVAR) {
804                                 if (--nesting == 0)
805                                         break;
806                         }
807                 }
808         }
809         return p;
810 }
811
812
813
814 /*
815  * Test whether a specialized variable is set.
816  */
817
818 static int
819 varisset(char *name, int nulok)
820 {
821
822         if (*name == '!')
823                 return backgndpid != -1;
824         else if (*name == '@' || *name == '*') {
825                 if (*shellparam.p == NULL)
826                         return 0;
827
828                 if (nulok) {
829                         char **av;
830
831                         for (av = shellparam.p; *av; av++)
832                                 if (**av != '\0')
833                                         return 1;
834                         return 0;
835                 }
836         } else if (is_digit(*name)) {
837                 char *ap;
838                 int num = atoi(name);
839
840                 if (num > shellparam.nparam)
841                         return 0;
842
843                 if (num == 0)
844                         ap = arg0;
845                 else
846                         ap = shellparam.p[num - 1];
847
848                 if (nulok && (ap == NULL || *ap == '\0'))
849                         return 0;
850         }
851         return 1;
852 }
853
854
855
856 /*
857  * Add the value of a specialized variable to the stack string.
858  */
859
860 static void
861 varvalue(char *name, int quoted, int subtype, int flag)
862 {
863         int num;
864         char *p;
865         int i;
866         char sep;
867         char **ap;
868         char const *syntax;
869
870 #define STRTODEST(p) \
871         do {\
872         if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
873                 syntax = quoted? DQSYNTAX : BASESYNTAX; \
874                 while (*p) { \
875                         if (syntax[(int)*p] == CCTL) \
876                                 STPUTC(CTLESC, expdest); \
877                         STPUTC(*p++, expdest); \
878                 } \
879         } else \
880                 while (*p) \
881                         STPUTC(*p++, expdest); \
882         } while (0)
883
884
885         switch (*name) {
886         case '$':
887                 num = rootpid;
888                 goto numvar;
889         case '?':
890                 num = oexitstatus;
891                 goto numvar;
892         case '#':
893                 num = shellparam.nparam;
894                 goto numvar;
895         case '!':
896                 num = backgndpid;
897 numvar:
898                 expdest = cvtnum(num, expdest);
899                 break;
900         case '-':
901                 for (i = 0 ; i < NOPTS ; i++) {
902                         if (optlist[i].val)
903                                 STPUTC(optlist[i].letter, expdest);
904                 }
905                 break;
906         case '@':
907                 if (flag & EXP_FULL && quoted) {
908                         for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
909                                 STRTODEST(p);
910                                 if (*ap)
911                                         STPUTC('\0', expdest);
912                         }
913                         break;
914                 }
915                 /* FALLTHROUGH */
916         case '*':
917                 if (ifsset())
918                         sep = ifsval()[0];
919                 else
920                         sep = ' ';
921                 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
922                         STRTODEST(p);
923                         if (*ap && sep)
924                                 STPUTC(sep, expdest);
925                 }
926                 break;
927         case '0':
928                 p = arg0;
929                 STRTODEST(p);
930                 break;
931         default:
932                 if (is_digit(*name)) {
933                         num = atoi(name);
934                         if (num > 0 && num <= shellparam.nparam) {
935                                 p = shellparam.p[num - 1];
936                                 STRTODEST(p);
937                         }
938                 }
939                 break;
940         }
941 }
942
943
944
945 /*
946  * Record the the fact that we have to scan this region of the
947  * string for IFS characters.
948  */
949
950 static void
951 recordregion(int start, int end, int inquotes)
952 {
953         struct ifsregion *ifsp;
954
955         if (ifslastp == NULL) {
956                 ifsp = &ifsfirst;
957         } else {
958                 if (ifslastp->endoff == start
959                     && ifslastp->inquotes == inquotes) {
960                         /* extend previous area */
961                         ifslastp->endoff = end;
962                         return;
963                 }
964                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
965                 ifslastp->next = ifsp;
966         }
967         ifslastp = ifsp;
968         ifslastp->next = NULL;
969         ifslastp->begoff = start;
970         ifslastp->endoff = end;
971         ifslastp->inquotes = inquotes;
972 }
973
974
975
976 /*
977  * Break the argument string into pieces based upon IFS and add the
978  * strings to the argument list.  The regions of the string to be
979  * searched for IFS characters have been stored by recordregion.
980  * CTLESC characters are preserved but have little effect in this pass
981  * other than escaping CTL* characters.  In particular, they do not escape
982  * IFS characters: that should be done with the ifsregion mechanism.
983  * CTLQUOTEMARK characters are used to preserve empty quoted strings.
984  * This pass treats them as a regular character, making the string non-empty.
985  * Later, they are removed along with the other CTL* characters.
986  */
987 static void
988 ifsbreakup(char *string, struct arglist *arglist)
989 {
990         struct ifsregion *ifsp;
991         struct strlist *sp;
992         char *start;
993         char *p;
994         char *q;
995         const char *ifs;
996         const char *ifsspc;
997         int had_param_ch = 0;
998
999         start = string;
1000
1001         if (ifslastp == NULL) {
1002                 /* Return entire argument, IFS doesn't apply to any of it */
1003                 sp = (struct strlist *)stalloc(sizeof *sp);
1004                 sp->text = start;
1005                 *arglist->lastp = sp;
1006                 arglist->lastp = &sp->next;
1007                 return;
1008         }
1009
1010         ifs = ifsset() ? ifsval() : " \t\n";
1011
1012         for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
1013                 p = string + ifsp->begoff;
1014                 while (p < string + ifsp->endoff) {
1015                         q = p;
1016                         if (*p == CTLESC)
1017                                 p++;
1018                         if (ifsp->inquotes) {
1019                                 /* Only NULs (should be from "$@") end args */
1020                                 had_param_ch = 1;
1021                                 if (*p != 0) {
1022                                         p++;
1023                                         continue;
1024                                 }
1025                                 ifsspc = NULL;
1026                         } else {
1027                                 if (!strchr(ifs, *p)) {
1028                                         had_param_ch = 1;
1029                                         p++;
1030                                         continue;
1031                                 }
1032                                 ifsspc = strchr(" \t\n", *p);
1033
1034                                 /* Ignore IFS whitespace at start */
1035                                 if (q == start && ifsspc != NULL) {
1036                                         p++;
1037                                         start = p;
1038                                         continue;
1039                                 }
1040                                 had_param_ch = 0;
1041                         }
1042
1043                         /* Save this argument... */
1044                         *q = '\0';
1045                         sp = (struct strlist *)stalloc(sizeof *sp);
1046                         sp->text = start;
1047                         *arglist->lastp = sp;
1048                         arglist->lastp = &sp->next;
1049                         p++;
1050
1051                         if (ifsspc != NULL) {
1052                                 /* Ignore further trailing IFS whitespace */
1053                                 for (; p < string + ifsp->endoff; p++) {
1054                                         q = p;
1055                                         if (*p == CTLESC)
1056                                                 p++;
1057                                         if (strchr(ifs, *p) == NULL) {
1058                                                 p = q;
1059                                                 break;
1060                                         }
1061                                         if (strchr(" \t\n", *p) == NULL) {
1062                                                 p++;
1063                                                 break;
1064                                         }
1065                                 }
1066                         }
1067                         start = p;
1068                 }
1069         }
1070
1071         /*
1072          * Save anything left as an argument.
1073          * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1074          * generating 2 arguments, the second of which is empty.
1075          * Some recent clarification of the Posix spec say that it
1076          * should only generate one....
1077          */
1078         if (had_param_ch || *start != 0) {
1079                 sp = (struct strlist *)stalloc(sizeof *sp);
1080                 sp->text = start;
1081                 *arglist->lastp = sp;
1082                 arglist->lastp = &sp->next;
1083         }
1084 }
1085
1086
1087 static char expdir[PATH_MAX];
1088 #define expdir_end (expdir + sizeof(expdir))
1089
1090 /*
1091  * Perform pathname generation and remove control characters.
1092  * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
1093  * The results are stored in the list exparg.
1094  */
1095 static void
1096 expandmeta(struct strlist *str, int flag __unused)
1097 {
1098         char *p;
1099         struct strlist **savelastp;
1100         struct strlist *sp;
1101         char c;
1102         /* TODO - EXP_REDIR */
1103
1104         while (str) {
1105                 if (fflag)
1106                         goto nometa;
1107                 p = str->text;
1108                 for (;;) {                      /* fast check for meta chars */
1109                         if ((c = *p++) == '\0')
1110                                 goto nometa;
1111                         if (c == '*' || c == '?' || c == '[' || c == '!')
1112                                 break;
1113                 }
1114                 savelastp = exparg.lastp;
1115                 INTOFF;
1116                 expmeta(expdir, str->text);
1117                 INTON;
1118                 if (exparg.lastp == savelastp) {
1119                         /*
1120                          * no matches
1121                          */
1122 nometa:
1123                         *exparg.lastp = str;
1124                         rmescapes(str->text);
1125                         exparg.lastp = &str->next;
1126                 } else {
1127                         *exparg.lastp = NULL;
1128                         *savelastp = sp = expsort(*savelastp);
1129                         while (sp->next != NULL)
1130                                 sp = sp->next;
1131                         exparg.lastp = &sp->next;
1132                 }
1133                 str = str->next;
1134         }
1135 }
1136
1137
1138 /*
1139  * Do metacharacter (i.e. *, ?, [...]) expansion.
1140  */
1141
1142 static void
1143 expmeta(char *enddir, char *name)
1144 {
1145         char *p;
1146         char *q;
1147         char *start;
1148         char *endname;
1149         int metaflag;
1150         struct stat statb;
1151         DIR *dirp;
1152         struct dirent *dp;
1153         int atend;
1154         int matchdot;
1155         int esc;
1156
1157         metaflag = 0;
1158         start = name;
1159         for (p = name; esc = 0, *p; p += esc + 1) {
1160                 if (*p == '*' || *p == '?')
1161                         metaflag = 1;
1162                 else if (*p == '[') {
1163                         q = p + 1;
1164                         if (*q == '!' || *q == '^')
1165                                 q++;
1166                         for (;;) {
1167                                 while (*q == CTLQUOTEMARK)
1168                                         q++;
1169                                 if (*q == CTLESC)
1170                                         q++;
1171                                 if (*q == '/' || *q == '\0')
1172                                         break;
1173                                 if (*++q == ']') {
1174                                         metaflag = 1;
1175                                         break;
1176                                 }
1177                         }
1178                 } else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
1179                         metaflag = 1;
1180                 } else if (*p == '\0')
1181                         break;
1182                 else if (*p == CTLQUOTEMARK)
1183                         continue;
1184                 else {
1185                         if (*p == CTLESC)
1186                                 esc++;
1187                         if (p[esc] == '/') {
1188                                 if (metaflag)
1189                                         break;
1190                                 start = p + esc + 1;
1191                         }
1192                 }
1193         }
1194         if (metaflag == 0) {    /* we've reached the end of the file name */
1195                 if (enddir != expdir)
1196                         metaflag++;
1197                 for (p = name ; ; p++) {
1198                         if (*p == CTLQUOTEMARK)
1199                                 continue;
1200                         if (*p == CTLESC)
1201                                 p++;
1202                         *enddir++ = *p;
1203                         if (*p == '\0')
1204                                 break;
1205                         if (enddir == expdir_end)
1206                                 return;
1207                 }
1208                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1209                         addfname(expdir);
1210                 return;
1211         }
1212         endname = p;
1213         if (start != name) {
1214                 p = name;
1215                 while (p < start) {
1216                         while (*p == CTLQUOTEMARK)
1217                                 p++;
1218                         if (*p == CTLESC)
1219                                 p++;
1220                         *enddir++ = *p++;
1221                         if (enddir == expdir_end)
1222                                 return;
1223                 }
1224         }
1225         if (enddir == expdir) {
1226                 p = ".";
1227         } else if (enddir == expdir + 1 && *expdir == '/') {
1228                 p = "/";
1229         } else {
1230                 p = expdir;
1231                 enddir[-1] = '\0';
1232         }
1233         if ((dirp = opendir(p)) == NULL)
1234                 return;
1235         if (enddir != expdir)
1236                 enddir[-1] = '/';
1237         if (*endname == 0) {
1238                 atend = 1;
1239         } else {
1240                 atend = 0;
1241                 *endname = '\0';
1242                 endname += esc + 1;
1243         }
1244         matchdot = 0;
1245         p = start;
1246         while (*p == CTLQUOTEMARK)
1247                 p++;
1248         if (*p == CTLESC)
1249                 p++;
1250         if (*p == '.')
1251                 matchdot++;
1252         while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1253                 if (dp->d_name[0] == '.' && ! matchdot)
1254                         continue;
1255                 if (patmatch(start, dp->d_name, 0)) {
1256                         if (enddir + dp->d_namlen + 1 > expdir_end)
1257                                 continue;
1258                         memcpy(enddir, dp->d_name, dp->d_namlen + 1);
1259                         if (atend)
1260                                 addfname(expdir);
1261                         else {
1262                                 if (enddir + dp->d_namlen + 2 > expdir_end)
1263                                         continue;
1264                                 enddir[dp->d_namlen] = '/';
1265                                 enddir[dp->d_namlen + 1] = '\0';
1266                                 expmeta(enddir + dp->d_namlen + 1, endname);
1267                         }
1268                 }
1269         }
1270         closedir(dirp);
1271         if (! atend)
1272                 endname[-esc - 1] = esc ? CTLESC : '/';
1273 }
1274
1275
1276 /*
1277  * Add a file name to the list.
1278  */
1279
1280 static void
1281 addfname(char *name)
1282 {
1283         char *p;
1284         struct strlist *sp;
1285
1286         p = stalloc(strlen(name) + 1);
1287         scopy(name, p);
1288         sp = (struct strlist *)stalloc(sizeof *sp);
1289         sp->text = p;
1290         *exparg.lastp = sp;
1291         exparg.lastp = &sp->next;
1292 }
1293
1294
1295 /*
1296  * Sort the results of file name expansion.  It calculates the number of
1297  * strings to sort and then calls msort (short for merge sort) to do the
1298  * work.
1299  */
1300
1301 static struct strlist *
1302 expsort(struct strlist *str)
1303 {
1304         int len;
1305         struct strlist *sp;
1306
1307         len = 0;
1308         for (sp = str ; sp ; sp = sp->next)
1309                 len++;
1310         return msort(str, len);
1311 }
1312
1313
1314 static struct strlist *
1315 msort(struct strlist *list, int len)
1316 {
1317         struct strlist *p, *q = NULL;
1318         struct strlist **lpp;
1319         int half;
1320         int n;
1321
1322         if (len <= 1)
1323                 return list;
1324         half = len >> 1;
1325         p = list;
1326         for (n = half ; --n >= 0 ; ) {
1327                 q = p;
1328                 p = p->next;
1329         }
1330         q->next = NULL;                 /* terminate first half of list */
1331         q = msort(list, half);          /* sort first half of list */
1332         p = msort(p, len - half);               /* sort second half */
1333         lpp = &list;
1334         for (;;) {
1335                 if (strcmp(p->text, q->text) < 0) {
1336                         *lpp = p;
1337                         lpp = &p->next;
1338                         if ((p = *lpp) == NULL) {
1339                                 *lpp = q;
1340                                 break;
1341                         }
1342                 } else {
1343                         *lpp = q;
1344                         lpp = &q->next;
1345                         if ((q = *lpp) == NULL) {
1346                                 *lpp = p;
1347                                 break;
1348                         }
1349                 }
1350         }
1351         return list;
1352 }
1353
1354
1355
1356 /*
1357  * Returns true if the pattern matches the string.
1358  */
1359
1360 int
1361 patmatch(const char *pattern, const char *string, int squoted)
1362 {
1363 #ifdef notdef
1364         if (pattern[0] == '!' && pattern[1] == '!')
1365                 return 1 - pmatch(pattern + 2, string);
1366         else
1367 #endif
1368                 return pmatch(pattern, string, squoted);
1369 }
1370
1371
1372 static int
1373 pmatch(const char *pattern, const char *string, int squoted)
1374 {
1375         const char *p, *q;
1376         char c;
1377
1378         p = pattern;
1379         q = string;
1380         for (;;) {
1381                 switch (c = *p++) {
1382                 case '\0':
1383                         goto breakloop;
1384                 case CTLESC:
1385                         if (squoted && *q == CTLESC)
1386                                 q++;
1387                         if (*q++ != *p++)
1388                                 return 0;
1389                         break;
1390                 case CTLQUOTEMARK:
1391                         continue;
1392                 case '?':
1393                         if (squoted && *q == CTLESC)
1394                                 q++;
1395                         if (*q++ == '\0')
1396                                 return 0;
1397                         break;
1398                 case '*':
1399                         c = *p;
1400                         while (c == CTLQUOTEMARK || c == '*')
1401                                 c = *++p;
1402                         if (c != CTLESC &&  c != CTLQUOTEMARK &&
1403                             c != '?' && c != '*' && c != '[') {
1404                                 while (*q != c) {
1405                                         if (squoted && *q == CTLESC &&
1406                                             q[1] == c)
1407                                                 break;
1408                                         if (*q == '\0')
1409                                                 return 0;
1410                                         if (squoted && *q == CTLESC)
1411                                                 q++;
1412                                         q++;
1413                                 }
1414                         }
1415                         do {
1416                                 if (pmatch(p, q, squoted))
1417                                         return 1;
1418                                 if (squoted && *q == CTLESC)
1419                                         q++;
1420                         } while (*q++ != '\0');
1421                         return 0;
1422                 case '[': {
1423                         const char *endp;
1424                         int invert, found;
1425                         char chr;
1426
1427                         endp = p;
1428                         if (*endp == '!' || *endp == '^')
1429                                 endp++;
1430                         for (;;) {
1431                                 while (*endp == CTLQUOTEMARK)
1432                                         endp++;
1433                                 if (*endp == '\0')
1434                                         goto dft;               /* no matching ] */
1435                                 if (*endp == CTLESC)
1436                                         endp++;
1437                                 if (*++endp == ']')
1438                                         break;
1439                         }
1440                         invert = 0;
1441                         if (*p == '!' || *p == '^') {
1442                                 invert++;
1443                                 p++;
1444                         }
1445                         found = 0;
1446                         chr = *q++;
1447                         if (squoted && chr == CTLESC)
1448                                 chr = *q++;
1449                         if (chr == '\0')
1450                                 return 0;
1451                         c = *p++;
1452                         do {
1453                                 if (c == CTLQUOTEMARK)
1454                                         continue;
1455                                 if (c == CTLESC)
1456                                         c = *p++;
1457                                 if (*p == '-' && p[1] != ']') {
1458                                         p++;
1459                                         while (*p == CTLQUOTEMARK)
1460                                                 p++;
1461                                         if (*p == CTLESC)
1462                                                 p++;
1463                                         if (   collate_range_cmp(chr, c) >= 0
1464                                             && collate_range_cmp(chr, *p) <= 0
1465                                            )
1466                                                 found = 1;
1467                                         p++;
1468                                 } else {
1469                                         if (chr == c)
1470                                                 found = 1;
1471                                 }
1472                         } while ((c = *p++) != ']');
1473                         if (found == invert)
1474                                 return 0;
1475                         break;
1476                 }
1477 dft:            default:
1478                         if (squoted && *q == CTLESC)
1479                                 q++;
1480                         if (*q++ != c)
1481                                 return 0;
1482                         break;
1483                 }
1484         }
1485 breakloop:
1486         if (*q != '\0')
1487                 return 0;
1488         return 1;
1489 }
1490
1491
1492
1493 /*
1494  * Remove any CTLESC and CTLQUOTEMARK characters from a string.
1495  */
1496
1497 void
1498 rmescapes(char *str)
1499 {
1500         char *p, *q;
1501
1502         p = str;
1503         while (*p != CTLESC && *p != CTLQUOTEMARK) {
1504                 if (*p++ == '\0')
1505                         return;
1506         }
1507         q = p;
1508         while (*p) {
1509                 if (*p == CTLQUOTEMARK) {
1510                         p++;
1511                         continue;
1512                 }
1513                 if (*p == CTLESC)
1514                         p++;
1515                 *q++ = *p++;
1516         }
1517         *q = '\0';
1518 }
1519
1520
1521
1522 /*
1523  * See if a pattern matches in a case statement.
1524  */
1525
1526 int
1527 casematch(union node *pattern, const char *val)
1528 {
1529         struct stackmark smark;
1530         int result;
1531         char *p;
1532
1533         setstackmark(&smark);
1534         argbackq = pattern->narg.backquote;
1535         STARTSTACKSTR(expdest);
1536         ifslastp = NULL;
1537         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1538         STPUTC('\0', expdest);
1539         p = grabstackstr(expdest);
1540         result = patmatch(p, val, 0);
1541         popstackmark(&smark);
1542         return result;
1543 }
1544
1545 /*
1546  * Our own itoa().
1547  */
1548
1549 static char *
1550 cvtnum(int num, char *buf)
1551 {
1552         char temp[32];
1553         int neg = num < 0;
1554         char *p = temp + 31;
1555
1556         temp[31] = '\0';
1557
1558         do {
1559                 *--p = num % 10 + '0';
1560         } while ((num /= 10) != 0);
1561
1562         if (neg)
1563                 *--p = '-';
1564
1565         while (*p)
1566                 STPUTC(*p++, buf);
1567         return buf;
1568 }
1569
1570 /*
1571  * Do most of the work for wordexp(3).
1572  */
1573
1574 int
1575 wordexpcmd(int argc, char **argv)
1576 {
1577         size_t len;
1578         int i;
1579
1580         out1fmt("%08x", argc - 1);
1581         for (i = 1, len = 0; i < argc; i++)
1582                 len += strlen(argv[i]);
1583         out1fmt("%08x", (int)len);
1584         for (i = 1; i < argc; i++) {
1585                 out1str(argv[i]);
1586                 out1c('\0');
1587         }
1588         return (0);
1589 }