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