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