]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - bin/sh/expand.c
MFC
[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 /*
1088  * Perform pathname generation and remove control characters.
1089  * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
1090  * The results are stored in the list exparg.
1091  */
1092
1093 static char expdir[PATH_MAX];
1094 #define expdir_end (expdir + sizeof(expdir))
1095
1096 static void
1097 expandmeta(struct strlist *str, int flag __unused)
1098 {
1099         char *p;
1100         struct strlist **savelastp;
1101         struct strlist *sp;
1102         char c;
1103         /* TODO - EXP_REDIR */
1104
1105         while (str) {
1106                 if (fflag)
1107                         goto nometa;
1108                 p = str->text;
1109                 for (;;) {                      /* fast check for meta chars */
1110                         if ((c = *p++) == '\0')
1111                                 goto nometa;
1112                         if (c == '*' || c == '?' || c == '[' || c == '!')
1113                                 break;
1114                 }
1115                 savelastp = exparg.lastp;
1116                 INTOFF;
1117                 expmeta(expdir, str->text);
1118                 INTON;
1119                 if (exparg.lastp == savelastp) {
1120                         /*
1121                          * no matches
1122                          */
1123 nometa:
1124                         *exparg.lastp = str;
1125                         rmescapes(str->text);
1126                         exparg.lastp = &str->next;
1127                 } else {
1128                         *exparg.lastp = NULL;
1129                         *savelastp = sp = expsort(*savelastp);
1130                         while (sp->next != NULL)
1131                                 sp = sp->next;
1132                         exparg.lastp = &sp->next;
1133                 }
1134                 str = str->next;
1135         }
1136 }
1137
1138
1139 /*
1140  * Do metacharacter (i.e. *, ?, [...]) expansion.
1141  */
1142
1143 static void
1144 expmeta(char *enddir, char *name)
1145 {
1146         char *p;
1147         char *q;
1148         char *start;
1149         char *endname;
1150         int metaflag;
1151         struct stat statb;
1152         DIR *dirp;
1153         struct dirent *dp;
1154         int atend;
1155         int matchdot;
1156         int esc;
1157
1158         metaflag = 0;
1159         start = name;
1160         for (p = name; esc = 0, *p; p += esc + 1) {
1161                 if (*p == '*' || *p == '?')
1162                         metaflag = 1;
1163                 else if (*p == '[') {
1164                         q = p + 1;
1165                         if (*q == '!' || *q == '^')
1166                                 q++;
1167                         for (;;) {
1168                                 while (*q == CTLQUOTEMARK)
1169                                         q++;
1170                                 if (*q == CTLESC)
1171                                         q++;
1172                                 if (*q == '/' || *q == '\0')
1173                                         break;
1174                                 if (*++q == ']') {
1175                                         metaflag = 1;
1176                                         break;
1177                                 }
1178                         }
1179                 } else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
1180                         metaflag = 1;
1181                 } else if (*p == '\0')
1182                         break;
1183                 else if (*p == CTLQUOTEMARK)
1184                         continue;
1185                 else {
1186                         if (*p == CTLESC)
1187                                 esc++;
1188                         if (p[esc] == '/') {
1189                                 if (metaflag)
1190                                         break;
1191                                 start = p + esc + 1;
1192                         }
1193                 }
1194         }
1195         if (metaflag == 0) {    /* we've reached the end of the file name */
1196                 if (enddir != expdir)
1197                         metaflag++;
1198                 for (p = name ; ; p++) {
1199                         if (*p == CTLQUOTEMARK)
1200                                 continue;
1201                         if (*p == CTLESC)
1202                                 p++;
1203                         *enddir++ = *p;
1204                         if (*p == '\0')
1205                                 break;
1206                         if (enddir == expdir_end)
1207                                 return;
1208                 }
1209                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1210                         addfname(expdir);
1211                 return;
1212         }
1213         endname = p;
1214         if (start != name) {
1215                 p = name;
1216                 while (p < start) {
1217                         while (*p == CTLQUOTEMARK)
1218                                 p++;
1219                         if (*p == CTLESC)
1220                                 p++;
1221                         *enddir++ = *p++;
1222                         if (enddir == expdir_end)
1223                                 return;
1224                 }
1225         }
1226         if (enddir == expdir) {
1227                 p = ".";
1228         } else if (enddir == expdir + 1 && *expdir == '/') {
1229                 p = "/";
1230         } else {
1231                 p = expdir;
1232                 enddir[-1] = '\0';
1233         }
1234         if ((dirp = opendir(p)) == NULL)
1235                 return;
1236         if (enddir != expdir)
1237                 enddir[-1] = '/';
1238         if (*endname == 0) {
1239                 atend = 1;
1240         } else {
1241                 atend = 0;
1242                 *endname = '\0';
1243                 endname += esc + 1;
1244         }
1245         matchdot = 0;
1246         p = start;
1247         while (*p == CTLQUOTEMARK)
1248                 p++;
1249         if (*p == CTLESC)
1250                 p++;
1251         if (*p == '.')
1252                 matchdot++;
1253         while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1254                 if (dp->d_name[0] == '.' && ! matchdot)
1255                         continue;
1256                 if (patmatch(start, dp->d_name, 0)) {
1257                         if (enddir + dp->d_namlen + 1 > expdir_end)
1258                                 continue;
1259                         memcpy(enddir, dp->d_name, dp->d_namlen + 1);
1260                         if (atend)
1261                                 addfname(expdir);
1262                         else {
1263                                 if (enddir + dp->d_namlen + 2 > expdir_end)
1264                                         continue;
1265                                 enddir[dp->d_namlen] = '/';
1266                                 enddir[dp->d_namlen + 1] = '\0';
1267                                 expmeta(enddir + dp->d_namlen + 1, endname);
1268                         }
1269                 }
1270         }
1271         closedir(dirp);
1272         if (! atend)
1273                 endname[-esc - 1] = esc ? CTLESC : '/';
1274 }
1275
1276
1277 /*
1278  * Add a file name to the list.
1279  */
1280
1281 static void
1282 addfname(char *name)
1283 {
1284         char *p;
1285         struct strlist *sp;
1286
1287         p = stalloc(strlen(name) + 1);
1288         scopy(name, p);
1289         sp = (struct strlist *)stalloc(sizeof *sp);
1290         sp->text = p;
1291         *exparg.lastp = sp;
1292         exparg.lastp = &sp->next;
1293 }
1294
1295
1296 /*
1297  * Sort the results of file name expansion.  It calculates the number of
1298  * strings to sort and then calls msort (short for merge sort) to do the
1299  * work.
1300  */
1301
1302 static struct strlist *
1303 expsort(struct strlist *str)
1304 {
1305         int len;
1306         struct strlist *sp;
1307
1308         len = 0;
1309         for (sp = str ; sp ; sp = sp->next)
1310                 len++;
1311         return msort(str, len);
1312 }
1313
1314
1315 static struct strlist *
1316 msort(struct strlist *list, int len)
1317 {
1318         struct strlist *p, *q = NULL;
1319         struct strlist **lpp;
1320         int half;
1321         int n;
1322
1323         if (len <= 1)
1324                 return list;
1325         half = len >> 1;
1326         p = list;
1327         for (n = half ; --n >= 0 ; ) {
1328                 q = p;
1329                 p = p->next;
1330         }
1331         q->next = NULL;                 /* terminate first half of list */
1332         q = msort(list, half);          /* sort first half of list */
1333         p = msort(p, len - half);               /* sort second half */
1334         lpp = &list;
1335         for (;;) {
1336                 if (strcmp(p->text, q->text) < 0) {
1337                         *lpp = p;
1338                         lpp = &p->next;
1339                         if ((p = *lpp) == NULL) {
1340                                 *lpp = q;
1341                                 break;
1342                         }
1343                 } else {
1344                         *lpp = q;
1345                         lpp = &q->next;
1346                         if ((q = *lpp) == NULL) {
1347                                 *lpp = p;
1348                                 break;
1349                         }
1350                 }
1351         }
1352         return list;
1353 }
1354
1355
1356
1357 /*
1358  * Returns true if the pattern matches the string.
1359  */
1360
1361 int
1362 patmatch(const char *pattern, const char *string, int squoted)
1363 {
1364 #ifdef notdef
1365         if (pattern[0] == '!' && pattern[1] == '!')
1366                 return 1 - pmatch(pattern + 2, string);
1367         else
1368 #endif
1369                 return pmatch(pattern, string, squoted);
1370 }
1371
1372
1373 static int
1374 pmatch(const char *pattern, const char *string, int squoted)
1375 {
1376         const char *p, *q;
1377         char c;
1378
1379         p = pattern;
1380         q = string;
1381         for (;;) {
1382                 switch (c = *p++) {
1383                 case '\0':
1384                         goto breakloop;
1385                 case CTLESC:
1386                         if (squoted && *q == CTLESC)
1387                                 q++;
1388                         if (*q++ != *p++)
1389                                 return 0;
1390                         break;
1391                 case CTLQUOTEMARK:
1392                         continue;
1393                 case '?':
1394                         if (squoted && *q == CTLESC)
1395                                 q++;
1396                         if (*q++ == '\0')
1397                                 return 0;
1398                         break;
1399                 case '*':
1400                         c = *p;
1401                         while (c == CTLQUOTEMARK || c == '*')
1402                                 c = *++p;
1403                         if (c != CTLESC &&  c != CTLQUOTEMARK &&
1404                             c != '?' && c != '*' && c != '[') {
1405                                 while (*q != c) {
1406                                         if (squoted && *q == CTLESC &&
1407                                             q[1] == c)
1408                                                 break;
1409                                         if (*q == '\0')
1410                                                 return 0;
1411                                         if (squoted && *q == CTLESC)
1412                                                 q++;
1413                                         q++;
1414                                 }
1415                         }
1416                         do {
1417                                 if (pmatch(p, q, squoted))
1418                                         return 1;
1419                                 if (squoted && *q == CTLESC)
1420                                         q++;
1421                         } while (*q++ != '\0');
1422                         return 0;
1423                 case '[': {
1424                         const char *endp;
1425                         int invert, found;
1426                         char chr;
1427
1428                         endp = p;
1429                         if (*endp == '!' || *endp == '^')
1430                                 endp++;
1431                         for (;;) {
1432                                 while (*endp == CTLQUOTEMARK)
1433                                         endp++;
1434                                 if (*endp == '\0')
1435                                         goto dft;               /* no matching ] */
1436                                 if (*endp == CTLESC)
1437                                         endp++;
1438                                 if (*++endp == ']')
1439                                         break;
1440                         }
1441                         invert = 0;
1442                         if (*p == '!' || *p == '^') {
1443                                 invert++;
1444                                 p++;
1445                         }
1446                         found = 0;
1447                         chr = *q++;
1448                         if (squoted && chr == CTLESC)
1449                                 chr = *q++;
1450                         if (chr == '\0')
1451                                 return 0;
1452                         c = *p++;
1453                         do {
1454                                 if (c == CTLQUOTEMARK)
1455                                         continue;
1456                                 if (c == CTLESC)
1457                                         c = *p++;
1458                                 if (*p == '-' && p[1] != ']') {
1459                                         p++;
1460                                         while (*p == CTLQUOTEMARK)
1461                                                 p++;
1462                                         if (*p == CTLESC)
1463                                                 p++;
1464                                         if (   collate_range_cmp(chr, c) >= 0
1465                                             && collate_range_cmp(chr, *p) <= 0
1466                                            )
1467                                                 found = 1;
1468                                         p++;
1469                                 } else {
1470                                         if (chr == c)
1471                                                 found = 1;
1472                                 }
1473                         } while ((c = *p++) != ']');
1474                         if (found == invert)
1475                                 return 0;
1476                         break;
1477                 }
1478 dft:            default:
1479                         if (squoted && *q == CTLESC)
1480                                 q++;
1481                         if (*q++ != c)
1482                                 return 0;
1483                         break;
1484                 }
1485         }
1486 breakloop:
1487         if (*q != '\0')
1488                 return 0;
1489         return 1;
1490 }
1491
1492
1493
1494 /*
1495  * Remove any CTLESC and CTLQUOTEMARK characters from a string.
1496  */
1497
1498 void
1499 rmescapes(char *str)
1500 {
1501         char *p, *q;
1502
1503         p = str;
1504         while (*p != CTLESC && *p != CTLQUOTEMARK) {
1505                 if (*p++ == '\0')
1506                         return;
1507         }
1508         q = p;
1509         while (*p) {
1510                 if (*p == CTLQUOTEMARK) {
1511                         p++;
1512                         continue;
1513                 }
1514                 if (*p == CTLESC)
1515                         p++;
1516                 *q++ = *p++;
1517         }
1518         *q = '\0';
1519 }
1520
1521
1522
1523 /*
1524  * See if a pattern matches in a case statement.
1525  */
1526
1527 int
1528 casematch(union node *pattern, const char *val)
1529 {
1530         struct stackmark smark;
1531         int result;
1532         char *p;
1533
1534         setstackmark(&smark);
1535         argbackq = pattern->narg.backquote;
1536         STARTSTACKSTR(expdest);
1537         ifslastp = NULL;
1538         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1539         STPUTC('\0', expdest);
1540         p = grabstackstr(expdest);
1541         result = patmatch(p, val, 0);
1542         popstackmark(&smark);
1543         return result;
1544 }
1545
1546 /*
1547  * Our own itoa().
1548  */
1549
1550 static char *
1551 cvtnum(int num, char *buf)
1552 {
1553         char temp[32];
1554         int neg = num < 0;
1555         char *p = temp + 31;
1556
1557         temp[31] = '\0';
1558
1559         do {
1560                 *--p = num % 10 + '0';
1561         } while ((num /= 10) != 0);
1562
1563         if (neg)
1564                 *--p = '-';
1565
1566         while (*p)
1567                 STPUTC(*p++, buf);
1568         return buf;
1569 }
1570
1571 /*
1572  * Do most of the work for wordexp(3).
1573  */
1574
1575 int
1576 wordexpcmd(int argc, char **argv)
1577 {
1578         size_t len;
1579         int i;
1580
1581         out1fmt("%08x", argc - 1);
1582         for (i = 1, len = 0; i < argc; i++)
1583                 len += strlen(argv[i]);
1584         out1fmt("%08x", (int)len);
1585         for (i = 1; i < argc; i++) {
1586                 out1str(argv[i]);
1587                 out1c('\0');
1588         }
1589         return (0);
1590 }