b34f0583f0d38222b1f3afca13aec5f730770aba
[oweals/busybox.git] / shell / ash.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * ash shell port for busybox
4  *
5  * Copyright (c) 1989, 1991, 1993, 1994
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9  * was re-ported from NetBSD and debianized.
10  *
11  *
12  * This code is derived from software contributed to Berkeley by
13  * Kenneth Almquist.
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28  *
29  * Original BSD copyright notice is retained at the end of this file.
30  */
31
32 /*
33  * rewrite arith.y to micro stack based cryptic algorithm by
34  * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
35  *
36  * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2003 to be
37  * used in busybox and size optimizations,
38  * support locale, rewrited arith (see notes to this)
39  *
40  */
41
42
43 /*
44  * The follow should be set to reflect the type of system you have:
45  *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
46  *      define SYSV if you are running under System V.
47  *      define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
48  *      define DEBUG=2 to compile in and turn on debugging.
49  *
50  * When debugging is on, debugging info will be written to ./trace and
51  * a quit signal will generate a core dump.
52  */
53
54
55
56 #define IFS_BROKEN
57
58 #define PROFILE 0
59
60 #ifdef DEBUG
61 #define _GNU_SOURCE
62 #endif
63
64 #include <sys/types.h>
65 #include <sys/cdefs.h>
66 #include <sys/ioctl.h>
67 #include <sys/param.h>
68 #include <sys/resource.h>
69 #include <sys/stat.h>
70 #include <sys/time.h>
71 #include <sys/wait.h>
72
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <unistd.h>
77
78 #include <stdarg.h>
79 #include <stddef.h>
80 #include <assert.h>
81 #include <ctype.h>
82 #include <dirent.h>
83 #include <errno.h>
84 #include <fcntl.h>
85 #include <limits.h>
86 #include <paths.h>
87 #include <setjmp.h>
88 #include <signal.h>
89 #include <stdint.h>
90 #include <sysexits.h>
91
92 #include <fnmatch.h>
93
94
95 #include "busybox.h"
96 #include "pwd_.h"
97
98 #ifdef CONFIG_ASH_JOB_CONTROL
99 #define JOBS 1
100 #else
101 #undef JOBS
102 #endif
103
104 #if JOBS
105 #include <termios.h>
106 #endif
107
108 #include "cmdedit.h"
109
110 #ifdef __GLIBC__
111 /* glibc sucks */
112 static int *dash_errno;
113 #undef errno
114 #define errno (*dash_errno)
115 #endif
116
117 #if defined(__uClinux__)
118 #error "Do not even bother, ash will not run on uClinux"
119 #endif
120
121 #ifdef DEBUG
122 #define _DIAGASSERT(assert_expr) assert(assert_expr)
123 #else
124 #define _DIAGASSERT(assert_expr)
125 #endif
126
127
128 #ifdef CONFIG_ASH_ALIAS
129 /*      $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $       */
130
131 #define ALIASINUSE      1
132 #define ALIASDEAD       2
133
134 struct alias {
135         struct alias *next;
136         char *name;
137         char *val;
138         int flag;
139 };
140
141 static struct alias *lookupalias(const char *, int);
142 static int aliascmd(int, char **);
143 static int unaliascmd(int, char **);
144 static void rmaliases(void);
145 static int unalias(const char *);
146 static void printalias(const struct alias *);
147 #endif
148
149 /*      $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $  */
150
151
152 static void    setpwd(const char *, int);
153
154 /*      $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $      */
155
156
157 /*
158  * Types of operations (passed to the errmsg routine).
159  */
160
161
162 static const char not_found_msg[] = "%s: not found";
163
164
165 #define E_OPEN  "No such file"          /* opening a file */
166 #define E_CREAT "Directory nonexistent" /* creating a file */
167 #define E_EXEC  not_found_msg+4         /* executing a program */
168
169 /*
170  * We enclose jmp_buf in a structure so that we can declare pointers to
171  * jump locations.  The global variable handler contains the location to
172  * jump to when an exception occurs, and the global variable exception
173  * contains a code identifying the exeception.  To implement nested
174  * exception handlers, the user should save the value of handler on entry
175  * to an inner scope, set handler to point to a jmploc structure for the
176  * inner scope, and restore handler on exit from the scope.
177  */
178
179 struct jmploc {
180         jmp_buf loc;
181 };
182
183 static struct jmploc *handler;
184 static int exception;
185 static volatile int suppressint;
186 static volatile sig_atomic_t intpending;
187
188 static int exerrno;            /* Last exec error, error for EXEXEC */
189
190 /* exceptions */
191 #define EXINT 0         /* SIGINT received */
192 #define EXERROR 1       /* a generic error */
193 #define EXSHELLPROC 2   /* execute a shell procedure */
194 #define EXEXEC 3        /* command execution failed */
195 #define EXEXIT 4        /* exit the shell */
196 #define EXSIG 5         /* trapped signal in wait(1) */
197
198
199 /* do we generate EXSIG events */
200 static int exsig;
201 /* last pending signal */
202 static volatile sig_atomic_t pendingsigs;
203
204 /*
205  * These macros allow the user to suspend the handling of interrupt signals
206  * over a period of time.  This is similar to SIGHOLD to or sigblock, but
207  * much more efficient and portable.  (But hacking the kernel is so much
208  * more fun than worrying about efficiency and portability. :-))
209  */
210
211 #define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
212 #define INTOFF \
213         ({ \
214                 suppressint++; \
215                 barrier(); \
216                 0; \
217         })
218 #define SAVEINT(v) ((v) = suppressint)
219 #define RESTOREINT(v) \
220         ({ \
221                 barrier(); \
222                 if ((suppressint = (v)) == 0 && intpending) onint(); \
223                 0; \
224         })
225 #define EXSIGON() \
226         ({ \
227                 exsig++; \
228                 barrier(); \
229                 if (pendingsigs) \
230                         exraise(EXSIG); \
231                 0; \
232         })
233 /* EXSIG is turned off by evalbltin(). */
234
235
236 static void exraise(int) __attribute__((__noreturn__));
237 static void onint(void) __attribute__((__noreturn__));
238
239 static void error(const char *, ...) __attribute__((__noreturn__));
240 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
241
242 static void sh_warnx(const char *, ...);
243
244 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
245 static void
246 inton(void) {
247         if (--suppressint == 0 && intpending) {
248                 onint();
249         }
250 }
251 #define INTON inton()
252 static void forceinton(void)
253 {
254         suppressint = 0;
255         if (intpending)
256                 onint();
257 }
258 #define FORCEINTON forceinton()
259 #else
260 #define INTON \
261         ({ \
262                 barrier(); \
263                 if (--suppressint == 0 && intpending) onint(); \
264                 0; \
265         })
266 #define FORCEINTON \
267         ({ \
268                 barrier(); \
269                 suppressint = 0; \
270                 if (intpending) onint(); \
271                 0; \
272         })
273 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
274
275 /*
276  * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
277  * so we use _setjmp instead.
278  */
279
280 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
281 #define setjmp(jmploc)  _setjmp(jmploc)
282 #define longjmp(jmploc, val)    _longjmp(jmploc, val)
283 #endif
284
285 /*      $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $     */
286
287 struct strlist {
288         struct strlist *next;
289         char *text;
290 };
291
292
293 struct arglist {
294         struct strlist *list;
295         struct strlist **lastp;
296 };
297
298 /*
299  * expandarg() flags
300  */
301 #define EXP_FULL        0x1     /* perform word splitting & file globbing */
302 #define EXP_TILDE       0x2     /* do normal tilde expansion */
303 #define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
304 #define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
305 #define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
306 #define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
307 #define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
308 #define EXP_WORD        0x80    /* expand word in parameter expansion */
309 #define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
310
311
312 union node;
313 static void expandarg(union node *, struct arglist *, int);
314 #define rmescapes(p) _rmescapes((p), 0)
315 static char *_rmescapes(char *, int);
316 static int casematch(union node *, char *);
317
318 #ifdef CONFIG_ASH_MATH_SUPPORT
319 static void expari(int);
320 #endif
321
322 /*      $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $       */
323
324 static char *commandname;              /* currently executing command */
325 static struct strlist *cmdenviron;     /* environment for builtin command */
326 static int exitstatus;                 /* exit status of last command */
327 static int back_exitstatus;            /* exit status of backquoted command */
328
329
330 struct backcmd {                /* result of evalbackcmd */
331         int fd;                 /* file descriptor to read from */
332         char *buf;              /* buffer */
333         int nleft;              /* number of chars in buffer */
334         struct job *jp;         /* job structure for command */
335 };
336
337 /*
338  * This file was generated by the mknodes program.
339  */
340
341 #define NCMD 0
342 #define NPIPE 1
343 #define NREDIR 2
344 #define NBACKGND 3
345 #define NSUBSHELL 4
346 #define NAND 5
347 #define NOR 6
348 #define NSEMI 7
349 #define NIF 8
350 #define NWHILE 9
351 #define NUNTIL 10
352 #define NFOR 11
353 #define NCASE 12
354 #define NCLIST 13
355 #define NDEFUN 14
356 #define NARG 15
357 #define NTO 16
358 #define NCLOBBER 17
359 #define NFROM 18
360 #define NFROMTO 19
361 #define NAPPEND 20
362 #define NTOFD 21
363 #define NFROMFD 22
364 #define NHERE 23
365 #define NXHERE 24
366 #define NNOT 25
367
368
369
370 struct ncmd {
371       int type;
372       union node *assign;
373       union node *args;
374       union node *redirect;
375 };
376
377
378 struct npipe {
379       int type;
380       int backgnd;
381       struct nodelist *cmdlist;
382 };
383
384
385 struct nredir {
386       int type;
387       union node *n;
388       union node *redirect;
389 };
390
391
392 struct nbinary {
393       int type;
394       union node *ch1;
395       union node *ch2;
396 };
397
398
399 struct nif {
400       int type;
401       union node *test;
402       union node *ifpart;
403       union node *elsepart;
404 };
405
406
407 struct nfor {
408       int type;
409       union node *args;
410       union node *body;
411       char *var;
412 };
413
414
415 struct ncase {
416       int type;
417       union node *expr;
418       union node *cases;
419 };
420
421
422 struct nclist {
423       int type;
424       union node *next;
425       union node *pattern;
426       union node *body;
427 };
428
429
430 struct narg {
431       int type;
432       union node *next;
433       char *text;
434       struct nodelist *backquote;
435 };
436
437
438 struct nfile {
439       int type;
440       union node *next;
441       int fd;
442       union node *fname;
443       char *expfname;
444 };
445
446
447 struct ndup {
448       int type;
449       union node *next;
450       int fd;
451       int dupfd;
452       union node *vname;
453 };
454
455
456 struct nhere {
457       int type;
458       union node *next;
459       int fd;
460       union node *doc;
461 };
462
463
464 struct nnot {
465       int type;
466       union node *com;
467 };
468
469
470 union node {
471       int type;
472       struct ncmd ncmd;
473       struct npipe npipe;
474       struct nredir nredir;
475       struct nbinary nbinary;
476       struct nif nif;
477       struct nfor nfor;
478       struct ncase ncase;
479       struct nclist nclist;
480       struct narg narg;
481       struct nfile nfile;
482       struct ndup ndup;
483       struct nhere nhere;
484       struct nnot nnot;
485 };
486
487
488 struct nodelist {
489         struct nodelist *next;
490         union node *n;
491 };
492
493
494 struct funcnode {
495         int count;
496         union node n;
497 };
498
499
500 static void freefunc(struct funcnode *);
501 /*      $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $     */
502
503 /* control characters in argument strings */
504 #define CTL_FIRST '\201'        /* first 'special' character */
505 #define CTLESC '\201'           /* escape next character */
506 #define CTLVAR '\202'           /* variable defn */
507 #define CTLENDVAR '\203'
508 #define CTLBACKQ '\204'
509 #define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
510 /*      CTLBACKQ | CTLQUOTE == '\205' */
511 #define CTLARI  '\206'          /* arithmetic expression */
512 #define CTLENDARI '\207'
513 #define CTLQUOTEMARK '\210'
514 #define CTL_LAST '\210'         /* last 'special' character */
515
516 /* variable substitution byte (follows CTLVAR) */
517 #define VSTYPE  0x0f            /* type of variable substitution */
518 #define VSNUL   0x10            /* colon--treat the empty string as unset */
519 #define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
520
521 /* values of VSTYPE field */
522 #define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
523 #define VSMINUS         0x2             /* ${var-text} */
524 #define VSPLUS          0x3             /* ${var+text} */
525 #define VSQUESTION      0x4             /* ${var?message} */
526 #define VSASSIGN        0x5             /* ${var=text} */
527 #define VSTRIMRIGHT     0x6             /* ${var%pattern} */
528 #define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
529 #define VSTRIMLEFT      0x8             /* ${var#pattern} */
530 #define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
531 #define VSLENGTH        0xa             /* ${#var} */
532
533 /* values of checkkwd variable */
534 #define CHKALIAS        0x1
535 #define CHKKWD          0x2
536 #define CHKNL           0x4
537
538 #define IBUFSIZ (BUFSIZ + 1)
539
540 /*
541  * NEOF is returned by parsecmd when it encounters an end of file.  It
542  * must be distinct from NULL, so we use the address of a variable that
543  * happens to be handy.
544  */
545 static int plinno = 1;                  /* input line number */
546
547 /* number of characters left in input buffer */
548 static int parsenleft;                  /* copy of parsefile->nleft */
549 static int parselleft;                  /* copy of parsefile->lleft */
550
551 /* next character in input buffer */
552 static char *parsenextc;                /* copy of parsefile->nextc */
553
554 struct strpush {
555         struct strpush *prev;   /* preceding string on stack */
556         char *prevstring;
557         int prevnleft;
558 #ifdef CONFIG_ASH_ALIAS
559         struct alias *ap;       /* if push was associated with an alias */
560 #endif
561         char *string;           /* remember the string since it may change */
562 };
563
564 struct parsefile {
565         struct parsefile *prev; /* preceding file on stack */
566         int linno;              /* current line */
567         int fd;                 /* file descriptor (or -1 if string) */
568         int nleft;              /* number of chars left in this line */
569         int lleft;              /* number of chars left in this buffer */
570         char *nextc;            /* next char in buffer */
571         char *buf;              /* input buffer */
572         struct strpush *strpush; /* for pushing strings at this level */
573         struct strpush basestrpush; /* so pushing one is fast */
574 };
575
576 static struct parsefile basepf;         /* top level input file */
577 static char basebuf[IBUFSIZ];           /* buffer for top level input file */
578 static struct parsefile *parsefile = &basepf;  /* current input file */
579
580
581 static int tokpushback;                 /* last token pushed back */
582 #define NEOF ((union node *)&tokpushback)
583 static int parsebackquote;             /* nonzero if we are inside backquotes */
584 static int doprompt;                   /* if set, prompt the user */
585 static int needprompt;                 /* true if interactive and at start of line */
586 static int lasttoken;                  /* last token read */
587 static char *wordtext;                 /* text of last word returned by readtoken */
588 static int checkkwd;
589 static struct nodelist *backquotelist;
590 static union node *redirnode;
591 static struct heredoc *heredoc;
592 static int quoteflag;                  /* set if (part of) last token was quoted */
593 static int startlinno;                 /* line # where last token started */
594
595 static union node *parsecmd(int);
596 static void fixredir(union node *, const char *, int);
597 static const char *const *findkwd(const char *);
598 static char *endofname(const char *);
599
600 /*      $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $   */
601
602 typedef void *pointer;
603
604 static char nullstr[1];                /* zero length string */
605 static const char spcstr[] = " ";
606 static const char snlfmt[] = "%s\n";
607 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
608 static const char illnum[] = "Illegal number: %s";
609 static const char homestr[] = "HOME";
610
611 #ifdef DEBUG
612 #define TRACE(param)    trace param
613 #define TRACEV(param)   tracev param
614 #else
615 #define TRACE(param)
616 #define TRACEV(param)
617 #endif
618
619 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
620 #define __builtin_expect(x, expected_value) (x)
621 #endif
622
623 #define likely(x)       __builtin_expect((x),1)
624
625
626 #define TEOF 0
627 #define TNL 1
628 #define TREDIR 2
629 #define TWORD 3
630 #define TSEMI 4
631 #define TBACKGND 5
632 #define TAND 6
633 #define TOR 7
634 #define TPIPE 8
635 #define TLP 9
636 #define TRP 10
637 #define TENDCASE 11
638 #define TENDBQUOTE 12
639 #define TNOT 13
640 #define TCASE 14
641 #define TDO 15
642 #define TDONE 16
643 #define TELIF 17
644 #define TELSE 18
645 #define TESAC 19
646 #define TFI 20
647 #define TFOR 21
648 #define TIF 22
649 #define TIN 23
650 #define TTHEN 24
651 #define TUNTIL 25
652 #define TWHILE 26
653 #define TBEGIN 27
654 #define TEND 28
655
656 /* first char is indicating which tokens mark the end of a list */
657 static const char *const tokname_array[] = {
658         "\1end of file",
659         "\0newline",
660         "\0redirection",
661         "\0word",
662         "\0;",
663         "\0&",
664         "\0&&",
665         "\0||",
666         "\0|",
667         "\0(",
668         "\1)",
669         "\1;;",
670         "\1`",
671 #define KWDOFFSET 13
672         /* the following are keywords */
673         "\0!",
674         "\0case",
675         "\1do",
676         "\1done",
677         "\1elif",
678         "\1else",
679         "\1esac",
680         "\1fi",
681         "\0for",
682         "\0if",
683         "\0in",
684         "\1then",
685         "\0until",
686         "\0while",
687         "\0{",
688         "\1}",
689 };
690
691 static const char *tokname(int tok)
692 {
693         static char buf[16];
694
695         if (tok >= TSEMI)
696                 buf[0] = '"';
697         sprintf(buf + (tok >= TSEMI), "%s%c",
698                         tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
699         return buf;
700 }
701
702 /*      $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $    */
703
704 /*
705  * Most machines require the value returned from malloc to be aligned
706  * in some way.  The following macro will get this right on many machines.
707  */
708
709 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
710 /*
711  * It appears that grabstackstr() will barf with such alignments
712  * because stalloc() will return a string allocated in a new stackblock.
713  */
714 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
715
716 /*
717  * This file was generated by the mksyntax program.
718  */
719
720
721 /* Syntax classes */
722 #define CWORD 0                 /* character is nothing special */
723 #define CNL 1                   /* newline character */
724 #define CBACK 2                 /* a backslash character */
725 #define CSQUOTE 3               /* single quote */
726 #define CDQUOTE 4               /* double quote */
727 #define CENDQUOTE 5             /* a terminating quote */
728 #define CBQUOTE 6               /* backwards single quote */
729 #define CVAR 7                  /* a dollar sign */
730 #define CENDVAR 8               /* a '}' character */
731 #define CLP 9                   /* a left paren in arithmetic */
732 #define CRP 10                  /* a right paren in arithmetic */
733 #define CENDFILE 11             /* end of file */
734 #define CCTL 12                 /* like CWORD, except it must be escaped */
735 #define CSPCL 13                /* these terminate a word */
736 #define CIGN 14                 /* character should be ignored */
737
738 #ifdef CONFIG_ASH_ALIAS
739 #define SYNBASE 130
740 #define PEOF -130
741 #define PEOA -129
742 #define PEOA_OR_PEOF PEOA
743 #else
744 #define SYNBASE 129
745 #define PEOF -129
746 #define PEOA_OR_PEOF PEOF
747 #endif
748
749 #define is_digit(c)     ((unsigned)((c) - '0') <= 9)
750 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
751 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
752
753 /*
754  * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
755  * (assuming ascii char codes, as the original implementation did)
756  */
757 #define is_special(c) \
758     ( (((unsigned int)c) - 33 < 32) \
759                          && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
760
761 #define digit_val(c)    ((c) - '0')
762
763 /*
764  * This file was generated by the mksyntax program.
765  */
766
767 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
768 #define USE_SIT_FUNCTION
769 #endif
770
771 /* number syntax index */
772 #define  BASESYNTAX  0  /* not in quotes */
773 #define  DQSYNTAX    1  /* in double quotes */
774 #define  SQSYNTAX    2  /* in single quotes */
775 #define  ARISYNTAX   3  /* in arithmetic */
776
777 #ifdef CONFIG_ASH_MATH_SUPPORT
778 static const char S_I_T[][4] = {
779 #ifdef CONFIG_ASH_ALIAS
780         {CSPCL, CIGN, CIGN, CIGN},              /* 0, PEOA */
781 #endif
782         {CSPCL, CWORD, CWORD, CWORD},           /* 1, ' ' */
783         {CNL, CNL, CNL, CNL},                   /* 2, \n */
784         {CWORD, CCTL, CCTL, CWORD},             /* 3, !*-/:=?[]~ */
785         {CDQUOTE, CENDQUOTE, CWORD, CWORD},     /* 4, '"' */
786         {CVAR, CVAR, CWORD, CVAR},              /* 5, $ */
787         {CSQUOTE, CWORD, CENDQUOTE, CWORD},     /* 6, "'" */
788         {CSPCL, CWORD, CWORD, CLP},             /* 7, ( */
789         {CSPCL, CWORD, CWORD, CRP},             /* 8, ) */
790         {CBACK, CBACK, CCTL, CBACK},            /* 9, \ */
791         {CBQUOTE, CBQUOTE, CWORD, CBQUOTE},     /* 10, ` */
792         {CENDVAR, CENDVAR, CWORD, CENDVAR},     /* 11, } */
793 #ifndef USE_SIT_FUNCTION
794         {CENDFILE, CENDFILE, CENDFILE, CENDFILE},       /* 12, PEOF */
795         {CWORD, CWORD, CWORD, CWORD},           /* 13, 0-9A-Za-z */
796         {CCTL, CCTL, CCTL, CCTL}                /* 14, CTLESC ... */
797 #endif
798 };
799 #else
800 static const char S_I_T[][3] = {
801 #ifdef CONFIG_ASH_ALIAS
802         {CSPCL, CIGN, CIGN},                    /* 0, PEOA */
803 #endif
804         {CSPCL, CWORD, CWORD},                  /* 1, ' ' */
805         {CNL, CNL, CNL},                        /* 2, \n */
806         {CWORD, CCTL, CCTL},                    /* 3, !*-/:=?[]~ */
807         {CDQUOTE, CENDQUOTE, CWORD},            /* 4, '"' */
808         {CVAR, CVAR, CWORD},                    /* 5, $ */
809         {CSQUOTE, CWORD, CENDQUOTE},            /* 6, "'" */
810         {CSPCL, CWORD, CWORD},                  /* 7, ( */
811         {CSPCL, CWORD, CWORD},                  /* 8, ) */
812         {CBACK, CBACK, CCTL},                   /* 9, \ */
813         {CBQUOTE, CBQUOTE, CWORD},              /* 10, ` */
814         {CENDVAR, CENDVAR, CWORD},              /* 11, } */
815 #ifndef USE_SIT_FUNCTION
816         {CENDFILE, CENDFILE, CENDFILE},         /* 12, PEOF */
817         {CWORD, CWORD, CWORD},                  /* 13, 0-9A-Za-z */
818         {CCTL, CCTL, CCTL}                      /* 14, CTLESC ... */
819 #endif
820 };
821 #endif /* CONFIG_ASH_MATH_SUPPORT */
822
823 #ifdef USE_SIT_FUNCTION
824
825 #define U_C(c) ((unsigned char)(c))
826
827 static int SIT(int c, int syntax)
828 {
829         static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
830 #ifdef CONFIG_ASH_ALIAS
831         static const char syntax_index_table[] = {
832                 1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
833                 7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
834                 3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
835                 11, 3                           /* "}~" */
836         };
837 #else
838         static const char syntax_index_table[] = {
839                 0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
840                 6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
841                 2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
842                 10, 2                           /* "}~" */
843         };
844 #endif
845         const char *s;
846         int indx;
847
848         if (c == PEOF)          /* 2^8+2 */
849                 return CENDFILE;
850 #ifdef CONFIG_ASH_ALIAS
851         if (c == PEOA)          /* 2^8+1 */
852                 indx = 0;
853         else
854 #endif
855                 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
856                         return CCTL;
857         else {
858                 s = strchr(spec_symbls, c);
859                 if (s == 0 || *s == 0)
860                         return CWORD;
861                 indx = syntax_index_table[(s - spec_symbls)];
862         }
863         return S_I_T[indx][syntax];
864 }
865
866 #else                                                   /* USE_SIT_FUNCTION */
867
868 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
869
870 #ifdef CONFIG_ASH_ALIAS
871 #define CSPCL_CIGN_CIGN_CIGN                           0
872 #define CSPCL_CWORD_CWORD_CWORD                        1
873 #define CNL_CNL_CNL_CNL                                2
874 #define CWORD_CCTL_CCTL_CWORD                          3
875 #define CDQUOTE_CENDQUOTE_CWORD_CWORD                  4
876 #define CVAR_CVAR_CWORD_CVAR                           5
877 #define CSQUOTE_CWORD_CENDQUOTE_CWORD                  6
878 #define CSPCL_CWORD_CWORD_CLP                          7
879 #define CSPCL_CWORD_CWORD_CRP                          8
880 #define CBACK_CBACK_CCTL_CBACK                         9
881 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                 10
882 #define CENDVAR_CENDVAR_CWORD_CENDVAR                 11
883 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE           12
884 #define CWORD_CWORD_CWORD_CWORD                       13
885 #define CCTL_CCTL_CCTL_CCTL                           14
886 #else
887 #define CSPCL_CWORD_CWORD_CWORD                        0
888 #define CNL_CNL_CNL_CNL                                1
889 #define CWORD_CCTL_CCTL_CWORD                          2
890 #define CDQUOTE_CENDQUOTE_CWORD_CWORD                  3
891 #define CVAR_CVAR_CWORD_CVAR                           4
892 #define CSQUOTE_CWORD_CENDQUOTE_CWORD                  5
893 #define CSPCL_CWORD_CWORD_CLP                          6
894 #define CSPCL_CWORD_CWORD_CRP                          7
895 #define CBACK_CBACK_CCTL_CBACK                         8
896 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                  9
897 #define CENDVAR_CENDVAR_CWORD_CENDVAR                 10
898 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE           11
899 #define CWORD_CWORD_CWORD_CWORD                       12
900 #define CCTL_CCTL_CCTL_CCTL                           13
901 #endif
902
903 static const char syntax_index_table[258] = {
904         /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
905         /*   0  PEOF */      CENDFILE_CENDFILE_CENDFILE_CENDFILE,
906 #ifdef CONFIG_ASH_ALIAS
907         /*   1  PEOA */      CSPCL_CIGN_CIGN_CIGN,
908 #endif
909         /*   2  -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
910         /*   3  -127 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
911         /*   4  -126 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
912         /*   5  -125 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
913         /*   6  -124 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
914         /*   7  -123 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
915         /*   8  -122 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
916         /*   9  -121 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
917         /*  10  -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
918         /*  11  -119      */ CWORD_CWORD_CWORD_CWORD,
919         /*  12  -118      */ CWORD_CWORD_CWORD_CWORD,
920         /*  13  -117      */ CWORD_CWORD_CWORD_CWORD,
921         /*  14  -116      */ CWORD_CWORD_CWORD_CWORD,
922         /*  15  -115      */ CWORD_CWORD_CWORD_CWORD,
923         /*  16  -114      */ CWORD_CWORD_CWORD_CWORD,
924         /*  17  -113      */ CWORD_CWORD_CWORD_CWORD,
925         /*  18  -112      */ CWORD_CWORD_CWORD_CWORD,
926         /*  19  -111      */ CWORD_CWORD_CWORD_CWORD,
927         /*  20  -110      */ CWORD_CWORD_CWORD_CWORD,
928         /*  21  -109      */ CWORD_CWORD_CWORD_CWORD,
929         /*  22  -108      */ CWORD_CWORD_CWORD_CWORD,
930         /*  23  -107      */ CWORD_CWORD_CWORD_CWORD,
931         /*  24  -106      */ CWORD_CWORD_CWORD_CWORD,
932         /*  25  -105      */ CWORD_CWORD_CWORD_CWORD,
933         /*  26  -104      */ CWORD_CWORD_CWORD_CWORD,
934         /*  27  -103      */ CWORD_CWORD_CWORD_CWORD,
935         /*  28  -102      */ CWORD_CWORD_CWORD_CWORD,
936         /*  29  -101      */ CWORD_CWORD_CWORD_CWORD,
937         /*  30  -100      */ CWORD_CWORD_CWORD_CWORD,
938         /*  31   -99      */ CWORD_CWORD_CWORD_CWORD,
939         /*  32   -98      */ CWORD_CWORD_CWORD_CWORD,
940         /*  33   -97      */ CWORD_CWORD_CWORD_CWORD,
941         /*  34   -96      */ CWORD_CWORD_CWORD_CWORD,
942         /*  35   -95      */ CWORD_CWORD_CWORD_CWORD,
943         /*  36   -94      */ CWORD_CWORD_CWORD_CWORD,
944         /*  37   -93      */ CWORD_CWORD_CWORD_CWORD,
945         /*  38   -92      */ CWORD_CWORD_CWORD_CWORD,
946         /*  39   -91      */ CWORD_CWORD_CWORD_CWORD,
947         /*  40   -90      */ CWORD_CWORD_CWORD_CWORD,
948         /*  41   -89      */ CWORD_CWORD_CWORD_CWORD,
949         /*  42   -88      */ CWORD_CWORD_CWORD_CWORD,
950         /*  43   -87      */ CWORD_CWORD_CWORD_CWORD,
951         /*  44   -86      */ CWORD_CWORD_CWORD_CWORD,
952         /*  45   -85      */ CWORD_CWORD_CWORD_CWORD,
953         /*  46   -84      */ CWORD_CWORD_CWORD_CWORD,
954         /*  47   -83      */ CWORD_CWORD_CWORD_CWORD,
955         /*  48   -82      */ CWORD_CWORD_CWORD_CWORD,
956         /*  49   -81      */ CWORD_CWORD_CWORD_CWORD,
957         /*  50   -80      */ CWORD_CWORD_CWORD_CWORD,
958         /*  51   -79      */ CWORD_CWORD_CWORD_CWORD,
959         /*  52   -78      */ CWORD_CWORD_CWORD_CWORD,
960         /*  53   -77      */ CWORD_CWORD_CWORD_CWORD,
961         /*  54   -76      */ CWORD_CWORD_CWORD_CWORD,
962         /*  55   -75      */ CWORD_CWORD_CWORD_CWORD,
963         /*  56   -74      */ CWORD_CWORD_CWORD_CWORD,
964         /*  57   -73      */ CWORD_CWORD_CWORD_CWORD,
965         /*  58   -72      */ CWORD_CWORD_CWORD_CWORD,
966         /*  59   -71      */ CWORD_CWORD_CWORD_CWORD,
967         /*  60   -70      */ CWORD_CWORD_CWORD_CWORD,
968         /*  61   -69      */ CWORD_CWORD_CWORD_CWORD,
969         /*  62   -68      */ CWORD_CWORD_CWORD_CWORD,
970         /*  63   -67      */ CWORD_CWORD_CWORD_CWORD,
971         /*  64   -66      */ CWORD_CWORD_CWORD_CWORD,
972         /*  65   -65      */ CWORD_CWORD_CWORD_CWORD,
973         /*  66   -64      */ CWORD_CWORD_CWORD_CWORD,
974         /*  67   -63      */ CWORD_CWORD_CWORD_CWORD,
975         /*  68   -62      */ CWORD_CWORD_CWORD_CWORD,
976         /*  69   -61      */ CWORD_CWORD_CWORD_CWORD,
977         /*  70   -60      */ CWORD_CWORD_CWORD_CWORD,
978         /*  71   -59      */ CWORD_CWORD_CWORD_CWORD,
979         /*  72   -58      */ CWORD_CWORD_CWORD_CWORD,
980         /*  73   -57      */ CWORD_CWORD_CWORD_CWORD,
981         /*  74   -56      */ CWORD_CWORD_CWORD_CWORD,
982         /*  75   -55      */ CWORD_CWORD_CWORD_CWORD,
983         /*  76   -54      */ CWORD_CWORD_CWORD_CWORD,
984         /*  77   -53      */ CWORD_CWORD_CWORD_CWORD,
985         /*  78   -52      */ CWORD_CWORD_CWORD_CWORD,
986         /*  79   -51      */ CWORD_CWORD_CWORD_CWORD,
987         /*  80   -50      */ CWORD_CWORD_CWORD_CWORD,
988         /*  81   -49      */ CWORD_CWORD_CWORD_CWORD,
989         /*  82   -48      */ CWORD_CWORD_CWORD_CWORD,
990         /*  83   -47      */ CWORD_CWORD_CWORD_CWORD,
991         /*  84   -46      */ CWORD_CWORD_CWORD_CWORD,
992         /*  85   -45      */ CWORD_CWORD_CWORD_CWORD,
993         /*  86   -44      */ CWORD_CWORD_CWORD_CWORD,
994         /*  87   -43      */ CWORD_CWORD_CWORD_CWORD,
995         /*  88   -42      */ CWORD_CWORD_CWORD_CWORD,
996         /*  89   -41      */ CWORD_CWORD_CWORD_CWORD,
997         /*  90   -40      */ CWORD_CWORD_CWORD_CWORD,
998         /*  91   -39      */ CWORD_CWORD_CWORD_CWORD,
999         /*  92   -38      */ CWORD_CWORD_CWORD_CWORD,
1000         /*  93   -37      */ CWORD_CWORD_CWORD_CWORD,
1001         /*  94   -36      */ CWORD_CWORD_CWORD_CWORD,
1002         /*  95   -35      */ CWORD_CWORD_CWORD_CWORD,
1003         /*  96   -34      */ CWORD_CWORD_CWORD_CWORD,
1004         /*  97   -33      */ CWORD_CWORD_CWORD_CWORD,
1005         /*  98   -32      */ CWORD_CWORD_CWORD_CWORD,
1006         /*  99   -31      */ CWORD_CWORD_CWORD_CWORD,
1007         /* 100   -30      */ CWORD_CWORD_CWORD_CWORD,
1008         /* 101   -29      */ CWORD_CWORD_CWORD_CWORD,
1009         /* 102   -28      */ CWORD_CWORD_CWORD_CWORD,
1010         /* 103   -27      */ CWORD_CWORD_CWORD_CWORD,
1011         /* 104   -26      */ CWORD_CWORD_CWORD_CWORD,
1012         /* 105   -25      */ CWORD_CWORD_CWORD_CWORD,
1013         /* 106   -24      */ CWORD_CWORD_CWORD_CWORD,
1014         /* 107   -23      */ CWORD_CWORD_CWORD_CWORD,
1015         /* 108   -22      */ CWORD_CWORD_CWORD_CWORD,
1016         /* 109   -21      */ CWORD_CWORD_CWORD_CWORD,
1017         /* 110   -20      */ CWORD_CWORD_CWORD_CWORD,
1018         /* 111   -19      */ CWORD_CWORD_CWORD_CWORD,
1019         /* 112   -18      */ CWORD_CWORD_CWORD_CWORD,
1020         /* 113   -17      */ CWORD_CWORD_CWORD_CWORD,
1021         /* 114   -16      */ CWORD_CWORD_CWORD_CWORD,
1022         /* 115   -15      */ CWORD_CWORD_CWORD_CWORD,
1023         /* 116   -14      */ CWORD_CWORD_CWORD_CWORD,
1024         /* 117   -13      */ CWORD_CWORD_CWORD_CWORD,
1025         /* 118   -12      */ CWORD_CWORD_CWORD_CWORD,
1026         /* 119   -11      */ CWORD_CWORD_CWORD_CWORD,
1027         /* 120   -10      */ CWORD_CWORD_CWORD_CWORD,
1028         /* 121    -9      */ CWORD_CWORD_CWORD_CWORD,
1029         /* 122    -8      */ CWORD_CWORD_CWORD_CWORD,
1030         /* 123    -7      */ CWORD_CWORD_CWORD_CWORD,
1031         /* 124    -6      */ CWORD_CWORD_CWORD_CWORD,
1032         /* 125    -5      */ CWORD_CWORD_CWORD_CWORD,
1033         /* 126    -4      */ CWORD_CWORD_CWORD_CWORD,
1034         /* 127    -3      */ CWORD_CWORD_CWORD_CWORD,
1035         /* 128    -2      */ CWORD_CWORD_CWORD_CWORD,
1036         /* 129    -1      */ CWORD_CWORD_CWORD_CWORD,
1037         /* 130     0      */ CWORD_CWORD_CWORD_CWORD,
1038         /* 131     1      */ CWORD_CWORD_CWORD_CWORD,
1039         /* 132     2      */ CWORD_CWORD_CWORD_CWORD,
1040         /* 133     3      */ CWORD_CWORD_CWORD_CWORD,
1041         /* 134     4      */ CWORD_CWORD_CWORD_CWORD,
1042         /* 135     5      */ CWORD_CWORD_CWORD_CWORD,
1043         /* 136     6      */ CWORD_CWORD_CWORD_CWORD,
1044         /* 137     7      */ CWORD_CWORD_CWORD_CWORD,
1045         /* 138     8      */ CWORD_CWORD_CWORD_CWORD,
1046         /* 139     9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1047         /* 140    10 "\n" */ CNL_CNL_CNL_CNL,
1048         /* 141    11      */ CWORD_CWORD_CWORD_CWORD,
1049         /* 142    12      */ CWORD_CWORD_CWORD_CWORD,
1050         /* 143    13      */ CWORD_CWORD_CWORD_CWORD,
1051         /* 144    14      */ CWORD_CWORD_CWORD_CWORD,
1052         /* 145    15      */ CWORD_CWORD_CWORD_CWORD,
1053         /* 146    16      */ CWORD_CWORD_CWORD_CWORD,
1054         /* 147    17      */ CWORD_CWORD_CWORD_CWORD,
1055         /* 148    18      */ CWORD_CWORD_CWORD_CWORD,
1056         /* 149    19      */ CWORD_CWORD_CWORD_CWORD,
1057         /* 150    20      */ CWORD_CWORD_CWORD_CWORD,
1058         /* 151    21      */ CWORD_CWORD_CWORD_CWORD,
1059         /* 152    22      */ CWORD_CWORD_CWORD_CWORD,
1060         /* 153    23      */ CWORD_CWORD_CWORD_CWORD,
1061         /* 154    24      */ CWORD_CWORD_CWORD_CWORD,
1062         /* 155    25      */ CWORD_CWORD_CWORD_CWORD,
1063         /* 156    26      */ CWORD_CWORD_CWORD_CWORD,
1064         /* 157    27      */ CWORD_CWORD_CWORD_CWORD,
1065         /* 158    28      */ CWORD_CWORD_CWORD_CWORD,
1066         /* 159    29      */ CWORD_CWORD_CWORD_CWORD,
1067         /* 160    30      */ CWORD_CWORD_CWORD_CWORD,
1068         /* 161    31      */ CWORD_CWORD_CWORD_CWORD,
1069         /* 162    32  " " */ CSPCL_CWORD_CWORD_CWORD,
1070         /* 163    33  "!" */ CWORD_CCTL_CCTL_CWORD,
1071         /* 164    34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1072         /* 165    35  "#" */ CWORD_CWORD_CWORD_CWORD,
1073         /* 166    36  "$" */ CVAR_CVAR_CWORD_CVAR,
1074         /* 167    37  "%" */ CWORD_CWORD_CWORD_CWORD,
1075         /* 168    38  "&" */ CSPCL_CWORD_CWORD_CWORD,
1076         /* 169    39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1077         /* 170    40  "(" */ CSPCL_CWORD_CWORD_CLP,
1078         /* 171    41  ")" */ CSPCL_CWORD_CWORD_CRP,
1079         /* 172    42  "*" */ CWORD_CCTL_CCTL_CWORD,
1080         /* 173    43  "+" */ CWORD_CWORD_CWORD_CWORD,
1081         /* 174    44  "," */ CWORD_CWORD_CWORD_CWORD,
1082         /* 175    45  "-" */ CWORD_CCTL_CCTL_CWORD,
1083         /* 176    46  "." */ CWORD_CWORD_CWORD_CWORD,
1084         /* 177    47  "/" */ CWORD_CCTL_CCTL_CWORD,
1085         /* 178    48  "0" */ CWORD_CWORD_CWORD_CWORD,
1086         /* 179    49  "1" */ CWORD_CWORD_CWORD_CWORD,
1087         /* 180    50  "2" */ CWORD_CWORD_CWORD_CWORD,
1088         /* 181    51  "3" */ CWORD_CWORD_CWORD_CWORD,
1089         /* 182    52  "4" */ CWORD_CWORD_CWORD_CWORD,
1090         /* 183    53  "5" */ CWORD_CWORD_CWORD_CWORD,
1091         /* 184    54  "6" */ CWORD_CWORD_CWORD_CWORD,
1092         /* 185    55  "7" */ CWORD_CWORD_CWORD_CWORD,
1093         /* 186    56  "8" */ CWORD_CWORD_CWORD_CWORD,
1094         /* 187    57  "9" */ CWORD_CWORD_CWORD_CWORD,
1095         /* 188    58  ":" */ CWORD_CCTL_CCTL_CWORD,
1096         /* 189    59  ";" */ CSPCL_CWORD_CWORD_CWORD,
1097         /* 190    60  "<" */ CSPCL_CWORD_CWORD_CWORD,
1098         /* 191    61  "=" */ CWORD_CCTL_CCTL_CWORD,
1099         /* 192    62  ">" */ CSPCL_CWORD_CWORD_CWORD,
1100         /* 193    63  "?" */ CWORD_CCTL_CCTL_CWORD,
1101         /* 194    64  "@" */ CWORD_CWORD_CWORD_CWORD,
1102         /* 195    65  "A" */ CWORD_CWORD_CWORD_CWORD,
1103         /* 196    66  "B" */ CWORD_CWORD_CWORD_CWORD,
1104         /* 197    67  "C" */ CWORD_CWORD_CWORD_CWORD,
1105         /* 198    68  "D" */ CWORD_CWORD_CWORD_CWORD,
1106         /* 199    69  "E" */ CWORD_CWORD_CWORD_CWORD,
1107         /* 200    70  "F" */ CWORD_CWORD_CWORD_CWORD,
1108         /* 201    71  "G" */ CWORD_CWORD_CWORD_CWORD,
1109         /* 202    72  "H" */ CWORD_CWORD_CWORD_CWORD,
1110         /* 203    73  "I" */ CWORD_CWORD_CWORD_CWORD,
1111         /* 204    74  "J" */ CWORD_CWORD_CWORD_CWORD,
1112         /* 205    75  "K" */ CWORD_CWORD_CWORD_CWORD,
1113         /* 206    76  "L" */ CWORD_CWORD_CWORD_CWORD,
1114         /* 207    77  "M" */ CWORD_CWORD_CWORD_CWORD,
1115         /* 208    78  "N" */ CWORD_CWORD_CWORD_CWORD,
1116         /* 209    79  "O" */ CWORD_CWORD_CWORD_CWORD,
1117         /* 210    80  "P" */ CWORD_CWORD_CWORD_CWORD,
1118         /* 211    81  "Q" */ CWORD_CWORD_CWORD_CWORD,
1119         /* 212    82  "R" */ CWORD_CWORD_CWORD_CWORD,
1120         /* 213    83  "S" */ CWORD_CWORD_CWORD_CWORD,
1121         /* 214    84  "T" */ CWORD_CWORD_CWORD_CWORD,
1122         /* 215    85  "U" */ CWORD_CWORD_CWORD_CWORD,
1123         /* 216    86  "V" */ CWORD_CWORD_CWORD_CWORD,
1124         /* 217    87  "W" */ CWORD_CWORD_CWORD_CWORD,
1125         /* 218    88  "X" */ CWORD_CWORD_CWORD_CWORD,
1126         /* 219    89  "Y" */ CWORD_CWORD_CWORD_CWORD,
1127         /* 220    90  "Z" */ CWORD_CWORD_CWORD_CWORD,
1128         /* 221    91  "[" */ CWORD_CCTL_CCTL_CWORD,
1129         /* 222    92  "\" */ CBACK_CBACK_CCTL_CBACK,
1130         /* 223    93  "]" */ CWORD_CCTL_CCTL_CWORD,
1131         /* 224    94  "^" */ CWORD_CWORD_CWORD_CWORD,
1132         /* 225    95  "_" */ CWORD_CWORD_CWORD_CWORD,
1133         /* 226    96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1134         /* 227    97  "a" */ CWORD_CWORD_CWORD_CWORD,
1135         /* 228    98  "b" */ CWORD_CWORD_CWORD_CWORD,
1136         /* 229    99  "c" */ CWORD_CWORD_CWORD_CWORD,
1137         /* 230   100  "d" */ CWORD_CWORD_CWORD_CWORD,
1138         /* 231   101  "e" */ CWORD_CWORD_CWORD_CWORD,
1139         /* 232   102  "f" */ CWORD_CWORD_CWORD_CWORD,
1140         /* 233   103  "g" */ CWORD_CWORD_CWORD_CWORD,
1141         /* 234   104  "h" */ CWORD_CWORD_CWORD_CWORD,
1142         /* 235   105  "i" */ CWORD_CWORD_CWORD_CWORD,
1143         /* 236   106  "j" */ CWORD_CWORD_CWORD_CWORD,
1144         /* 237   107  "k" */ CWORD_CWORD_CWORD_CWORD,
1145         /* 238   108  "l" */ CWORD_CWORD_CWORD_CWORD,
1146         /* 239   109  "m" */ CWORD_CWORD_CWORD_CWORD,
1147         /* 240   110  "n" */ CWORD_CWORD_CWORD_CWORD,
1148         /* 241   111  "o" */ CWORD_CWORD_CWORD_CWORD,
1149         /* 242   112  "p" */ CWORD_CWORD_CWORD_CWORD,
1150         /* 243   113  "q" */ CWORD_CWORD_CWORD_CWORD,
1151         /* 244   114  "r" */ CWORD_CWORD_CWORD_CWORD,
1152         /* 245   115  "s" */ CWORD_CWORD_CWORD_CWORD,
1153         /* 246   116  "t" */ CWORD_CWORD_CWORD_CWORD,
1154         /* 247   117  "u" */ CWORD_CWORD_CWORD_CWORD,
1155         /* 248   118  "v" */ CWORD_CWORD_CWORD_CWORD,
1156         /* 249   119  "w" */ CWORD_CWORD_CWORD_CWORD,
1157         /* 250   120  "x" */ CWORD_CWORD_CWORD_CWORD,
1158         /* 251   121  "y" */ CWORD_CWORD_CWORD_CWORD,
1159         /* 252   122  "z" */ CWORD_CWORD_CWORD_CWORD,
1160         /* 253   123  "{" */ CWORD_CWORD_CWORD_CWORD,
1161         /* 254   124  "|" */ CSPCL_CWORD_CWORD_CWORD,
1162         /* 255   125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1163         /* 256   126  "~" */ CWORD_CCTL_CCTL_CWORD,
1164         /* 257   127      */ CWORD_CWORD_CWORD_CWORD,
1165 };
1166
1167 #endif                                                  /* USE_SIT_FUNCTION */
1168
1169 /*      $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $      */
1170
1171
1172 #define ATABSIZE 39
1173
1174 static int     funcblocksize;          /* size of structures in function */
1175 static int     funcstringsize;         /* size of strings in node */
1176 static pointer funcblock;              /* block to allocate function from */
1177 static char   *funcstring;             /* block to allocate strings from */
1178
1179 static const short nodesize[26] = {
1180       SHELL_ALIGN(sizeof (struct ncmd)),
1181       SHELL_ALIGN(sizeof (struct npipe)),
1182       SHELL_ALIGN(sizeof (struct nredir)),
1183       SHELL_ALIGN(sizeof (struct nredir)),
1184       SHELL_ALIGN(sizeof (struct nredir)),
1185       SHELL_ALIGN(sizeof (struct nbinary)),
1186       SHELL_ALIGN(sizeof (struct nbinary)),
1187       SHELL_ALIGN(sizeof (struct nbinary)),
1188       SHELL_ALIGN(sizeof (struct nif)),
1189       SHELL_ALIGN(sizeof (struct nbinary)),
1190       SHELL_ALIGN(sizeof (struct nbinary)),
1191       SHELL_ALIGN(sizeof (struct nfor)),
1192       SHELL_ALIGN(sizeof (struct ncase)),
1193       SHELL_ALIGN(sizeof (struct nclist)),
1194       SHELL_ALIGN(sizeof (struct narg)),
1195       SHELL_ALIGN(sizeof (struct narg)),
1196       SHELL_ALIGN(sizeof (struct nfile)),
1197       SHELL_ALIGN(sizeof (struct nfile)),
1198       SHELL_ALIGN(sizeof (struct nfile)),
1199       SHELL_ALIGN(sizeof (struct nfile)),
1200       SHELL_ALIGN(sizeof (struct nfile)),
1201       SHELL_ALIGN(sizeof (struct ndup)),
1202       SHELL_ALIGN(sizeof (struct ndup)),
1203       SHELL_ALIGN(sizeof (struct nhere)),
1204       SHELL_ALIGN(sizeof (struct nhere)),
1205       SHELL_ALIGN(sizeof (struct nnot)),
1206 };
1207
1208
1209 static void calcsize(union node *);
1210 static void sizenodelist(struct nodelist *);
1211 static union node *copynode(union node *);
1212 static struct nodelist *copynodelist(struct nodelist *);
1213 static char *nodesavestr(char *);
1214
1215
1216
1217 static void evalstring(char *);
1218 union node;     /* BLETCH for ansi C */
1219 static void evaltree(union node *, int);
1220 static void evalbackcmd(union node *, struct backcmd *);
1221
1222 /* in_function returns nonzero if we are currently evaluating a function */
1223 #define in_function()   funcnest
1224 static int evalskip;                   /* set if we are skipping commands */
1225 static int skipcount;           /* number of levels to skip */
1226 static int funcnest;                   /* depth of function calls */
1227
1228 /* reasons for skipping commands (see comment on breakcmd routine) */
1229 #define SKIPBREAK       1
1230 #define SKIPCONT        2
1231 #define SKIPFUNC        3
1232 #define SKIPFILE        4
1233
1234 /*
1235  * This file was generated by the mkbuiltins program.
1236  */
1237
1238 #ifdef JOBS
1239 static int bgcmd(int, char **);
1240 #endif
1241 static int breakcmd(int, char **);
1242 static int cdcmd(int, char **);
1243 #ifdef CONFIG_ASH_CMDCMD
1244 static int commandcmd(int, char **);
1245 #endif
1246 static int dotcmd(int, char **);
1247 static int evalcmd(int, char **);
1248 static int execcmd(int, char **);
1249 static int exitcmd(int, char **);
1250 static int exportcmd(int, char **);
1251 static int falsecmd(int, char **);
1252 #ifdef JOBS
1253 static int fgcmd(int, char **);
1254 #endif
1255 #ifdef CONFIG_ASH_GETOPTS
1256 static int getoptscmd(int, char **);
1257 #endif
1258 static int hashcmd(int, char **);
1259 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1260 static int helpcmd(int argc, char **argv);
1261 #endif
1262 #ifdef JOBS
1263 static int jobscmd(int, char **);
1264 #endif
1265 #ifdef CONFIG_ASH_MATH_SUPPORT
1266 static int letcmd(int, char **);
1267 #endif
1268 static int localcmd(int, char **);
1269 static int pwdcmd(int, char **);
1270 static int readcmd(int, char **);
1271 static int returncmd(int, char **);
1272 static int setcmd(int, char **);
1273 static int shiftcmd(int, char **);
1274 static int timescmd(int, char **);
1275 static int trapcmd(int, char **);
1276 static int truecmd(int, char **);
1277 static int typecmd(int, char **);
1278 static int umaskcmd(int, char **);
1279 static int unsetcmd(int, char **);
1280 static int waitcmd(int, char **);
1281 static int ulimitcmd(int, char **);
1282 #ifdef JOBS
1283 static int killcmd(int, char **);
1284 #endif
1285
1286 /*      $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
1287
1288 #ifdef CONFIG_ASH_MAIL
1289 static void chkmail(void);
1290 static void changemail(const char *);
1291 #endif
1292
1293 /*      $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $    */
1294
1295 /* values of cmdtype */
1296 #define CMDUNKNOWN      -1      /* no entry in table for command */
1297 #define CMDNORMAL       0       /* command is an executable program */
1298 #define CMDFUNCTION     1       /* command is a shell function */
1299 #define CMDBUILTIN      2       /* command is a shell builtin */
1300
1301 struct builtincmd {
1302         const char *name;
1303         int (*builtin)(int, char **);
1304         /* unsigned flags; */
1305 };
1306
1307 #ifdef CONFIG_ASH_CMDCMD
1308 # ifdef JOBS
1309 #  ifdef CONFIG_ASH_ALIAS
1310 #    define COMMANDCMD (builtincmd + 7)
1311 #    define EXECCMD (builtincmd + 10)
1312 #  else
1313 #    define COMMANDCMD (builtincmd + 6)
1314 #    define EXECCMD (builtincmd + 9)
1315 #  endif
1316 # else /* ! JOBS */
1317 #  ifdef CONFIG_ASH_ALIAS
1318 #    define COMMANDCMD (builtincmd + 6)
1319 #    define EXECCMD (builtincmd + 9)
1320 #  else
1321 #    define COMMANDCMD (builtincmd + 5)
1322 #    define EXECCMD (builtincmd + 8)
1323 #  endif
1324 # endif /* JOBS */
1325 #else   /* ! CONFIG_ASH_CMDCMD */
1326 # ifdef JOBS
1327 #  ifdef CONFIG_ASH_ALIAS
1328 #    define EXECCMD (builtincmd + 9)
1329 #  else
1330 #    define EXECCMD (builtincmd + 8)
1331 #  endif
1332 # else /* ! JOBS */
1333 #  ifdef CONFIG_ASH_ALIAS
1334 #    define EXECCMD (builtincmd + 8)
1335 #  else
1336 #    define EXECCMD (builtincmd + 7)
1337 #  endif
1338 # endif /* JOBS */
1339 #endif /* CONFIG_ASH_CMDCMD */
1340
1341 #define BUILTIN_NOSPEC  "0"
1342 #define BUILTIN_SPECIAL "1"
1343 #define BUILTIN_REGULAR "2"
1344 #define BUILTIN_SPEC_REG "3"
1345 #define BUILTIN_ASSIGN  "4"
1346 #define BUILTIN_SPEC_ASSG  "5"
1347 #define BUILTIN_REG_ASSG   "6"
1348 #define BUILTIN_SPEC_REG_ASSG   "7"
1349
1350 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1351 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1352
1353 static const struct builtincmd builtincmd[] = {
1354         { BUILTIN_SPEC_REG      ".", dotcmd },
1355         { BUILTIN_SPEC_REG      ":", truecmd },
1356 #ifdef CONFIG_ASH_ALIAS
1357         { BUILTIN_REG_ASSG      "alias", aliascmd },
1358 #endif
1359 #ifdef JOBS
1360         { BUILTIN_REGULAR       "bg", bgcmd },
1361 #endif
1362         { BUILTIN_SPEC_REG      "break", breakcmd },
1363         { BUILTIN_REGULAR       "cd", cdcmd },
1364         { BUILTIN_NOSPEC        "chdir", cdcmd },
1365 #ifdef CONFIG_ASH_CMDCMD
1366         { BUILTIN_REGULAR       "command", commandcmd },
1367 #endif
1368         { BUILTIN_SPEC_REG      "continue", breakcmd },
1369         { BUILTIN_SPEC_REG      "eval", evalcmd },
1370         { BUILTIN_SPEC_REG      "exec", execcmd },
1371         { BUILTIN_SPEC_REG      "exit", exitcmd },
1372         { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1373         { BUILTIN_REGULAR       "false", falsecmd },
1374 #ifdef JOBS
1375         { BUILTIN_REGULAR       "fg", fgcmd },
1376 #endif
1377 #ifdef CONFIG_ASH_GETOPTS
1378         { BUILTIN_REGULAR       "getopts", getoptscmd },
1379 #endif
1380         { BUILTIN_NOSPEC        "hash", hashcmd },
1381 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1382         { BUILTIN_NOSPEC        "help", helpcmd },
1383 #endif
1384 #ifdef JOBS
1385         { BUILTIN_REGULAR       "jobs", jobscmd },
1386         { BUILTIN_REGULAR       "kill", killcmd },
1387 #endif
1388 #ifdef CONFIG_ASH_MATH_SUPPORT
1389         { BUILTIN_NOSPEC        "let", letcmd },
1390 #endif
1391         { BUILTIN_ASSIGN        "local", localcmd },
1392         { BUILTIN_NOSPEC        "pwd", pwdcmd },
1393         { BUILTIN_REGULAR       "read", readcmd },
1394         { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1395         { BUILTIN_SPEC_REG      "return", returncmd },
1396         { BUILTIN_SPEC_REG      "set", setcmd },
1397         { BUILTIN_SPEC_REG      "shift", shiftcmd },
1398         { BUILTIN_SPEC_REG      "times", timescmd },
1399         { BUILTIN_SPEC_REG      "trap", trapcmd },
1400         { BUILTIN_REGULAR       "true", truecmd },
1401         { BUILTIN_NOSPEC        "type", typecmd },
1402         { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
1403         { BUILTIN_REGULAR       "umask", umaskcmd },
1404 #ifdef CONFIG_ASH_ALIAS
1405         { BUILTIN_REGULAR       "unalias", unaliascmd },
1406 #endif
1407         { BUILTIN_SPEC_REG      "unset", unsetcmd },
1408         { BUILTIN_REGULAR       "wait", waitcmd },
1409 };
1410
1411 #define NUMBUILTINS  (sizeof (builtincmd) / sizeof (struct builtincmd) )
1412
1413
1414
1415 struct cmdentry {
1416         int cmdtype;
1417         union param {
1418                 int index;
1419                 const struct builtincmd *cmd;
1420                 struct funcnode *func;
1421         } u;
1422 };
1423
1424
1425 /* action to find_command() */
1426 #define DO_ERR          0x01    /* prints errors */
1427 #define DO_ABS          0x02    /* checks absolute paths */
1428 #define DO_NOFUNC       0x04    /* don't return shell functions, for command */
1429 #define DO_ALTPATH      0x08    /* using alternate path */
1430 #define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
1431
1432 static const char *pathopt;     /* set by padvance */
1433
1434 static void shellexec(char **, const char *, int)
1435     __attribute__((__noreturn__));
1436 static char *padvance(const char **, const char *);
1437 static void find_command(char *, struct cmdentry *, int, const char *);
1438 static struct builtincmd *find_builtin(const char *);
1439 static void hashcd(void);
1440 static void changepath(const char *);
1441 static void defun(char *, union node *);
1442 static void unsetfunc(const char *);
1443
1444 #ifdef CONFIG_ASH_MATH_SUPPORT
1445 static int dash_arith(const char *);
1446 #endif
1447
1448 /*      $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
1449
1450 static void reset(void);
1451
1452 /*      $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $     */
1453
1454 /*
1455  * Shell variables.
1456  */
1457
1458 /* flags */
1459 #define VEXPORT         0x01    /* variable is exported */
1460 #define VREADONLY       0x02    /* variable cannot be modified */
1461 #define VSTRFIXED       0x04    /* variable struct is statically allocated */
1462 #define VTEXTFIXED      0x08    /* text is statically allocated */
1463 #define VSTACK          0x10    /* text is allocated on the stack */
1464 #define VUNSET          0x20    /* the variable is not set */
1465 #define VNOFUNC         0x40    /* don't call the callback function */
1466 #define VNOSET          0x80    /* do not set variable - just readonly test */
1467 #define VNOSAVE         0x100   /* when text is on the heap before setvareq */
1468
1469
1470 struct var {
1471         struct var *next;               /* next entry in hash list */
1472         int flags;                      /* flags are defined above */
1473         const char *text;               /* name=value */
1474         void (*func)(const char *);
1475                                         /* function to be called when  */
1476                                         /* the variable gets set/unset */
1477 };
1478
1479 struct localvar {
1480         struct localvar *next;          /* next local variable in list */
1481         struct var *vp;                 /* the variable that was made local */
1482         int flags;                      /* saved flags */
1483         const char *text;               /* saved text */
1484 };
1485
1486
1487 static struct localvar *localvars;
1488
1489 /*
1490  * Shell variables.
1491  */
1492
1493 #ifdef CONFIG_ASH_GETOPTS
1494 static void getoptsreset(const char *);
1495 #endif
1496
1497 #ifdef CONFIG_LOCALE_SUPPORT
1498 #include <locale.h>
1499 static void change_lc_all(const char *value);
1500 static void change_lc_ctype(const char *value);
1501 #endif
1502
1503 #define VTABSIZE 39
1504
1505 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1506 #ifdef IFS_BROKEN
1507 static const char defifsvar[] = "IFS= \t\n";
1508 #define defifs (defifsvar + 4)
1509 #else
1510 static const char defifs[] = " \t\n";
1511 #endif
1512
1513
1514 static struct var varinit[] = {
1515 #ifdef IFS_BROKEN
1516         { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
1517 #else
1518         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
1519 #endif
1520
1521 #ifdef CONFIG_ASH_MAIL
1522         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
1523         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
1524 #endif
1525
1526         { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
1527         { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0 },
1528         { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0 },
1529         { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0 },
1530 #ifdef CONFIG_ASH_GETOPTS
1531         { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
1532 #endif
1533 #ifdef CONFIG_LOCALE_SUPPORT
1534         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1535         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1536 #endif
1537 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1538         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1539 #endif
1540 };
1541
1542 #define vifs varinit[0]
1543 #ifdef CONFIG_ASH_MAIL
1544 #define vmail (&vifs)[1]
1545 #define vmpath (&vmail)[1]
1546 #else
1547 #define vmpath vifs
1548 #endif
1549 #define vpath (&vmpath)[1]
1550 #define vps1 (&vpath)[1]
1551 #define vps2 (&vps1)[1]
1552 #define vps4 (&vps2)[1]
1553 #define voptind (&vps4)[1]
1554
1555 #define defpath (defpathvar + 5)
1556
1557 /*
1558  * The following macros access the values of the above variables.
1559  * They have to skip over the name.  They return the null string
1560  * for unset variables.
1561  */
1562
1563 #define ifsval()        (vifs.text + 4)
1564 #define ifsset()        ((vifs.flags & VUNSET) == 0)
1565 #define mailval()       (vmail.text + 5)
1566 #define mpathval()      (vmpath.text + 9)
1567 #define pathval()       (vpath.text + 5)
1568 #define ps1val()        (vps1.text + 4)
1569 #define ps2val()        (vps2.text + 4)
1570 #define ps4val()        (vps4.text + 4)
1571 #define optindval()     (voptind.text + 7)
1572
1573 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
1574
1575 static void setvar(const char *, const char *, int);
1576 static void setvareq(char *, int);
1577 static void listsetvar(struct strlist *, int);
1578 static char *lookupvar(const char *);
1579 static char *bltinlookup(const char *);
1580 static char **listvars(int, int, char ***);
1581 #define environment() listvars(VEXPORT, VUNSET, 0)
1582 static int showvars(const char *, int, int);
1583 static void poplocalvars(void);
1584 static int unsetvar(const char *);
1585 #ifdef CONFIG_ASH_GETOPTS
1586 static int setvarsafe(const char *, const char *, int);
1587 #endif
1588 static int varcmp(const char *, const char *);
1589 static struct var **hashvar(const char *);
1590
1591
1592 static inline int varequal(const char *a, const char *b) {
1593         return !varcmp(a, b);
1594 }
1595
1596
1597 static int loopnest;            /* current loop nesting level */
1598
1599 /*
1600  * The parsefile structure pointed to by the global variable parsefile
1601  * contains information about the current file being read.
1602  */
1603
1604
1605 struct redirtab {
1606         struct redirtab *next;
1607         int renamed[10];
1608         int nullredirs;
1609 };
1610
1611 static struct redirtab *redirlist;
1612 static int nullredirs;
1613
1614 extern char **environ;
1615
1616 /*      $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $     */
1617
1618
1619 static void outstr(const char *, FILE *);
1620 static void outcslow(int, FILE *);
1621 static void flushall(void);
1622 static void flushout(FILE *);
1623 static int  out1fmt(const char *, ...)
1624     __attribute__((__format__(__printf__,1,2)));
1625 static int fmtstr(char *, size_t, const char *, ...)
1626     __attribute__((__format__(__printf__,3,4)));
1627 static void xwrite(int, const void *, size_t);
1628
1629 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
1630
1631
1632 static void out1str(const char *p)
1633 {
1634         outstr(p, stdout);
1635 }
1636
1637 static void out2str(const char *p)
1638 {
1639         outstr(p, stderr);
1640         flushout(stderr);
1641 }
1642
1643 /*
1644  * Initialization code.
1645  */
1646
1647 /*
1648  * This routine initializes the builtin variables.
1649  */
1650
1651 static inline void
1652 initvar(void)
1653 {
1654         struct var *vp;
1655         struct var *end;
1656         struct var **vpp;
1657
1658         /*
1659          * PS1 depends on uid
1660          */
1661 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1662         vps1.text = "PS1=\\w \\$ ";
1663 #else
1664         if (!geteuid())
1665                 vps1.text = "PS1=# ";
1666 #endif
1667         vp = varinit;
1668         end = vp + sizeof(varinit) / sizeof(varinit[0]);
1669         do {
1670                 vpp = hashvar(vp->text);
1671                 vp->next = *vpp;
1672                 *vpp = vp;
1673         } while (++vp < end);
1674 }
1675
1676 static inline void
1677 init(void)
1678 {
1679
1680       /* from input.c: */
1681       {
1682               basepf.nextc = basepf.buf = basebuf;
1683       }
1684
1685       /* from trap.c: */
1686       {
1687               signal(SIGCHLD, SIG_DFL);
1688       }
1689
1690       /* from var.c: */
1691       {
1692               char **envp;
1693               char ppid[32];
1694
1695               initvar();
1696               for (envp = environ ; *envp ; envp++) {
1697                       if (strchr(*envp, '=')) {
1698                               setvareq(*envp, VEXPORT|VTEXTFIXED);
1699                       }
1700               }
1701
1702               snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1703               setvar("PPID", ppid, 0);
1704               setpwd(0, 0);
1705       }
1706 }
1707
1708 /* PEOF (the end of file marker) */
1709
1710 /*
1711  * The input line number.  Input.c just defines this variable, and saves
1712  * and restores it when files are pushed and popped.  The user of this
1713  * package must set its value.
1714  */
1715
1716 static int pgetc(void);
1717 static int pgetc2(void);
1718 static int preadbuffer(void);
1719 static void pungetc(void);
1720 static void pushstring(char *, void *);
1721 static void popstring(void);
1722 static void setinputfile(const char *, int);
1723 static void setinputfd(int, int);
1724 static void setinputstring(char *);
1725 static void popfile(void);
1726 static void popallfiles(void);
1727 static void closescript(void);
1728
1729
1730 /*      $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $    */
1731
1732
1733 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
1734 #define FORK_FG 0
1735 #define FORK_BG 1
1736 #define FORK_NOJOB 2
1737
1738 /* mode flags for showjob(s) */
1739 #define SHOW_PGID       0x01    /* only show pgid - for jobs -p */
1740 #define SHOW_PID        0x04    /* include process pid */
1741 #define SHOW_CHANGED    0x08    /* only jobs whose state has changed */
1742
1743
1744 /*
1745  * A job structure contains information about a job.  A job is either a
1746  * single process or a set of processes contained in a pipeline.  In the
1747  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1748  * array of pids.
1749  */
1750
1751 struct procstat {
1752         pid_t   pid;            /* process id */
1753         int     status;         /* last process status from wait() */
1754         char    *cmd;           /* text of command being run */
1755 };
1756
1757 struct job {
1758         struct procstat ps0;    /* status of process */
1759         struct procstat *ps;    /* status or processes when more than one */
1760 #if JOBS
1761         int stopstatus;         /* status of a stopped job */
1762 #endif
1763         uint32_t
1764                 nprocs: 16,     /* number of processes */
1765                 state: 8,
1766 #define JOBRUNNING      0       /* at least one proc running */
1767 #define JOBSTOPPED      1       /* all procs are stopped */
1768 #define JOBDONE         2       /* all procs are completed */
1769 #if JOBS
1770                 sigint: 1,      /* job was killed by SIGINT */
1771                 jobctl: 1,      /* job running under job control */
1772 #endif
1773                 waited: 1,      /* true if this entry has been waited for */
1774                 used: 1,        /* true if this entry is in used */
1775                 changed: 1;     /* true if status has changed */
1776         struct job *prev_job;   /* previous job */
1777 };
1778
1779 static pid_t backgndpid;        /* pid of last background process */
1780 static int job_warning;         /* user was warned about stopped jobs */
1781 #if JOBS
1782 static int jobctl;              /* true if doing job control */
1783 #endif
1784
1785 static struct job *makejob(union node *, int);
1786 static int forkshell(struct job *, union node *, int);
1787 static int waitforjob(struct job *);
1788 static int stoppedjobs(void);
1789
1790 #if ! JOBS
1791 #define setjobctl(on)   /* do nothing */
1792 #else
1793 static void setjobctl(int);
1794 static void showjobs(FILE *, int);
1795 #endif
1796
1797 /*      $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $        */
1798
1799
1800 /* pid of main shell */
1801 static int rootpid;
1802 /* true if we aren't a child of the main shell */
1803 static int rootshell;
1804
1805 static void readcmdfile(char *);
1806 static void cmdloop(int);
1807
1808 /*      $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $        */
1809
1810
1811 struct stackmark {
1812         struct stack_block *stackp;
1813         char *stacknxt;
1814         size_t stacknleft;
1815         struct stackmark *marknext;
1816 };
1817
1818 /* minimum size of a block */
1819 #define MINSIZE SHELL_ALIGN(504)
1820
1821 struct stack_block {
1822         struct stack_block *prev;
1823         char space[MINSIZE];
1824 };
1825
1826 static struct stack_block stackbase;
1827 static struct stack_block *stackp = &stackbase;
1828 static struct stackmark *markp;
1829 static char *stacknxt = stackbase.space;
1830 static size_t stacknleft = MINSIZE;
1831 static char *sstrend = stackbase.space + MINSIZE;
1832 static int herefd = -1;
1833
1834
1835 static pointer ckmalloc(size_t);
1836 static pointer ckrealloc(pointer, size_t);
1837 static char *savestr(const char *);
1838 static pointer stalloc(size_t);
1839 static void stunalloc(pointer);
1840 static void setstackmark(struct stackmark *);
1841 static void popstackmark(struct stackmark *);
1842 static void growstackblock(void);
1843 static void *growstackstr(void);
1844 static char *makestrspace(size_t, char *);
1845 static char *stnputs(const char *, size_t, char *);
1846 static char *stputs(const char *, char *);
1847
1848
1849 static inline char *_STPUTC(char c, char *p) {
1850         if (p == sstrend)
1851                 p = growstackstr();
1852         *p++ = c;
1853         return p;
1854 }
1855
1856 #define stackblock() ((void *)stacknxt)
1857 #define stackblocksize() stacknleft
1858 #define STARTSTACKSTR(p) ((p) = stackblock())
1859 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1860 #define CHECKSTRSPACE(n, p) \
1861         ({ \
1862                 char *q = (p); \
1863                 size_t l = (n); \
1864                 size_t m = sstrend - q; \
1865                 if (l > m) \
1866                         (p) = makestrspace(l, q); \
1867                 0; \
1868         })
1869 #define USTPUTC(c, p)   (*p++ = (c))
1870 #define STACKSTRNUL(p)  ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1871 #define STUNPUTC(p)     (--p)
1872 #define STTOPC(p)       p[-1]
1873 #define STADJUST(amount, p)     (p += (amount))
1874
1875 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1876 #define ungrabstackstr(s, p) stunalloc((s))
1877 #define stackstrend() ((void *)sstrend)
1878
1879 #define ckfree(p)       free((pointer)(p))
1880
1881 /*      $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $   */
1882
1883
1884 #define DOLATSTRLEN 4
1885
1886 static char *prefix(const char *, const char *);
1887 static int number(const char *);
1888 static int is_number(const char *);
1889 static char *single_quote(const char *);
1890 static char *sstrdup(const char *);
1891
1892 #define equal(s1, s2)   (strcmp(s1, s2) == 0)
1893 #define scopy(s1, s2)   ((void)strcpy(s2, s1))
1894
1895 /*      $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1896
1897 struct shparam {
1898         int nparam;             /* # of positional parameters (without $0) */
1899         unsigned char malloc;   /* if parameter list dynamically allocated */
1900         char **p;               /* parameter list */
1901 #ifdef CONFIG_ASH_GETOPTS
1902         int optind;             /* next parameter to be processed by getopts */
1903         int optoff;             /* used by getopts */
1904 #endif
1905 };
1906
1907
1908 #define eflag optlist[0]
1909 #define fflag optlist[1]
1910 #define Iflag optlist[2]
1911 #define iflag optlist[3]
1912 #define mflag optlist[4]
1913 #define nflag optlist[5]
1914 #define sflag optlist[6]
1915 #define xflag optlist[7]
1916 #define vflag optlist[8]
1917 #define Cflag optlist[9]
1918 #define aflag optlist[10]
1919 #define bflag optlist[11]
1920 #define uflag optlist[12]
1921 #define qflag optlist[13]
1922
1923 #ifdef DEBUG
1924 #define nolog optlist[14]
1925 #define debug optlist[15]
1926 #define NOPTS   16
1927 #else
1928 #define NOPTS   14
1929 #endif
1930
1931 /*      $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1932
1933
1934 static const char *const optletters_optnames[NOPTS] = {
1935         "e"   "errexit",
1936         "f"   "noglob",
1937         "I"   "ignoreeof",
1938         "i"   "interactive",
1939         "m"   "monitor",
1940         "n"   "noexec",
1941         "s"   "stdin",
1942         "x"   "xtrace",
1943         "v"   "verbose",
1944         "C"   "noclobber",
1945         "a"   "allexport",
1946         "b"   "notify",
1947         "u"   "nounset",
1948         "q"   "quietprofile",
1949 #ifdef DEBUG
1950         "\0"  "nolog",
1951         "\0"  "debug",
1952 #endif
1953 };
1954
1955 #define optletters(n) optletters_optnames[(n)][0]
1956 #define optnames(n) (&optletters_optnames[(n)][1])
1957
1958
1959 static char optlist[NOPTS];
1960
1961
1962 static char *arg0;                     /* value of $0 */
1963 static struct shparam shellparam;      /* $@ current positional parameters */
1964 static char **argptr;                  /* argument list for builtin commands */
1965 static char *optionarg;                /* set by nextopt (like getopt) */
1966 static char *optptr;                   /* used by nextopt */
1967
1968 static char *minusc;                   /* argument to -c option */
1969
1970
1971 static void procargs(int, char **);
1972 static void optschanged(void);
1973 static void setparam(char **);
1974 static void freeparam(volatile struct shparam *);
1975 static int shiftcmd(int, char **);
1976 static int setcmd(int, char **);
1977 static int nextopt(const char *);
1978
1979 /*      $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $      */
1980
1981 /* flags passed to redirect */
1982 #define REDIR_PUSH 01           /* save previous values of file descriptors */
1983 #define REDIR_SAVEFD2 03       /* set preverrout */
1984
1985 union node;
1986 static void redirect(union node *, int);
1987 static void popredir(int);
1988 static void clearredir(int);
1989 static int copyfd(int, int);
1990 static int redirectsafe(union node *, int);
1991
1992 /*      $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $     */
1993
1994
1995 #ifdef DEBUG
1996 static void showtree(union node *);
1997 static void trace(const char *, ...);
1998 static void tracev(const char *, va_list);
1999 static void trargs(char **);
2000 static void trputc(int);
2001 static void trputs(const char *);
2002 static void opentrace(void);
2003 #endif
2004
2005 /*      $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $       */
2006
2007
2008 /* trap handler commands */
2009 static char *trap[NSIG];
2010 /* current value of signal */
2011 static char sigmode[NSIG - 1];
2012 /* indicates specified signal received */
2013 static char gotsig[NSIG - 1];
2014
2015 static void clear_traps(void);
2016 static void setsignal(int);
2017 static void ignoresig(int);
2018 static void onsig(int);
2019 static void dotrap(void);
2020 static void setinteractive(int);
2021 static void exitshell(void) __attribute__((__noreturn__));
2022 static int decode_signal(const char *, int);
2023
2024 /*
2025  * This routine is called when an error or an interrupt occurs in an
2026  * interactive shell and control is returned to the main command loop.
2027  */
2028
2029 static void
2030 reset(void)
2031 {
2032       /* from eval.c: */
2033       {
2034               evalskip = 0;
2035               loopnest = 0;
2036               funcnest = 0;
2037       }
2038
2039       /* from input.c: */
2040       {
2041               parselleft = parsenleft = 0;      /* clear input buffer */
2042               popallfiles();
2043       }
2044
2045       /* from parser.c: */
2046       {
2047               tokpushback = 0;
2048               checkkwd = 0;
2049       }
2050
2051       /* from redir.c: */
2052       {
2053               clearredir(0);
2054       }
2055
2056 }
2057
2058 #ifdef CONFIG_ASH_ALIAS
2059 static struct alias *atab[ATABSIZE];
2060
2061 static void setalias(const char *, const char *);
2062 static struct alias *freealias(struct alias *);
2063 static struct alias **__lookupalias(const char *);
2064
2065 static void
2066 setalias(const char *name, const char *val)
2067 {
2068         struct alias *ap, **app;
2069
2070         app = __lookupalias(name);
2071         ap = *app;
2072         INTOFF;
2073         if (ap) {
2074                 if (!(ap->flag & ALIASINUSE)) {
2075                         ckfree(ap->val);
2076                 }
2077                 ap->val = savestr(val);
2078                 ap->flag &= ~ALIASDEAD;
2079         } else {
2080                 /* not found */
2081                 ap = ckmalloc(sizeof (struct alias));
2082                 ap->name = savestr(name);
2083                 ap->val = savestr(val);
2084                 ap->flag = 0;
2085                 ap->next = 0;
2086                 *app = ap;
2087         }
2088         INTON;
2089 }
2090
2091 static int
2092 unalias(const char *name)
2093 {
2094         struct alias **app;
2095
2096         app = __lookupalias(name);
2097
2098         if (*app) {
2099                 INTOFF;
2100                 *app = freealias(*app);
2101                 INTON;
2102                 return (0);
2103         }
2104
2105         return (1);
2106 }
2107
2108 static void
2109 rmaliases(void)
2110 {
2111         struct alias *ap, **app;
2112         int i;
2113
2114         INTOFF;
2115         for (i = 0; i < ATABSIZE; i++) {
2116                 app = &atab[i];
2117                 for (ap = *app; ap; ap = *app) {
2118                         *app = freealias(*app);
2119                         if (ap == *app) {
2120                                 app = &ap->next;
2121                         }
2122                 }
2123         }
2124         INTON;
2125 }
2126
2127 static struct alias *
2128 lookupalias(const char *name, int check)
2129 {
2130         struct alias *ap = *__lookupalias(name);
2131
2132         if (check && ap && (ap->flag & ALIASINUSE))
2133                 return (NULL);
2134         return (ap);
2135 }
2136
2137 /*
2138  * TODO - sort output
2139  */
2140 static int
2141 aliascmd(int argc, char **argv)
2142 {
2143         char *n, *v;
2144         int ret = 0;
2145         struct alias *ap;
2146
2147         if (argc == 1) {
2148                 int i;
2149
2150                 for (i = 0; i < ATABSIZE; i++)
2151                         for (ap = atab[i]; ap; ap = ap->next) {
2152                                 printalias(ap);
2153                         }
2154                 return (0);
2155         }
2156         while ((n = *++argv) != NULL) {
2157                 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2158                         if ((ap = *__lookupalias(n)) == NULL) {
2159                                 fprintf(stderr, "%s: %s not found\n", "alias", n);
2160                                 ret = 1;
2161                         } else
2162                                 printalias(ap);
2163                 } else {
2164                         *v++ = '\0';
2165                         setalias(n, v);
2166                 }
2167         }
2168
2169         return (ret);
2170 }
2171
2172 static int
2173 unaliascmd(int argc, char **argv)
2174 {
2175         int i;
2176
2177         while ((i = nextopt("a")) != '\0') {
2178                 if (i == 'a') {
2179                         rmaliases();
2180                         return (0);
2181                 }
2182         }
2183         for (i = 0; *argptr; argptr++) {
2184                 if (unalias(*argptr)) {
2185                         fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2186                         i = 1;
2187                 }
2188         }
2189
2190         return (i);
2191 }
2192
2193 static struct alias *
2194 freealias(struct alias *ap) {
2195         struct alias *next;
2196
2197         if (ap->flag & ALIASINUSE) {
2198                 ap->flag |= ALIASDEAD;
2199                 return ap;
2200         }
2201
2202         next = ap->next;
2203         ckfree(ap->name);
2204         ckfree(ap->val);
2205         ckfree(ap);
2206         return next;
2207 }
2208
2209 static void
2210 printalias(const struct alias *ap) {
2211         out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2212 }
2213
2214 static struct alias **
2215 __lookupalias(const char *name) {
2216         unsigned int hashval;
2217         struct alias **app;
2218         const char *p;
2219         unsigned int ch;
2220
2221         p = name;
2222
2223         ch = (unsigned char)*p;
2224         hashval = ch << 4;
2225         while (ch) {
2226                 hashval += ch;
2227                 ch = (unsigned char)*++p;
2228         }
2229         app = &atab[hashval % ATABSIZE];
2230
2231         for (; *app; app = &(*app)->next) {
2232                 if (equal(name, (*app)->name)) {
2233                         break;
2234                 }
2235         }
2236
2237         return app;
2238 }
2239 #endif /* CONFIG_ASH_ALIAS */
2240
2241
2242 /*      $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $      */
2243
2244 /*
2245  * The cd and pwd commands.
2246  */
2247
2248 #define CD_PHYSICAL 1
2249 #define CD_PRINT 2
2250
2251 static int docd(const char *, int);
2252 static int cdopt(void);
2253
2254 static char *curdir = nullstr;          /* current working directory */
2255 static char *physdir = nullstr;         /* physical working directory */
2256
2257 static int
2258 cdopt(void)
2259 {
2260         int flags = 0;
2261         int i, j;
2262
2263         j = 'L';
2264         while ((i = nextopt("LP"))) {
2265                 if (i != j) {
2266                         flags ^= CD_PHYSICAL;
2267                         j = i;
2268                 }
2269         }
2270
2271         return flags;
2272 }
2273
2274 static int
2275 cdcmd(int argc, char **argv)
2276 {
2277         const char *dest;
2278         const char *path;
2279         const char *p;
2280         char c;
2281         struct stat statb;
2282         int flags;
2283
2284         flags = cdopt();
2285         dest = *argptr;
2286         if (!dest)
2287                 dest = bltinlookup(homestr);
2288         else if (dest[0] == '-' && dest[1] == '\0') {
2289                 dest = bltinlookup("OLDPWD");
2290                 flags |= CD_PRINT;
2291                 goto step7;
2292         }
2293         if (!dest)
2294                 dest = nullstr;
2295         if (*dest == '/')
2296                 goto step7;
2297         if (*dest == '.') {
2298                 c = dest[1];
2299 dotdot:
2300                 switch (c) {
2301                 case '\0':
2302                 case '/':
2303                         goto step6;
2304                 case '.':
2305                         c = dest[2];
2306                         if (c != '.')
2307                                 goto dotdot;
2308                 }
2309         }
2310         if (!*dest)
2311                 dest = ".";
2312         if (!(path = bltinlookup("CDPATH"))) {
2313 step6:
2314 step7:
2315                 p = dest;
2316                 goto docd;
2317         }
2318         do {
2319                 c = *path;
2320                 p = padvance(&path, dest);
2321                 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2322                         if (c && c != ':')
2323                                 flags |= CD_PRINT;
2324 docd:
2325                         if (!docd(p, flags))
2326                                 goto out;
2327                         break;
2328                 }
2329         } while (path);
2330         error("can't cd to %s", dest);
2331         /* NOTREACHED */
2332 out:
2333         if (flags & CD_PRINT)
2334                 out1fmt(snlfmt, curdir);
2335         return 0;
2336 }
2337
2338
2339 /*
2340  * Update curdir (the name of the current directory) in response to a
2341  * cd command.
2342  */
2343
2344 static inline const char *
2345 updatepwd(const char *dir)
2346 {
2347         char *new;
2348         char *p;
2349         char *cdcomppath;
2350         const char *lim;
2351
2352         cdcomppath = sstrdup(dir);
2353         STARTSTACKSTR(new);
2354         if (*dir != '/') {
2355                 if (curdir == nullstr)
2356                         return 0;
2357                 new = stputs(curdir, new);
2358         }
2359         new = makestrspace(strlen(dir) + 2, new);
2360         lim = stackblock() + 1;
2361         if (*dir != '/') {
2362                 if (new[-1] != '/')
2363                         USTPUTC('/', new);
2364                 if (new > lim && *lim == '/')
2365                         lim++;
2366         } else {
2367                 USTPUTC('/', new);
2368                 cdcomppath++;
2369                 if (dir[1] == '/' && dir[2] != '/') {
2370                         USTPUTC('/', new);
2371                         cdcomppath++;
2372                         lim++;
2373                 }
2374         }
2375         p = strtok(cdcomppath, "/");
2376         while (p) {
2377                 switch(*p) {
2378                 case '.':
2379                         if (p[1] == '.' && p[2] == '\0') {
2380                                 while (new > lim) {
2381                                         STUNPUTC(new);
2382                                         if (new[-1] == '/')
2383                                                 break;
2384                                 }
2385                                 break;
2386                         } else if (p[1] == '\0')
2387                                 break;
2388                         /* fall through */
2389                 default:
2390                         new = stputs(p, new);
2391                         USTPUTC('/', new);
2392                 }
2393                 p = strtok(0, "/");
2394         }
2395         if (new > lim)
2396                 STUNPUTC(new);
2397         *new = 0;
2398         return stackblock();
2399 }
2400
2401 /*
2402  * Actually do the chdir.  We also call hashcd to let the routines in exec.c
2403  * know that the current directory has changed.
2404  */
2405
2406 static int
2407 docd(const char *dest, int flags)
2408 {
2409         const char *dir = 0;
2410         int err;
2411
2412         TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2413
2414         INTOFF;
2415         if (!(flags & CD_PHYSICAL)) {
2416                 dir = updatepwd(dest);
2417                 if (dir)
2418                         dest = dir;
2419         }
2420         err = chdir(dest);
2421         if (err)
2422                 goto out;
2423         setpwd(dir, 1);
2424         hashcd();
2425 out:
2426         INTON;
2427         return err;
2428 }
2429
2430 /*
2431  * Find out what the current directory is. If we already know the current
2432  * directory, this routine returns immediately.
2433  */
2434 static inline char *
2435 getpwd(void)
2436 {
2437         char *dir = getcwd(0, 0);
2438         return dir ? dir : nullstr;
2439 }
2440
2441 static int
2442 pwdcmd(int argc, char **argv)
2443 {
2444         int flags;
2445         const char *dir = curdir;
2446
2447         flags = cdopt();
2448         if (flags) {
2449                 if (physdir == nullstr)
2450                         setpwd(dir, 0);
2451                 dir = physdir;
2452         }
2453         out1fmt(snlfmt, dir);
2454         return 0;
2455 }
2456
2457 static void
2458 setpwd(const char *val, int setold)
2459 {
2460         char *oldcur, *dir;
2461
2462         oldcur = dir = curdir;
2463
2464         if (setold) {
2465                 setvar("OLDPWD", oldcur, VEXPORT);
2466         }
2467         INTOFF;
2468         if (physdir != nullstr) {
2469                 if (physdir != oldcur)
2470                         free(physdir);
2471                 physdir = nullstr;
2472         }
2473         if (oldcur == val || !val) {
2474                 char *s = getpwd();
2475                 physdir = s;
2476                 if (!val)
2477                         dir = s;
2478         } else
2479                 dir = savestr(val);
2480         if (oldcur != dir && oldcur != nullstr) {
2481                 free(oldcur);
2482         }
2483         curdir = dir;
2484         INTON;
2485         setvar("PWD", dir, VEXPORT);
2486 }
2487
2488 /*      $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $   */
2489
2490 /*
2491  * Errors and exceptions.
2492  */
2493
2494 /*
2495  * Code to handle exceptions in C.
2496  */
2497
2498
2499
2500 static void exverror(int, const char *, va_list)
2501     __attribute__((__noreturn__));
2502
2503 /*
2504  * Called to raise an exception.  Since C doesn't include exceptions, we
2505  * just do a longjmp to the exception handler.  The type of exception is
2506  * stored in the global variable "exception".
2507  */
2508
2509 static void
2510 exraise(int e)
2511 {
2512 #ifdef DEBUG
2513         if (handler == NULL)
2514                 abort();
2515 #endif
2516         INTOFF;
2517
2518         exception = e;
2519         longjmp(handler->loc, 1);
2520 }
2521
2522
2523 /*
2524  * Called from trap.c when a SIGINT is received.  (If the user specifies
2525  * that SIGINT is to be trapped or ignored using the trap builtin, then
2526  * this routine is not called.)  Suppressint is nonzero when interrupts
2527  * are held using the INTOFF macro.  (The test for iflag is just
2528  * defensive programming.)
2529  */
2530
2531 static void
2532 onint(void) {
2533         int i;
2534
2535         intpending = 0;
2536         sigsetmask(0);
2537         i = EXSIG;
2538         if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2539                 if (!(rootshell && iflag)) {
2540                         signal(SIGINT, SIG_DFL);
2541                         raise(SIGINT);
2542                 }
2543                 i = EXINT;
2544         }
2545         exraise(i);
2546         /* NOTREACHED */
2547 }
2548
2549 static void
2550 exvwarning(const char *msg, va_list ap)
2551 {
2552         FILE *errs;
2553         const char *name;
2554         const char *fmt;
2555
2556         errs = stderr;
2557         name = arg0;
2558         fmt = "%s: ";
2559         if (commandname) {
2560                 name = commandname;
2561                 fmt = "%s: %d: ";
2562         }
2563         fprintf(errs, fmt, name, startlinno);
2564         vfprintf(errs, msg, ap);
2565         outcslow('\n', errs);
2566 }
2567
2568 /*
2569  * Exverror is called to raise the error exception.  If the second argument
2570  * is not NULL then error prints an error message using printf style
2571  * formatting.  It then raises the error exception.
2572  */
2573 static void
2574 exverror(int cond, const char *msg, va_list ap)
2575 {
2576 #ifdef DEBUG
2577         if (msg) {
2578                 TRACE(("exverror(%d, \"", cond));
2579                 TRACEV((msg, ap));
2580                 TRACE(("\") pid=%d\n", getpid()));
2581         } else
2582                 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2583         if (msg)
2584 #endif
2585                 exvwarning(msg, ap);
2586
2587         flushall();
2588         exraise(cond);
2589         /* NOTREACHED */
2590 }
2591
2592
2593 static void
2594 error(const char *msg, ...)
2595 {
2596         va_list ap;
2597
2598         va_start(ap, msg);
2599         exverror(EXERROR, msg, ap);
2600         /* NOTREACHED */
2601         va_end(ap);
2602 }
2603
2604
2605 static void
2606 exerror(int cond, const char *msg, ...)
2607 {
2608         va_list ap;
2609
2610         va_start(ap, msg);
2611         exverror(cond, msg, ap);
2612         /* NOTREACHED */
2613         va_end(ap);
2614 }
2615
2616 /*
2617  * error/warning routines for external builtins
2618  */
2619
2620 static void
2621 sh_warnx(const char *fmt, ...)
2622 {
2623         va_list ap;
2624
2625         va_start(ap, fmt);
2626         exvwarning(fmt, ap);
2627         va_end(ap);
2628 }
2629
2630
2631 /*
2632  * Return a string describing an error.  The returned string may be a
2633  * pointer to a static buffer that will be overwritten on the next call.
2634  * Action describes the operation that got the error.
2635  */
2636
2637 static const char *
2638 errmsg(int e, const char *em)
2639 {
2640         if(e == ENOENT || e == ENOTDIR) {
2641
2642                 return em;
2643         }
2644         return strerror(e);
2645 }
2646
2647
2648 /*      $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $  */
2649
2650 /*
2651  * Evaluate a command.
2652  */
2653
2654 /* flags in argument to evaltree */
2655 #define EV_EXIT 01              /* exit after evaluating tree */
2656 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
2657 #define EV_BACKCMD 04           /* command executing within back quotes */
2658
2659
2660 static void evalloop(union node *, int);
2661 static void evalfor(union node *, int);
2662 static void evalcase(union node *, int);
2663 static void evalsubshell(union node *, int);
2664 static void expredir(union node *);
2665 static void evalpipe(union node *, int);
2666 static void evalcommand(union node *, int);
2667 static int evalbltin(const struct builtincmd *, int, char **);
2668 static int evalfun(struct funcnode *, int, char **, int);
2669 static void prehash(union node *);
2670 static int bltincmd(int, char **);
2671
2672
2673 static const struct builtincmd bltin = {
2674         "\0\0", bltincmd
2675 };
2676
2677
2678 /*
2679  * Called to reset things after an exception.
2680  */
2681
2682 /*
2683  * The eval commmand.
2684  */
2685
2686 static int
2687 evalcmd(int argc, char **argv)
2688 {
2689         char *p;
2690         char *concat;
2691         char **ap;
2692
2693         if (argc > 1) {
2694                 p = argv[1];
2695                 if (argc > 2) {
2696                         STARTSTACKSTR(concat);
2697                         ap = argv + 2;
2698                         for (;;) {
2699                                 concat = stputs(p, concat);
2700                                 if ((p = *ap++) == NULL)
2701                                         break;
2702                                 STPUTC(' ', concat);
2703                         }
2704                         STPUTC('\0', concat);
2705                         p = grabstackstr(concat);
2706                 }
2707                 evalstring(p);
2708         }
2709         return exitstatus;
2710 }
2711
2712
2713 /*
2714  * Execute a command or commands contained in a string.
2715  */
2716
2717 static void
2718 evalstring(char *s)
2719 {
2720         union node *n;
2721         struct stackmark smark;
2722
2723         setstackmark(&smark);
2724         setinputstring(s);
2725
2726         while ((n = parsecmd(0)) != NEOF) {
2727                 evaltree(n, 0);
2728                 popstackmark(&smark);
2729                 if (evalskip)
2730                         break;
2731         }
2732         popfile();
2733         popstackmark(&smark);
2734 }
2735
2736
2737
2738 /*
2739  * Evaluate a parse tree.  The value is left in the global variable
2740  * exitstatus.
2741  */
2742
2743 static void
2744 evaltree(union node *n, int flags)
2745 {
2746         int checkexit = 0;
2747         void (*evalfn)(union node *, int);
2748         unsigned isor;
2749         int status;
2750         if (n == NULL) {
2751                 TRACE(("evaltree(NULL) called\n"));
2752                 goto out;
2753         }
2754         TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2755             getpid(), n, n->type, flags));
2756         switch (n->type) {
2757         default:
2758 #ifdef DEBUG
2759                 out1fmt("Node type = %d\n", n->type);
2760                 fflush(stdout);
2761                 break;
2762 #endif
2763         case NNOT:
2764                 evaltree(n->nnot.com, EV_TESTED);
2765                 status = !exitstatus;
2766                 goto setstatus;
2767         case NREDIR:
2768                 expredir(n->nredir.redirect);
2769                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2770                 if (!status) {
2771                         evaltree(n->nredir.n, flags & EV_TESTED);
2772                         status = exitstatus;
2773                 }
2774                 popredir(0);
2775                 goto setstatus;
2776         case NCMD:
2777                 evalfn = evalcommand;
2778 checkexit:
2779                 if (eflag && !(flags & EV_TESTED))
2780                         checkexit = ~0;
2781                 goto calleval;
2782         case NFOR:
2783                 evalfn = evalfor;
2784                 goto calleval;
2785         case NWHILE:
2786         case NUNTIL:
2787                 evalfn = evalloop;
2788                 goto calleval;
2789         case NSUBSHELL:
2790         case NBACKGND:
2791                 evalfn = evalsubshell;
2792                 goto calleval;
2793         case NPIPE:
2794                 evalfn = evalpipe;
2795                 goto checkexit;
2796         case NCASE:
2797                 evalfn = evalcase;
2798                 goto calleval;
2799         case NAND:
2800         case NOR:
2801         case NSEMI:
2802 #if NAND + 1 != NOR
2803 #error NAND + 1 != NOR
2804 #endif
2805 #if NOR + 1 != NSEMI
2806 #error NOR + 1 != NSEMI
2807 #endif
2808                 isor = n->type - NAND;
2809                 evaltree(
2810                         n->nbinary.ch1,
2811                         (flags | ((isor >> 1) - 1)) & EV_TESTED
2812                 );
2813                 if (!exitstatus == isor)
2814                         break;
2815                 if (!evalskip) {
2816                         n = n->nbinary.ch2;
2817 evaln:
2818                         evalfn = evaltree;
2819 calleval:
2820                         evalfn(n, flags);
2821                         break;
2822                 }
2823                 break;
2824         case NIF:
2825                 evaltree(n->nif.test, EV_TESTED);
2826                 if (evalskip)
2827                         break;
2828                 if (exitstatus == 0) {
2829                         n = n->nif.ifpart;
2830                         goto evaln;
2831                 } else if (n->nif.elsepart) {
2832                         n = n->nif.elsepart;
2833                         goto evaln;
2834                 }
2835                 goto success;
2836         case NDEFUN:
2837                 defun(n->narg.text, n->narg.next);
2838 success:
2839                 status = 0;
2840 setstatus:
2841                 exitstatus = status;
2842                 break;
2843         }
2844 out:
2845         if (pendingsigs)
2846                 dotrap();
2847         if (flags & EV_EXIT || checkexit & exitstatus)
2848                 exraise(EXEXIT);
2849 }
2850
2851
2852 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2853 static
2854 #endif
2855 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2856
2857
2858 static void
2859 evalloop(union node *n, int flags)
2860 {
2861         int status;
2862
2863         loopnest++;
2864         status = 0;
2865         flags &= EV_TESTED;
2866         for (;;) {
2867                 int i;
2868
2869                 evaltree(n->nbinary.ch1, EV_TESTED);
2870                 if (evalskip) {
2871 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
2872                                 evalskip = 0;
2873                                 continue;
2874                         }
2875                         if (evalskip == SKIPBREAK && --skipcount <= 0)
2876                                 evalskip = 0;
2877                         break;
2878                 }
2879                 i = exitstatus;
2880                 if (n->type != NWHILE)
2881                         i = !i;
2882                 if (i != 0)
2883                         break;
2884                 evaltree(n->nbinary.ch2, flags);
2885                 status = exitstatus;
2886                 if (evalskip)
2887                         goto skipping;
2888         }
2889         loopnest--;
2890         exitstatus = status;
2891 }
2892
2893
2894
2895 static void
2896 evalfor(union node *n, int flags)
2897 {
2898         struct arglist arglist;
2899         union node *argp;
2900         struct strlist *sp;
2901         struct stackmark smark;
2902
2903         setstackmark(&smark);
2904         arglist.lastp = &arglist.list;
2905         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2906                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2907                 /* XXX */
2908                 if (evalskip)
2909                         goto out;
2910         }
2911         *arglist.lastp = NULL;
2912
2913         exitstatus = 0;
2914         loopnest++;
2915         flags &= EV_TESTED;
2916         for (sp = arglist.list ; sp ; sp = sp->next) {
2917                 setvar(n->nfor.var, sp->text, 0);
2918                 evaltree(n->nfor.body, flags);
2919                 if (evalskip) {
2920                         if (evalskip == SKIPCONT && --skipcount <= 0) {
2921                                 evalskip = 0;
2922                                 continue;
2923                         }
2924                         if (evalskip == SKIPBREAK && --skipcount <= 0)
2925                                 evalskip = 0;
2926                         break;
2927                 }
2928         }
2929         loopnest--;
2930 out:
2931         popstackmark(&smark);
2932 }
2933
2934
2935
2936 static void
2937 evalcase(union node *n, int flags)
2938 {
2939         union node *cp;
2940         union node *patp;
2941         struct arglist arglist;
2942         struct stackmark smark;
2943
2944         setstackmark(&smark);
2945         arglist.lastp = &arglist.list;
2946         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2947         exitstatus = 0;
2948         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2949                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2950                         if (casematch(patp, arglist.list->text)) {
2951                                 if (evalskip == 0) {
2952                                         evaltree(cp->nclist.body, flags);
2953                                 }
2954                                 goto out;
2955                         }
2956                 }
2957         }
2958 out:
2959         popstackmark(&smark);
2960 }
2961
2962
2963
2964 /*
2965  * Kick off a subshell to evaluate a tree.
2966  */
2967
2968 static void
2969 evalsubshell(union node *n, int flags)
2970 {
2971         struct job *jp;
2972         int backgnd = (n->type == NBACKGND);
2973         int status;
2974
2975         expredir(n->nredir.redirect);
2976         if (!backgnd && flags & EV_EXIT && !trap[0])
2977                 goto nofork;
2978         INTOFF;
2979         jp = makejob(n, 1);
2980         if (forkshell(jp, n, backgnd) == 0) {
2981                 INTON;
2982                 flags |= EV_EXIT;
2983                 if (backgnd)
2984                         flags &=~ EV_TESTED;
2985 nofork:
2986                 redirect(n->nredir.redirect, 0);
2987                 evaltreenr(n->nredir.n, flags);
2988                 /* never returns */
2989         }
2990         status = 0;
2991         if (! backgnd)
2992                 status = waitforjob(jp);
2993         exitstatus = status;
2994         INTON;
2995 }
2996
2997
2998
2999 /*
3000  * Compute the names of the files in a redirection list.
3001  */
3002
3003 static void
3004 expredir(union node *n)
3005 {
3006         union node *redir;
3007
3008         for (redir = n ; redir ; redir = redir->nfile.next) {
3009                 struct arglist fn;
3010                 fn.lastp = &fn.list;
3011                 switch (redir->type) {
3012                 case NFROMTO:
3013                 case NFROM:
3014                 case NTO:
3015                 case NCLOBBER:
3016                 case NAPPEND:
3017                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3018                         redir->nfile.expfname = fn.list->text;
3019                         break;
3020                 case NFROMFD:
3021                 case NTOFD:
3022                         if (redir->ndup.vname) {
3023                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3024                                 fixredir(redir, fn.list->text, 1);
3025                         }
3026                         break;
3027                 }
3028         }
3029 }
3030
3031
3032
3033 /*
3034  * Evaluate a pipeline.  All the processes in the pipeline are children
3035  * of the process creating the pipeline.  (This differs from some versions
3036  * of the shell, which make the last process in a pipeline the parent
3037  * of all the rest.)
3038  */
3039
3040 static void
3041 evalpipe(union node *n, int flags)
3042 {
3043         struct job *jp;
3044         struct nodelist *lp;
3045         int pipelen;
3046         int prevfd;
3047         int pip[2];
3048
3049         TRACE(("evalpipe(0x%lx) called\n", (long)n));
3050         pipelen = 0;
3051         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3052                 pipelen++;
3053         flags |= EV_EXIT;
3054         INTOFF;
3055         jp = makejob(n, pipelen);
3056         prevfd = -1;
3057         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3058                 prehash(lp->n);
3059                 pip[1] = -1;
3060                 if (lp->next) {
3061                         if (pipe(pip) < 0) {
3062                                 close(prevfd);
3063                                 error("Pipe call failed");
3064                         }
3065                 }
3066                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3067                         INTON;
3068                         if (pip[1] >= 0) {
3069                                 close(pip[0]);
3070                         }
3071                         if (prevfd > 0) {
3072                                 dup2(prevfd, 0);
3073                                 close(prevfd);
3074                         }
3075                         if (pip[1] > 1) {
3076                                 dup2(pip[1], 1);
3077                                 close(pip[1]);
3078                         }
3079                         evaltreenr(lp->n, flags);
3080                         /* never returns */
3081                 }
3082                 if (prevfd >= 0)
3083                         close(prevfd);
3084                 prevfd = pip[0];
3085                 close(pip[1]);
3086         }
3087         if (n->npipe.backgnd == 0) {
3088                 exitstatus = waitforjob(jp);
3089                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
3090         }
3091         INTON;
3092 }
3093
3094
3095
3096 /*
3097  * Execute a command inside back quotes.  If it's a builtin command, we
3098  * want to save its output in a block obtained from malloc.  Otherwise
3099  * we fork off a subprocess and get the output of the command via a pipe.
3100  * Should be called with interrupts off.
3101  */
3102
3103 static void
3104 evalbackcmd(union node *n, struct backcmd *result)
3105 {
3106         int saveherefd;
3107
3108         result->fd = -1;
3109         result->buf = NULL;
3110         result->nleft = 0;
3111         result->jp = NULL;
3112         if (n == NULL) {
3113                 goto out;
3114         }
3115
3116         saveherefd = herefd;
3117         herefd = -1;
3118
3119         {
3120                 int pip[2];
3121                 struct job *jp;
3122
3123                 if (pipe(pip) < 0)
3124                         error("Pipe call failed");
3125                 jp = makejob(n, 1);
3126                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3127                         FORCEINTON;
3128                         close(pip[0]);
3129                         if (pip[1] != 1) {
3130                                 close(1);
3131                                 copyfd(pip[1], 1);
3132                                 close(pip[1]);
3133                         }
3134                         eflag = 0;
3135                         evaltreenr(n, EV_EXIT);
3136                         /* NOTREACHED */
3137                 }
3138                 close(pip[1]);
3139                 result->fd = pip[0];
3140                 result->jp = jp;
3141         }
3142         herefd = saveherefd;
3143 out:
3144         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3145                 result->fd, result->buf, result->nleft, result->jp));
3146 }
3147
3148 #ifdef CONFIG_ASH_CMDCMD
3149 static inline char **
3150 parse_command_args(char **argv, const char **path)
3151 {
3152         char *cp, c;
3153
3154         for (;;) {
3155                 cp = *++argv;
3156                 if (!cp)
3157                         return 0;
3158                 if (*cp++ != '-')
3159                         break;
3160                 if (!(c = *cp++))
3161                         break;
3162                 if (c == '-' && !*cp) {
3163                         argv++;
3164                         break;
3165                 }
3166                 do {
3167                         switch (c) {
3168                         case 'p':
3169                                 *path = defpath;
3170                                 break;
3171                         default:
3172                                 /* run 'typecmd' for other options */
3173                                 return 0;
3174                         }
3175                 } while ((c = *cp++));
3176         }
3177         return argv;
3178 }
3179 #endif
3180
3181
3182
3183 /*
3184  * Execute a simple command.
3185  */
3186
3187 static void
3188 evalcommand(union node *cmd, int flags)
3189 {
3190         struct stackmark smark;
3191         union node *argp;
3192         struct arglist arglist;
3193         struct arglist varlist;
3194         char **argv;
3195         int argc;
3196         const struct strlist *sp;
3197         struct cmdentry cmdentry;
3198         struct job *jp;
3199         char *lastarg;
3200         const char *path;
3201         int spclbltin;
3202         int cmd_is_exec;
3203         int status;
3204         char **nargv;
3205
3206         /* First expand the arguments. */
3207         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3208         setstackmark(&smark);
3209         back_exitstatus = 0;
3210
3211         cmdentry.cmdtype = CMDBUILTIN;
3212         cmdentry.u.cmd = &bltin;
3213         varlist.lastp = &varlist.list;
3214         *varlist.lastp = NULL;
3215         arglist.lastp = &arglist.list;
3216         *arglist.lastp = NULL;
3217
3218         argc = 0;
3219         for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3220                 struct strlist **spp;
3221
3222                 spp = arglist.lastp;
3223                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3224                 for (sp = *spp; sp; sp = sp->next)
3225                         argc++;
3226         }
3227
3228         argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3229         for (sp = arglist.list ; sp ; sp = sp->next) {
3230                 TRACE(("evalcommand arg: %s\n", sp->text));
3231                 *nargv++ = sp->text;
3232         }
3233         *nargv = NULL;
3234
3235         lastarg = NULL;
3236         if (iflag && funcnest == 0 && argc > 0)
3237                 lastarg = nargv[-1];
3238
3239         preverrout_fd = 2;
3240         expredir(cmd->ncmd.redirect);
3241         status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3242
3243         path = vpath.text;
3244         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3245                 struct strlist **spp;
3246                 char *p;
3247
3248                 spp = varlist.lastp;
3249                 expandarg(argp, &varlist, EXP_VARTILDE);
3250
3251                 /*
3252                  * Modify the command lookup path, if a PATH= assignment
3253                  * is present
3254                  */
3255                 p = (*spp)->text;
3256                 if (varequal(p, path))
3257                         path = p;
3258         }
3259
3260         /* Print the command if xflag is set. */
3261         if (xflag) {
3262                 int n;
3263                 const char *p = " %s";
3264
3265                 p++;
3266                 dprintf(preverrout_fd, p, ps4val());
3267
3268                 sp = varlist.list;
3269                 for(n = 0; n < 2; n++) {
3270                         while (sp) {
3271                                 dprintf(preverrout_fd, p, sp->text);
3272                                 sp = sp->next;
3273                                 if(*p == '%') {
3274                                         p--;
3275                                 }
3276                         }
3277                         sp = arglist.list;
3278                 }
3279                 xwrite(preverrout_fd, "\n", 1);
3280         }
3281
3282         cmd_is_exec = 0;
3283         spclbltin = -1;
3284
3285         /* Now locate the command. */
3286         if (argc) {
3287                 const char *oldpath;
3288                 int cmd_flag = DO_ERR;
3289
3290                 path += 5;
3291                 oldpath = path;
3292                 for (;;) {
3293                         find_command(argv[0], &cmdentry, cmd_flag, path);
3294                         if (cmdentry.cmdtype == CMDUNKNOWN) {
3295                                 status = 127;
3296                                 flushout(stderr);
3297                                 goto bail;
3298                         }
3299
3300                         /* implement bltin and command here */
3301                         if (cmdentry.cmdtype != CMDBUILTIN)
3302                                 break;
3303                         if (spclbltin < 0)
3304                                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3305                         if (cmdentry.u.cmd == EXECCMD)
3306                                 cmd_is_exec++;
3307 #ifdef CONFIG_ASH_CMDCMD
3308                         if (cmdentry.u.cmd == COMMANDCMD) {
3309
3310                                 path = oldpath;
3311                                 nargv = parse_command_args(argv, &path);
3312                                 if (!nargv)
3313                                         break;
3314                                 argc -= nargv - argv;
3315                                 argv = nargv;
3316                                 cmd_flag |= DO_NOFUNC;
3317                         } else
3318 #endif
3319                                 break;
3320                 }
3321         }
3322
3323         if (status) {
3324                 /* We have a redirection error. */
3325                 if (spclbltin > 0)
3326                         exraise(EXERROR);
3327 bail:
3328                 exitstatus = status;
3329                 goto out;
3330         }
3331
3332         /* Execute the command. */
3333         switch (cmdentry.cmdtype) {
3334         default:
3335                 /* Fork off a child process if necessary. */
3336                 if (!(flags & EV_EXIT) || trap[0]) {
3337                         INTOFF;
3338                         jp = makejob(cmd, 1);
3339                         if (forkshell(jp, cmd, FORK_FG) != 0) {
3340                                 exitstatus = waitforjob(jp);
3341                                 INTON;
3342                                 break;
3343                         }
3344                         FORCEINTON;
3345                 }
3346                 listsetvar(varlist.list, VEXPORT|VSTACK);
3347                 shellexec(argv, path, cmdentry.u.index);
3348                 /* NOTREACHED */
3349
3350         case CMDBUILTIN:
3351                 cmdenviron = varlist.list;
3352                 if (cmdenviron) {
3353                         struct strlist *list = cmdenviron;
3354                         int i = VNOSET;
3355                         if (spclbltin > 0 || argc == 0) {
3356                                 i = 0;
3357                                 if (cmd_is_exec && argc > 1)
3358                                         i = VEXPORT;
3359                         }
3360                         listsetvar(list, i);
3361                 }
3362                 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3363                         int exit_status;
3364                         int i, j;
3365
3366                         i = exception;
3367                         if (i == EXEXIT)
3368                                 goto raise;
3369
3370                         exit_status = 2;
3371                         j = 0;
3372                         if (i == EXINT)
3373                                 j = SIGINT;
3374                         if (i == EXSIG)
3375                                 j = pendingsigs;
3376                         if (j)
3377                                 exit_status = j + 128;
3378                         exitstatus = exit_status;
3379
3380                         if (i == EXINT || spclbltin > 0) {
3381 raise:
3382                                 longjmp(handler->loc, 1);
3383                         }
3384                         FORCEINTON;
3385                 }
3386                 break;
3387
3388         case CMDFUNCTION:
3389                 listsetvar(varlist.list, 0);
3390                 if (evalfun(cmdentry.u.func, argc, argv, flags))
3391                         goto raise;
3392                 break;
3393         }
3394
3395 out:
3396         popredir(cmd_is_exec);
3397         if (lastarg)
3398                 /* dsl: I think this is intended to be used to support
3399                  * '_' in 'vi' command mode during line editing...
3400                  * However I implemented that within libedit itself.
3401                  */
3402                 setvar("_", lastarg, 0);
3403         popstackmark(&smark);
3404 }
3405
3406 static int
3407 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3408         char *volatile savecmdname;
3409         struct jmploc *volatile savehandler;
3410         struct jmploc jmploc;
3411         int i;
3412
3413         savecmdname = commandname;
3414         if ((i = setjmp(jmploc.loc)))
3415                 goto cmddone;
3416         savehandler = handler;
3417         handler = &jmploc;
3418         commandname = argv[0];
3419         argptr = argv + 1;
3420         optptr = NULL;                  /* initialize nextopt */
3421         exitstatus = (*cmd->builtin)(argc, argv);
3422         flushall();
3423 cmddone:
3424         exitstatus |= ferror(stdout);
3425         commandname = savecmdname;
3426         exsig = 0;
3427         handler = savehandler;
3428
3429         return i;
3430 }
3431
3432 static int
3433 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3434 {
3435         volatile struct shparam saveparam;
3436         struct localvar *volatile savelocalvars;
3437         struct jmploc *volatile savehandler;
3438         struct jmploc jmploc;
3439         int e;
3440
3441         saveparam = shellparam;
3442         savelocalvars = localvars;
3443         if ((e = setjmp(jmploc.loc))) {
3444                 goto funcdone;
3445         }
3446         INTOFF;
3447         savehandler = handler;
3448         handler = &jmploc;
3449         localvars = NULL;
3450         shellparam.malloc = 0;
3451         func->count++;
3452         INTON;
3453         shellparam.nparam = argc - 1;
3454         shellparam.p = argv + 1;
3455 #ifdef CONFIG_ASH_GETOPTS
3456         shellparam.optind = 1;
3457         shellparam.optoff = -1;
3458 #endif
3459         funcnest++;
3460         evaltree(&func->n, flags & EV_TESTED);
3461         funcnest--;
3462 funcdone:
3463         INTOFF;
3464         freefunc(func);
3465         poplocalvars();
3466         localvars = savelocalvars;
3467         freeparam(&shellparam);
3468         shellparam = saveparam;
3469         handler = savehandler;
3470         INTON;
3471         if (evalskip == SKIPFUNC) {
3472                 evalskip = 0;
3473                 skipcount = 0;
3474         }
3475         return e;
3476 }
3477
3478
3479 /*
3480  * Search for a command.  This is called before we fork so that the
3481  * location of the command will be available in the parent as well as
3482  * the child.
3483  */
3484
3485 static void
3486 prehash(union node *n)
3487 {
3488         struct cmdentry entry;
3489
3490         if (n->type == NCMD && n->ncmd.args)
3491                 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
3492 }
3493
3494
3495
3496 /*
3497  * Builtin commands.  Builtin commands whose functions are closely
3498  * tied to evaluation are implemented here.
3499  */
3500
3501 /*
3502  * No command given.
3503  */
3504
3505 static int
3506 bltincmd(int argc, char **argv)
3507 {
3508         /*
3509          * Preserve exitstatus of a previous possible redirection
3510          * as POSIX mandates
3511          */
3512         return back_exitstatus;
3513 }
3514
3515
3516 /*
3517  * Handle break and continue commands.  Break, continue, and return are
3518  * all handled by setting the evalskip flag.  The evaluation routines
3519  * above all check this flag, and if it is set they start skipping
3520  * commands rather than executing them.  The variable skipcount is
3521  * the number of loops to break/continue, or the number of function
3522  * levels to return.  (The latter is always 1.)  It should probably
3523  * be an error to break out of more loops than exist, but it isn't
3524  * in the standard shell so we don't make it one here.
3525  */
3526
3527 static int
3528 breakcmd(int argc, char **argv)
3529 {
3530         int n = argc > 1 ? number(argv[1]) : 1;
3531
3532         if (n <= 0)
3533                 error(illnum, argv[1]);
3534         if (n > loopnest)
3535                 n = loopnest;
3536         if (n > 0) {
3537                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3538                 skipcount = n;
3539         }
3540         return 0;
3541 }
3542
3543
3544 /*
3545  * The return command.
3546  */
3547
3548 static int
3549 returncmd(int argc, char **argv)
3550 {
3551         int ret = argc > 1 ? number(argv[1]) : exitstatus;
3552
3553         if (funcnest) {
3554                 evalskip = SKIPFUNC;
3555                 skipcount = 1;
3556                 return ret;
3557         }
3558         else {
3559                 /* Do what ksh does; skip the rest of the file */
3560                 evalskip = SKIPFILE;
3561                 skipcount = 1;
3562                 return ret;
3563         }
3564 }
3565
3566
3567 static int
3568 falsecmd(int argc, char **argv)
3569 {
3570         return 1;
3571 }
3572
3573
3574 static int
3575 truecmd(int argc, char **argv)
3576 {
3577         return 0;
3578 }
3579
3580
3581 static int
3582 execcmd(int argc, char **argv)
3583 {
3584         if (argc > 1) {
3585                 iflag = 0;              /* exit on error */
3586                 mflag = 0;
3587                 optschanged();
3588                 shellexec(argv + 1, pathval(), 0);
3589         }
3590         return 0;
3591 }
3592
3593
3594 /*      $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $    */
3595
3596 /*
3597  * When commands are first encountered, they are entered in a hash table.
3598  * This ensures that a full path search will not have to be done for them
3599  * on each invocation.
3600  *
3601  * We should investigate converting to a linear search, even though that
3602  * would make the command name "hash" a misnomer.
3603  */
3604
3605 #define CMDTABLESIZE 31         /* should be prime */
3606 #define ARB 1                   /* actual size determined at run time */
3607
3608
3609
3610 struct tblentry {
3611         struct tblentry *next;  /* next entry in hash chain */
3612         union param param;      /* definition of builtin function */
3613         short cmdtype;          /* index identifying command */
3614         char rehash;            /* if set, cd done since entry created */
3615         char cmdname[ARB];      /* name of command */
3616 };
3617
3618
3619 static struct tblentry *cmdtable[CMDTABLESIZE];
3620 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
3621
3622
3623 static void tryexec(char *, char **, char **);
3624 static void clearcmdentry(int);
3625 static struct tblentry *cmdlookup(const char *, int);
3626 static void delete_cmd_entry(void);
3627
3628
3629 /*
3630  * Exec a program.  Never returns.  If you change this routine, you may
3631  * have to change the find_command routine as well.
3632  */
3633
3634 static void
3635 shellexec(char **argv, const char *path, int idx)
3636 {
3637         char *cmdname;
3638         int e;
3639         char **envp;
3640
3641         clearredir(1);
3642         envp = environment();
3643         if (strchr(argv[0], '/') != NULL
3644 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3645                 || find_applet_by_name(argv[0])
3646 #endif
3647                                                 ) {
3648                 tryexec(argv[0], argv, envp);
3649                 e = errno;
3650         } else {
3651                 e = ENOENT;
3652                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3653                         if (--idx < 0 && pathopt == NULL) {
3654                                 tryexec(cmdname, argv, envp);
3655                                 if (errno != ENOENT && errno != ENOTDIR)
3656                                         e = errno;
3657                         }
3658                         stunalloc(cmdname);
3659                 }
3660         }
3661
3662         /* Map to POSIX errors */
3663         switch (e) {
3664         case EACCES:
3665                 exerrno = 126;
3666                 break;
3667         case ENOENT:
3668                 exerrno = 127;
3669                 break;
3670         default:
3671                 exerrno = 2;
3672                 break;
3673         }
3674         TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3675                 argv[0], e, suppressint ));
3676         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3677         /* NOTREACHED */
3678 }
3679
3680
3681 static void
3682 tryexec(char *cmd, char **argv, char **envp)
3683 {
3684         int repeated = 0;
3685 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3686         int flg_bb = 0;
3687         char *name = cmd;
3688
3689 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3690         name = bb_get_last_path_component(name);
3691         if(find_applet_by_name(name) != NULL)
3692                 flg_bb = 1;
3693 #else
3694         if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3695                 flg_bb = 1;
3696         }
3697 #endif
3698         if(flg_bb) {
3699                 char **ap;
3700                 char **new;
3701
3702                 *argv = name;
3703                 if(strcmp(name, "busybox")) {
3704                         for (ap = argv; *ap; ap++);
3705                         ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3706                         *ap++ = cmd = "/bin/busybox";
3707                         while ((*ap++ = *argv++));
3708                         argv = new;
3709                         repeated++;
3710                 } else {
3711                         cmd = "/bin/busybox";
3712                 }
3713         }
3714 #endif
3715
3716 repeat:
3717 #ifdef SYSV
3718         do {
3719                 execve(cmd, argv, envp);
3720         } while (errno == EINTR);
3721 #else
3722         execve(cmd, argv, envp);
3723 #endif
3724         if (repeated++) {
3725                 ckfree(argv);
3726         } else if (errno == ENOEXEC) {
3727                 char **ap;
3728                 char **new;
3729
3730                 for (ap = argv; *ap; ap++)
3731                         ;
3732                 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3733                 ap[1] = cmd;
3734                 *ap = cmd = (char *)DEFAULT_SHELL;
3735                 ap += 2;
3736                 argv++;
3737                 while ((*ap++ = *argv++))
3738                         ;
3739                 argv = new;
3740                 goto repeat;
3741         }
3742 }
3743
3744
3745
3746 /*
3747  * Do a path search.  The variable path (passed by reference) should be
3748  * set to the start of the path before the first call; padvance will update
3749  * this value as it proceeds.  Successive calls to padvance will return
3750  * the possible path expansions in sequence.  If an option (indicated by
3751  * a percent sign) appears in the path entry then the global variable
3752  * pathopt will be set to point to it; otherwise pathopt will be set to
3753  * NULL.
3754  */
3755
3756 static char *
3757 padvance(const char **path, const char *name)
3758 {
3759         const char *p;
3760         char *q;
3761         const char *start;
3762         size_t len;
3763
3764         if (*path == NULL)
3765                 return NULL;
3766         start = *path;
3767         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3768         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
3769         while (stackblocksize() < len)
3770                 growstackblock();
3771         q = stackblock();
3772         if (p != start) {
3773                 memcpy(q, start, p - start);
3774                 q += p - start;
3775                 *q++ = '/';
3776         }
3777         strcpy(q, name);
3778         pathopt = NULL;
3779         if (*p == '%') {
3780                 pathopt = ++p;
3781                 while (*p && *p != ':')  p++;
3782         }
3783         if (*p == ':')
3784                 *path = p + 1;
3785         else
3786                 *path = NULL;
3787         return stalloc(len);
3788 }
3789
3790
3791 /*** Command hashing code ***/
3792
3793 static void
3794 printentry(struct tblentry *cmdp)
3795 {
3796         int idx;
3797         const char *path;
3798         char *name;
3799
3800         idx = cmdp->param.index;
3801         path = pathval();
3802         do {
3803                 name = padvance(&path, cmdp->cmdname);
3804                 stunalloc(name);
3805         } while (--idx >= 0);
3806         out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3807 }
3808
3809
3810 static int
3811 hashcmd(int argc, char **argv)
3812 {
3813         struct tblentry **pp;
3814         struct tblentry *cmdp;
3815         int c;
3816         struct cmdentry entry;
3817         char *name;
3818
3819         while ((c = nextopt("r")) != '\0') {
3820                 clearcmdentry(0);
3821                 return 0;
3822         }
3823         if (*argptr == NULL) {
3824                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3825                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3826                                 if (cmdp->cmdtype == CMDNORMAL)
3827                                         printentry(cmdp);
3828                         }
3829                 }
3830                 return 0;
3831         }
3832         c = 0;
3833         while ((name = *argptr) != NULL) {
3834                 if ((cmdp = cmdlookup(name, 0)) != NULL
3835                  && (cmdp->cmdtype == CMDNORMAL
3836                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3837                         delete_cmd_entry();
3838                 find_command(name, &entry, DO_ERR, pathval());
3839                 if (entry.cmdtype == CMDUNKNOWN)
3840                         c = 1;
3841                 argptr++;
3842         }
3843         return c;
3844 }
3845
3846
3847 /*
3848  * Resolve a command name.  If you change this routine, you may have to
3849  * change the shellexec routine as well.
3850  */
3851
3852 static void
3853 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3854 {
3855         struct tblentry *cmdp;
3856         int idx;
3857         int prev;
3858         char *fullname;
3859         struct stat statb;
3860         int e;
3861         int updatetbl;
3862         struct builtincmd *bcmd;
3863
3864         /* If name contains a slash, don't use PATH or hash table */
3865         if (strchr(name, '/') != NULL) {
3866                 entry->u.index = -1;
3867                 if (act & DO_ABS) {
3868                         while (stat(name, &statb) < 0) {
3869 #ifdef SYSV
3870                                 if (errno == EINTR)
3871                                         continue;
3872 #endif
3873                                 entry->cmdtype = CMDUNKNOWN;
3874                                 return;
3875                         }
3876                 }
3877                 entry->cmdtype = CMDNORMAL;
3878                 return;
3879         }
3880
3881 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3882         if (find_applet_by_name(name)) {
3883                 entry->cmdtype = CMDNORMAL;
3884                 entry->u.index = -1;
3885                 return;
3886         }
3887 #endif
3888
3889         updatetbl = (path == pathval());
3890         if (!updatetbl) {
3891                 act |= DO_ALTPATH;
3892                 if (strstr(path, "%builtin") != NULL)
3893                         act |= DO_ALTBLTIN;
3894         }
3895
3896         /* If name is in the table, check answer will be ok */
3897         if ((cmdp = cmdlookup(name, 0)) != NULL) {
3898                 int bit;
3899
3900                 switch (cmdp->cmdtype) {
3901                 default:
3902 #if DEBUG
3903                         abort();
3904 #endif
3905                 case CMDNORMAL:
3906                         bit = DO_ALTPATH;
3907                         break;
3908                 case CMDFUNCTION:
3909                         bit = DO_NOFUNC;
3910                         break;
3911                 case CMDBUILTIN:
3912                         bit = DO_ALTBLTIN;
3913                         break;
3914                 }
3915                 if (act & bit) {
3916                         updatetbl = 0;
3917                         cmdp = NULL;
3918                 } else if (cmdp->rehash == 0)
3919                         /* if not invalidated by cd, we're done */
3920                         goto success;
3921         }
3922
3923         /* If %builtin not in path, check for builtin next */
3924         bcmd = find_builtin(name);
3925         if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3926                 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3927         )))
3928                 goto builtin_success;
3929
3930         /* We have to search path. */
3931         prev = -1;              /* where to start */
3932         if (cmdp && cmdp->rehash) {     /* doing a rehash */
3933                 if (cmdp->cmdtype == CMDBUILTIN)
3934                         prev = builtinloc;
3935                 else
3936                         prev = cmdp->param.index;
3937         }
3938
3939         e = ENOENT;
3940         idx = -1;
3941 loop:
3942         while ((fullname = padvance(&path, name)) != NULL) {
3943                 stunalloc(fullname);
3944                 idx++;
3945                 if (pathopt) {
3946                         if (prefix(pathopt, "builtin")) {
3947                                 if (bcmd)
3948                                         goto builtin_success;
3949                                 continue;
3950                         } else if (!(act & DO_NOFUNC) &&
3951                                    prefix(pathopt, "func")) {
3952                                 /* handled below */
3953                         } else {
3954                                 /* ignore unimplemented options */
3955                                 continue;
3956                         }
3957                 }
3958                 /* if rehash, don't redo absolute path names */
3959                 if (fullname[0] == '/' && idx <= prev) {
3960                         if (idx < prev)
3961                                 continue;
3962                         TRACE(("searchexec \"%s\": no change\n", name));
3963                         goto success;
3964                 }
3965                 while (stat(fullname, &statb) < 0) {
3966 #ifdef SYSV
3967                         if (errno == EINTR)
3968                                 continue;
3969 #endif
3970                         if (errno != ENOENT && errno != ENOTDIR)
3971                                 e = errno;
3972                         goto loop;
3973                 }
3974                 e = EACCES;     /* if we fail, this will be the error */
3975                 if (!S_ISREG(statb.st_mode))
3976                         continue;
3977                 if (pathopt) {          /* this is a %func directory */
3978                         stalloc(strlen(fullname) + 1);
3979                         readcmdfile(fullname);
3980                         if ((cmdp = cmdlookup(name, 0)) == NULL ||
3981                             cmdp->cmdtype != CMDFUNCTION)
3982                                 error("%s not defined in %s", name, fullname);
3983                         stunalloc(fullname);
3984                         goto success;
3985                 }
3986                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3987                 if (!updatetbl) {
3988                         entry->cmdtype = CMDNORMAL;
3989                         entry->u.index = idx;
3990                         return;
3991                 }
3992                 INTOFF;
3993                 cmdp = cmdlookup(name, 1);
3994                 cmdp->cmdtype = CMDNORMAL;
3995                 cmdp->param.index = idx;
3996                 INTON;
3997                 goto success;
3998         }
3999
4000         /* We failed.  If there was an entry for this command, delete it */
4001         if (cmdp && updatetbl)
4002                 delete_cmd_entry();
4003         if (act & DO_ERR)
4004                 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4005         entry->cmdtype = CMDUNKNOWN;
4006         return;
4007
4008 builtin_success:
4009         if (!updatetbl) {
4010                 entry->cmdtype = CMDBUILTIN;
4011                 entry->u.cmd = bcmd;
4012                 return;
4013         }
4014         INTOFF;
4015         cmdp = cmdlookup(name, 1);
4016         cmdp->cmdtype = CMDBUILTIN;
4017         cmdp->param.cmd = bcmd;
4018         INTON;
4019 success:
4020         cmdp->rehash = 0;
4021         entry->cmdtype = cmdp->cmdtype;
4022         entry->u = cmdp->param;
4023 }
4024
4025
4026 /*
4027  * Wrapper around strcmp for qsort/bsearch/...
4028  */
4029 static int pstrcmp(const void *a, const void *b)
4030 {
4031         return strcmp((const char *) a, (*(const char *const *) b) + 1);
4032 }
4033
4034 /*
4035  * Search the table of builtin commands.
4036  */
4037
4038 static struct builtincmd *
4039 find_builtin(const char *name)
4040 {
4041         struct builtincmd *bp;
4042
4043         bp = bsearch(
4044                 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4045                 pstrcmp
4046         );
4047         return bp;
4048 }
4049
4050
4051
4052 /*
4053  * Called when a cd is done.  Marks all commands so the next time they
4054  * are executed they will be rehashed.
4055  */
4056
4057 static void
4058 hashcd(void)
4059 {
4060         struct tblentry **pp;
4061         struct tblentry *cmdp;
4062
4063         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4064                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4065                         if (cmdp->cmdtype == CMDNORMAL || (
4066                                 cmdp->cmdtype == CMDBUILTIN &&
4067                                 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4068                                 builtinloc > 0
4069                         ))
4070                                 cmdp->rehash = 1;
4071                 }
4072         }
4073 }
4074
4075
4076
4077 /*
4078  * Fix command hash table when PATH changed.
4079  * Called before PATH is changed.  The argument is the new value of PATH;
4080  * pathval() still returns the old value at this point.
4081  * Called with interrupts off.
4082  */
4083
4084 static void
4085 changepath(const char *newval)
4086 {
4087         const char *old, *new;
4088         int idx;
4089         int firstchange;
4090         int idx_bltin;
4091
4092         old = pathval();
4093         new = newval;
4094         firstchange = 9999;     /* assume no change */
4095         idx = 0;
4096         idx_bltin = -1;
4097         for (;;) {
4098                 if (*old != *new) {
4099                         firstchange = idx;
4100                         if ((*old == '\0' && *new == ':')
4101                          || (*old == ':' && *new == '\0'))
4102                                 firstchange++;
4103                         old = new;      /* ignore subsequent differences */
4104                 }
4105                 if (*new == '\0')
4106                         break;
4107                 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4108                         idx_bltin = idx;
4109                 if (*new == ':') {
4110                         idx++;
4111                 }
4112                 new++, old++;
4113         }
4114         if (builtinloc < 0 && idx_bltin >= 0)
4115                 builtinloc = idx_bltin;             /* zap builtins */
4116         if (builtinloc >= 0 && idx_bltin < 0)
4117                 firstchange = 0;
4118         clearcmdentry(firstchange);
4119         builtinloc = idx_bltin;
4120 }
4121
4122
4123 /*
4124  * Clear out command entries.  The argument specifies the first entry in
4125  * PATH which has changed.
4126  */
4127
4128 static void
4129 clearcmdentry(int firstchange)
4130 {
4131         struct tblentry **tblp;
4132         struct tblentry **pp;
4133         struct tblentry *cmdp;
4134
4135         INTOFF;
4136         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4137                 pp = tblp;
4138                 while ((cmdp = *pp) != NULL) {
4139                         if ((cmdp->cmdtype == CMDNORMAL &&
4140                              cmdp->param.index >= firstchange)
4141                          || (cmdp->cmdtype == CMDBUILTIN &&
4142                              builtinloc >= firstchange)) {
4143                                 *pp = cmdp->next;
4144                                 ckfree(cmdp);
4145                         } else {
4146                                 pp = &cmdp->next;
4147                         }
4148                 }
4149         }
4150         INTON;
4151 }
4152
4153
4154
4155 /*
4156  * Locate a command in the command hash table.  If "add" is nonzero,
4157  * add the command to the table if it is not already present.  The
4158  * variable "lastcmdentry" is set to point to the address of the link
4159  * pointing to the entry, so that delete_cmd_entry can delete the
4160  * entry.
4161  *
4162  * Interrupts must be off if called with add != 0.
4163  */
4164
4165 static struct tblentry **lastcmdentry;
4166
4167
4168 static struct tblentry *
4169 cmdlookup(const char *name, int add)
4170 {
4171         unsigned int hashval;
4172         const char *p;
4173         struct tblentry *cmdp;
4174         struct tblentry **pp;
4175
4176         p = name;
4177         hashval = (unsigned char)*p << 4;
4178         while (*p)
4179                 hashval += (unsigned char)*p++;
4180         hashval &= 0x7FFF;
4181         pp = &cmdtable[hashval % CMDTABLESIZE];
4182         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4183                 if (equal(cmdp->cmdname, name))
4184                         break;
4185                 pp = &cmdp->next;
4186         }
4187         if (add && cmdp == NULL) {
4188                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4189                                         + strlen(name) + 1);
4190                 cmdp->next = NULL;
4191                 cmdp->cmdtype = CMDUNKNOWN;
4192                 strcpy(cmdp->cmdname, name);
4193         }
4194         lastcmdentry = pp;
4195         return cmdp;
4196 }
4197
4198 /*
4199  * Delete the command entry returned on the last lookup.
4200  */
4201
4202 static void
4203 delete_cmd_entry(void)
4204 {
4205         struct tblentry *cmdp;
4206
4207         INTOFF;
4208         cmdp = *lastcmdentry;
4209         *lastcmdentry = cmdp->next;
4210         if (cmdp->cmdtype == CMDFUNCTION)
4211                 freefunc(cmdp->param.func);
4212         ckfree(cmdp);
4213         INTON;
4214 }
4215
4216
4217 /*
4218  * Add a new command entry, replacing any existing command entry for
4219  * the same name - except special builtins.
4220  */
4221
4222 static inline void
4223 addcmdentry(char *name, struct cmdentry *entry)
4224 {
4225         struct tblentry *cmdp;
4226
4227         cmdp = cmdlookup(name, 1);
4228         if (cmdp->cmdtype == CMDFUNCTION) {
4229                 freefunc(cmdp->param.func);
4230         }
4231         cmdp->cmdtype = entry->cmdtype;
4232         cmdp->param = entry->u;
4233         cmdp->rehash = 0;
4234 }
4235
4236 /*
4237  * Make a copy of a parse tree.
4238  */
4239
4240 static inline struct funcnode *
4241 copyfunc(union node *n)
4242 {
4243         struct funcnode *f;
4244         size_t blocksize;
4245
4246         funcblocksize = offsetof(struct funcnode, n);
4247         funcstringsize = 0;
4248         calcsize(n);
4249         blocksize = funcblocksize;
4250         f = ckmalloc(blocksize + funcstringsize);
4251         funcblock = (char *) f + offsetof(struct funcnode, n);
4252         funcstring = (char *) f + blocksize;
4253         copynode(n);
4254         f->count = 0;
4255         return f;
4256 }
4257
4258 /*
4259  * Define a shell function.
4260  */
4261
4262 static void
4263 defun(char *name, union node *func)
4264 {
4265         struct cmdentry entry;
4266
4267         INTOFF;
4268         entry.cmdtype = CMDFUNCTION;
4269         entry.u.func = copyfunc(func);
4270         addcmdentry(name, &entry);
4271         INTON;
4272 }
4273
4274
4275 /*
4276  * Delete a function if it exists.
4277  */
4278
4279 static void
4280 unsetfunc(const char *name)
4281 {
4282         struct tblentry *cmdp;
4283
4284         if ((cmdp = cmdlookup(name, 0)) != NULL &&
4285             cmdp->cmdtype == CMDFUNCTION)
4286                 delete_cmd_entry();
4287 }
4288
4289 /*
4290  * Locate and print what a word is...
4291  */
4292
4293
4294 #ifdef CONFIG_ASH_CMDCMD
4295 static int
4296 describe_command(char *command, int describe_command_verbose)
4297 #else
4298 #define describe_command_verbose 1
4299 static int
4300 describe_command(char *command)
4301 #endif
4302 {
4303         struct cmdentry entry;
4304         struct tblentry *cmdp;
4305 #ifdef CONFIG_ASH_ALIAS
4306         const struct alias *ap;
4307 #endif
4308         const char *path = pathval();
4309
4310         if (describe_command_verbose) {
4311                 out1str(command);
4312         }
4313
4314         /* First look at the keywords */
4315         if (findkwd(command)) {
4316                 out1str(describe_command_verbose ? " is a shell keyword" : command);
4317                 goto out;
4318         }
4319
4320 #ifdef CONFIG_ASH_ALIAS
4321         /* Then look at the aliases */
4322         if ((ap = lookupalias(command, 0)) != NULL) {
4323                 if (describe_command_verbose) {
4324                         out1fmt(" is an alias for %s", ap->val);
4325                 } else {
4326                         out1str("alias ");
4327                         printalias(ap);
4328                         return 0;
4329                 }
4330                 goto out;
4331         }
4332 #endif
4333         /* Then check if it is a tracked alias */
4334         if ((cmdp = cmdlookup(command, 0)) != NULL) {
4335                 entry.cmdtype = cmdp->cmdtype;
4336                 entry.u = cmdp->param;
4337         } else {
4338                 /* Finally use brute force */
4339                 find_command(command, &entry, DO_ABS, path);
4340         }
4341
4342         switch (entry.cmdtype) {
4343         case CMDNORMAL: {
4344                 int j = entry.u.index;
4345                 char *p;
4346                 if (j == -1) {
4347                         p = command;
4348                 } else {
4349                         do {
4350                                 p = padvance(&path, command);
4351                                 stunalloc(p);
4352                         } while (--j >= 0);
4353                 }
4354                 if (describe_command_verbose) {
4355                         out1fmt(" is%s %s",
4356                                 (cmdp ? " a tracked alias for" : nullstr), p
4357                         );
4358                 } else {
4359                         out1str(p);
4360                 }
4361                 break;
4362         }
4363
4364         case CMDFUNCTION:
4365                 if (describe_command_verbose) {
4366                         out1str(" is a shell function");
4367                 } else {
4368                         out1str(command);
4369                 }
4370                 break;
4371
4372         case CMDBUILTIN:
4373                 if (describe_command_verbose) {
4374                         out1fmt(" is a %sshell builtin",
4375                                 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4376                                         "special " : nullstr
4377                         );
4378                 } else {
4379                         out1str(command);
4380                 }
4381                 break;
4382
4383         default:
4384                 if (describe_command_verbose) {
4385                         out1str(": not found\n");
4386                 }
4387                 return 127;
4388         }
4389
4390 out:
4391         outstr("\n", stdout);
4392         return 0;
4393 }
4394
4395 static int
4396 typecmd(int argc, char **argv)
4397 {
4398         int i;
4399         int err = 0;
4400
4401         for (i = 1; i < argc; i++) {
4402 #ifdef CONFIG_ASH_CMDCMD
4403                 err |= describe_command(argv[i], 1);
4404 #else
4405                 err |= describe_command(argv[i]);
4406 #endif
4407         }
4408         return err;
4409 }
4410
4411 #ifdef CONFIG_ASH_CMDCMD
4412 static int
4413 commandcmd(int argc, char **argv)
4414 {
4415         int c;
4416         int default_path = 0;
4417         int verify_only = 0;
4418         int verbose_verify_only = 0;
4419
4420         while ((c = nextopt("pvV")) != '\0')
4421                 switch (c) {
4422                 default:
4423 #ifdef DEBUG
4424                         fprintf(stderr,
4425 "command: nextopt returned character code 0%o\n", c);
4426                         return EX_SOFTWARE;
4427 #endif
4428                 case 'p':
4429                         default_path = 1;
4430                         break;
4431                 case 'v':
4432                         verify_only = 1;
4433                         break;
4434                 case 'V':
4435                         verbose_verify_only = 1;
4436                         break;
4437                 }
4438
4439         if (default_path + verify_only + verbose_verify_only > 1 ||
4440             !*argptr) {
4441                         fprintf(stderr,
4442                                 "command [-p] command [arg ...]\n"
4443                                 "command {-v|-V} command\n");
4444                         return EX_USAGE;
4445         }
4446
4447         if (verify_only || verbose_verify_only) {
4448                 return describe_command(*argptr, verbose_verify_only);
4449         }
4450
4451         return 0;
4452 }
4453 #endif
4454
4455 /*      $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $     */
4456
4457 /*
4458  * Routines to expand arguments to commands.  We have to deal with
4459  * backquotes, shell variables, and file metacharacters.
4460  */
4461
4462 /*
4463  * _rmescape() flags
4464  */
4465 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
4466 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
4467 #define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
4468 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
4469 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
4470
4471 /*
4472  * Structure specifying which parts of the string should be searched
4473  * for IFS characters.
4474  */
4475
4476 struct ifsregion {
4477         struct ifsregion *next; /* next region in list */
4478         int begoff;             /* offset of start of region */
4479         int endoff;             /* offset of end of region */
4480         int nulonly;            /* search for nul bytes only */
4481 };
4482
4483 /* output of current string */
4484 static char *expdest;
4485 /* list of back quote expressions */
4486 static struct nodelist *argbackq;
4487 /* first struct in list of ifs regions */
4488 static struct ifsregion ifsfirst;
4489 /* last struct in list */
4490 static struct ifsregion *ifslastp;
4491 /* holds expanded arg list */
4492 static struct arglist exparg;
4493
4494 static void argstr(char *, int);
4495 static char *exptilde(char *, char *, int);
4496 static void expbackq(union node *, int, int);
4497 static const char *subevalvar(char *, char *, int, int, int, int, int);
4498 static char *evalvar(char *, int);
4499 static void strtodest(const char *, int, int);
4500 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4501 static ssize_t varvalue(char *, int, int);
4502 static void recordregion(int, int, int);
4503 static void removerecordregions(int);
4504 static void ifsbreakup(char *, struct arglist *);
4505 static void ifsfree(void);
4506 static void expandmeta(struct strlist *, int);
4507 static int patmatch(char *, const char *);
4508
4509 static int cvtnum(long);
4510 static size_t esclen(const char *, const char *);
4511 static char *scanleft(char *, char *, char *, char *, int, int);
4512 static char *scanright(char *, char *, char *, char *, int, int);
4513 static void varunset(const char *, const char *, const char *, int)
4514         __attribute__((__noreturn__));
4515
4516
4517 #define pmatch(a, b) !fnmatch((a), (b), 0)
4518 /*
4519  * Prepare a pattern for a expmeta (internal glob(3)) call.
4520  *
4521  * Returns an stalloced string.
4522  */
4523
4524 static inline char *
4525 preglob(const char *pattern, int quoted, int flag) {
4526         flag |= RMESCAPE_GLOB;
4527         if (quoted) {
4528                 flag |= RMESCAPE_QUOTED;
4529         }
4530         return _rmescapes((char *)pattern, flag);
4531 }
4532
4533
4534 static size_t
4535 esclen(const char *start, const char *p) {
4536         size_t esc = 0;
4537
4538         while (p > start && *--p == CTLESC) {
4539                 esc++;
4540         }
4541         return esc;
4542 }
4543
4544
4545 /*
4546  * Expand shell variables and backquotes inside a here document.
4547  */
4548
4549 static inline void
4550 expandhere(union node *arg, int fd)
4551 {
4552         herefd = fd;
4553         expandarg(arg, (struct arglist *)NULL, 0);
4554         xwrite(fd, stackblock(), expdest - (char *)stackblock());
4555 }
4556
4557
4558 /*
4559  * Perform variable substitution and command substitution on an argument,
4560  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
4561  * perform splitting and file name expansion.  When arglist is NULL, perform
4562  * here document expansion.
4563  */
4564
4565 void
4566 expandarg(union node *arg, struct arglist *arglist, int flag)
4567 {
4568         struct strlist *sp;
4569         char *p;
4570
4571         argbackq = arg->narg.backquote;
4572         STARTSTACKSTR(expdest);
4573         ifsfirst.next = NULL;
4574         ifslastp = NULL;
4575         argstr(arg->narg.text, flag);
4576         if (arglist == NULL) {
4577                 return;                 /* here document expanded */
4578         }
4579         STPUTC('\0', expdest);
4580         p = grabstackstr(expdest);
4581         exparg.lastp = &exparg.list;
4582         /*
4583          * TODO - EXP_REDIR
4584          */
4585         if (flag & EXP_FULL) {
4586                 ifsbreakup(p, &exparg);
4587                 *exparg.lastp = NULL;
4588                 exparg.lastp = &exparg.list;
4589                 expandmeta(exparg.list, flag);
4590         } else {
4591                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4592                         rmescapes(p);
4593                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4594                 sp->text = p;
4595                 *exparg.lastp = sp;
4596                 exparg.lastp = &sp->next;
4597         }
4598         if (ifsfirst.next)
4599                 ifsfree();
4600         *exparg.lastp = NULL;
4601         if (exparg.list) {
4602                 *arglist->lastp = exparg.list;
4603                 arglist->lastp = exparg.lastp;
4604         }
4605 }
4606
4607
4608 /*
4609  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
4610  * characters to allow for further processing.  Otherwise treat
4611  * $@ like $* since no splitting will be performed.
4612  */
4613
4614 static void
4615 argstr(char *p, int flag)
4616 {
4617         static const char spclchars[] = {
4618                 '=',
4619                 ':',
4620                 CTLQUOTEMARK,
4621                 CTLENDVAR,
4622                 CTLESC,
4623                 CTLVAR,
4624                 CTLBACKQ,
4625                 CTLBACKQ | CTLQUOTE,
4626 #ifdef CONFIG_ASH_MATH_SUPPORT
4627                 CTLENDARI,
4628 #endif
4629                 0
4630         };
4631         const char *reject = spclchars;
4632         int c;
4633         int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
4634         int breakall = flag & EXP_WORD;
4635         int inquotes;
4636         size_t length;
4637         int startloc;
4638
4639         if (!(flag & EXP_VARTILDE)) {
4640                 reject += 2;
4641         } else if (flag & EXP_VARTILDE2) {
4642                 reject++;
4643         }
4644         inquotes = 0;
4645         length = 0;
4646         if (flag & EXP_TILDE) {
4647                 char *q;
4648
4649                 flag &= ~EXP_TILDE;
4650 tilde:
4651                 q = p;
4652                 if (*q == CTLESC && (flag & EXP_QWORD))
4653                         q++;
4654                 if (*q == '~')
4655                         p = exptilde(p, q, flag);
4656         }
4657 start:
4658         startloc = expdest - (char *)stackblock();
4659         for (;;) {
4660                 length += strcspn(p + length, reject);
4661                 c = p[length];
4662                 if (c && (!(c & 0x80)
4663 #ifdef CONFIG_ASH_MATH_SUPPORT
4664                                         || c == CTLENDARI
4665 #endif
4666                    )) {
4667                         /* c == '=' || c == ':' || c == CTLENDARI */
4668                         length++;
4669                 }
4670                 if (length > 0) {
4671                         int newloc;
4672                         expdest = stnputs(p, length, expdest);
4673                         newloc = expdest - (char *)stackblock();
4674                         if (breakall && !inquotes && newloc > startloc) {
4675                                 recordregion(startloc, newloc, 0);
4676                         }
4677                         startloc = newloc;
4678                 }
4679                 p += length + 1;
4680                 length = 0;
4681
4682                 switch (c) {
4683                 case '\0':
4684                         goto breakloop;
4685                 case '=':
4686                         if (flag & EXP_VARTILDE2) {
4687                                 p--;
4688                                 continue;
4689                         }
4690                         flag |= EXP_VARTILDE2;
4691                         reject++;
4692                         /* fall through */
4693                 case ':':
4694                         /*
4695                          * sort of a hack - expand tildes in variable
4696                          * assignments (after the first '=' and after ':'s).
4697                          */
4698                         if (*--p == '~') {
4699                                 goto tilde;
4700                         }
4701                         continue;
4702                 }
4703
4704                 switch (c) {
4705                 case CTLENDVAR: /* ??? */
4706                         goto breakloop;
4707                 case CTLQUOTEMARK:
4708                         /* "$@" syntax adherence hack */
4709                         if (
4710                                 !inquotes &&
4711                                 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4712                                 (p[4] == CTLQUOTEMARK || (
4713                                         p[4] == CTLENDVAR &&
4714                                         p[5] == CTLQUOTEMARK
4715                                 ))
4716                         ) {
4717                                 p = evalvar(p + 1, flag) + 1;
4718                                 goto start;
4719                         }
4720                         inquotes = !inquotes;
4721 addquote:
4722                         if (quotes) {
4723                                 p--;
4724                                 length++;
4725                                 startloc++;
4726                         }
4727                         break;
4728                 case CTLESC:
4729                         startloc++;
4730                         length++;
4731                         goto addquote;
4732                 case CTLVAR:
4733                         p = evalvar(p, flag);
4734                         goto start;
4735                 case CTLBACKQ:
4736                         c = 0;
4737                 case CTLBACKQ|CTLQUOTE:
4738                         expbackq(argbackq->n, c, quotes);
4739                         argbackq = argbackq->next;
4740                         goto start;
4741 #ifdef CONFIG_ASH_MATH_SUPPORT
4742                 case CTLENDARI:
4743                         p--;
4744                         expari(quotes);
4745                         goto start;
4746 #endif
4747                 }
4748         }
4749 breakloop:
4750         ;
4751 }
4752
4753 static char *
4754 exptilde(char *startp, char *p, int flag)
4755 {
4756         char c;
4757         char *name;
4758         struct passwd *pw;
4759         const char *home;
4760         int quotes = flag & (EXP_FULL | EXP_CASE);
4761         int startloc;
4762
4763         name = p + 1;
4764
4765         while ((c = *++p) != '\0') {
4766                 switch(c) {
4767                 case CTLESC:
4768                         return (startp);
4769                 case CTLQUOTEMARK:
4770                         return (startp);
4771                 case ':':
4772                         if (flag & EXP_VARTILDE)
4773                                 goto done;
4774                         break;
4775                 case '/':
4776                 case CTLENDVAR:
4777                         goto done;
4778                 }
4779         }
4780 done:
4781         *p = '\0';
4782         if (*name == '\0') {
4783                 if ((home = lookupvar(homestr)) == NULL)
4784                         goto lose;
4785         } else {
4786                 if ((pw = getpwnam(name)) == NULL)
4787                         goto lose;
4788                 home = pw->pw_dir;
4789         }
4790         if (*home == '\0')
4791                 goto lose;
4792         *p = c;
4793         startloc = expdest - (char *)stackblock();
4794         strtodest(home, SQSYNTAX, quotes);
4795         recordregion(startloc, expdest - (char *)stackblock(), 0);
4796         return (p);
4797 lose:
4798         *p = c;
4799         return (startp);
4800 }
4801
4802
4803 static void
4804 removerecordregions(int endoff)
4805 {
4806         if (ifslastp == NULL)
4807                 return;
4808
4809         if (ifsfirst.endoff > endoff) {
4810                 while (ifsfirst.next != NULL) {
4811                         struct ifsregion *ifsp;
4812                         INTOFF;
4813                         ifsp = ifsfirst.next->next;
4814                         ckfree(ifsfirst.next);
4815                         ifsfirst.next = ifsp;
4816                         INTON;
4817                 }
4818                 if (ifsfirst.begoff > endoff)
4819                         ifslastp = NULL;
4820                 else {
4821                         ifslastp = &ifsfirst;
4822                         ifsfirst.endoff = endoff;
4823                 }
4824                 return;
4825         }
4826
4827         ifslastp = &ifsfirst;
4828         while (ifslastp->next && ifslastp->next->begoff < endoff)
4829                 ifslastp=ifslastp->next;
4830         while (ifslastp->next != NULL) {
4831                 struct ifsregion *ifsp;
4832                 INTOFF;
4833                 ifsp = ifslastp->next->next;
4834                 ckfree(ifslastp->next);
4835                 ifslastp->next = ifsp;
4836                 INTON;
4837         }
4838         if (ifslastp->endoff > endoff)
4839                 ifslastp->endoff = endoff;
4840 }
4841
4842
4843 #ifdef CONFIG_ASH_MATH_SUPPORT
4844 /*
4845  * Expand arithmetic expression.  Backup to start of expression,
4846  * evaluate, place result in (backed up) result, adjust string position.
4847  */
4848 void
4849 expari(int quotes)
4850 {
4851         char *p, *start;
4852         int begoff;
4853         int flag;
4854         int len;
4855
4856         /*      ifsfree(); */
4857
4858         /*
4859          * This routine is slightly over-complicated for
4860          * efficiency.  Next we scan backwards looking for the
4861          * start of arithmetic.
4862          */
4863         start = stackblock();
4864         p = expdest - 1;
4865         *p = '\0';
4866         p--;
4867         do {
4868                 int esc;
4869
4870                 while (*p != CTLARI) {
4871                         p--;
4872 #ifdef DEBUG
4873                         if (p < start) {
4874                                 error("missing CTLARI (shouldn't happen)");
4875                         }
4876 #endif
4877                 }
4878
4879                 esc = esclen(start, p);
4880                 if (!(esc % 2)) {
4881                         break;
4882                 }
4883
4884                 p -= esc + 1;
4885         } while (1);
4886
4887         begoff = p - start;
4888
4889         removerecordregions(begoff);
4890
4891         flag = p[1];
4892
4893         expdest = p;
4894
4895         if (quotes)
4896                 rmescapes(p + 2);
4897
4898         len = cvtnum(dash_arith(p + 2));
4899
4900         if (flag != '"')
4901                 recordregion(begoff, begoff + len, 0);
4902 }
4903 #endif
4904
4905 /*
4906  * Expand stuff in backwards quotes.
4907  */
4908
4909 static void
4910 expbackq(union node *cmd, int quoted, int quotes)
4911 {
4912         struct backcmd in;
4913         int i;
4914         char buf[128];
4915         char *p;
4916         char *dest;
4917         int startloc;
4918         int syntax = quoted? DQSYNTAX : BASESYNTAX;
4919         struct stackmark smark;
4920
4921         INTOFF;
4922         setstackmark(&smark);
4923         dest = expdest;
4924         startloc = dest - (char *)stackblock();
4925         grabstackstr(dest);
4926         evalbackcmd(cmd, (struct backcmd *) &in);
4927         popstackmark(&smark);
4928
4929         p = in.buf;
4930         i = in.nleft;
4931         if (i == 0)
4932                 goto read;
4933         for (;;) {
4934                 memtodest(p, i, syntax, quotes);
4935 read:
4936                 if (in.fd < 0)
4937                         break;
4938                 i = safe_read(in.fd, buf, sizeof buf);
4939                 TRACE(("expbackq: read returns %d\n", i));
4940                 if (i <= 0)
4941                         break;
4942                 p = buf;
4943         }
4944
4945         if (in.buf)
4946                 ckfree(in.buf);
4947         if (in.fd >= 0) {
4948                 close(in.fd);
4949                 back_exitstatus = waitforjob(in.jp);
4950         }
4951         INTON;
4952
4953         /* Eat all trailing newlines */
4954         dest = expdest;
4955         for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4956                 STUNPUTC(dest);
4957         expdest = dest;
4958
4959         if (quoted == 0)
4960                 recordregion(startloc, dest - (char *)stackblock(), 0);
4961         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4962                 (dest - (char *)stackblock()) - startloc,
4963                 (dest - (char *)stackblock()) - startloc,
4964                 stackblock() + startloc));
4965 }
4966
4967
4968 static char *
4969 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4970         int zero)
4971 {
4972         char *loc;
4973         char *loc2;
4974         char c;
4975
4976         loc = startp;
4977         loc2 = rmesc;
4978         do {
4979                 int match;
4980                 const char *s = loc2;
4981                 c = *loc2;
4982                 if (zero) {
4983                         *loc2 = '\0';
4984                         s = rmesc;
4985                 }
4986                 match = pmatch(str, s);
4987                 *loc2 = c;
4988                 if (match)
4989                         return loc;
4990                 if (quotes && *loc == CTLESC)
4991                         loc++;
4992                 loc++;
4993                 loc2++;
4994         } while (c);
4995         return 0;
4996 }
4997
4998
4999 static char *
5000 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5001         int zero)
5002 {
5003         int esc = 0;
5004         char *loc;
5005         char *loc2;
5006
5007         for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5008                 int match;
5009                 char c = *loc2;
5010                 const char *s = loc2;
5011                 if (zero) {
5012                         *loc2 = '\0';
5013                         s = rmesc;
5014                 }
5015                 match = pmatch(str, s);
5016                 *loc2 = c;
5017                 if (match)
5018                         return loc;
5019                 loc--;
5020                 if (quotes) {
5021                         if (--esc < 0) {
5022                                 esc = esclen(startp, loc);
5023                         }
5024                         if (esc % 2) {
5025                                 esc--;
5026                                 loc--;
5027                         }
5028                 }
5029         }
5030         return 0;
5031 }
5032
5033 static const char *
5034 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5035 {
5036         char *startp;
5037         char *loc;
5038         int saveherefd = herefd;
5039         struct nodelist *saveargbackq = argbackq;
5040         int amount;
5041         char *rmesc, *rmescend;
5042         int zero;
5043         char *(*scan)(char *, char *, char *, char *, int , int);
5044
5045         herefd = -1;
5046         argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5047         STPUTC('\0', expdest);
5048         herefd = saveherefd;
5049         argbackq = saveargbackq;
5050         startp = stackblock() + startloc;
5051
5052         switch (subtype) {
5053         case VSASSIGN:
5054                 setvar(str, startp, 0);
5055                 amount = startp - expdest;
5056                 STADJUST(amount, expdest);
5057                 return startp;
5058
5059         case VSQUESTION:
5060                 varunset(p, str, startp, varflags);
5061                 /* NOTREACHED */
5062         }
5063
5064         subtype -= VSTRIMRIGHT;
5065 #ifdef DEBUG
5066         if (subtype < 0 || subtype > 3)
5067                 abort();
5068 #endif
5069
5070         rmesc = startp;
5071         rmescend = stackblock() + strloc;
5072         if (quotes) {
5073                 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5074                 if (rmesc != startp) {
5075                         rmescend = expdest;
5076                         startp = stackblock() + startloc;
5077                 }
5078         }
5079         rmescend--;
5080         str = stackblock() + strloc;
5081         preglob(str, varflags & VSQUOTE, 0);
5082
5083         /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5084         zero = subtype >> 1;
5085         /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5086         scan = (subtype & 1) ^ zero ? scanleft : scanright;
5087
5088         loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5089         if (loc) {
5090                 if (zero) {
5091                         memmove(startp, loc, str - loc);
5092                         loc = startp + (str - loc) - 1;
5093                 }
5094                 *loc = '\0';
5095                 amount = loc - expdest;
5096                 STADJUST(amount, expdest);
5097         }
5098         return loc;
5099 }
5100
5101
5102 /*
5103  * Expand a variable, and return a pointer to the next character in the
5104  * input string.
5105  */
5106 static char *
5107 evalvar(char *p, int flag)
5108 {
5109         int subtype;
5110         int varflags;
5111         char *var;
5112         int patloc;
5113         int c;
5114         int startloc;
5115         ssize_t varlen;
5116         int easy;
5117         int quotes;
5118         int quoted;
5119
5120         quotes = flag & (EXP_FULL | EXP_CASE);
5121         varflags = *p++;
5122         subtype = varflags & VSTYPE;
5123         quoted = varflags & VSQUOTE;
5124         var = p;
5125         easy = (!quoted || (*var == '@' && shellparam.nparam));
5126         startloc = expdest - (char *)stackblock();
5127         p = strchr(p, '=') + 1;
5128
5129 again:
5130         varlen = varvalue(var, varflags, flag);
5131         if (varflags & VSNUL)
5132                 varlen--;
5133
5134         if (subtype == VSPLUS) {
5135                 varlen = -1 - varlen;
5136                 goto vsplus;
5137         }
5138
5139         if (subtype == VSMINUS) {
5140 vsplus:
5141                 if (varlen < 0) {
5142                         argstr(
5143                                 p, flag | EXP_TILDE |
5144                                         (quoted ?  EXP_QWORD : EXP_WORD)
5145                         );
5146                         goto end;
5147                 }
5148                 if (easy)
5149                         goto record;
5150                 goto end;
5151         }
5152
5153         if (subtype == VSASSIGN || subtype == VSQUESTION) {
5154                 if (varlen < 0) {
5155                         if (subevalvar(p, var, 0, subtype, startloc,
5156                                        varflags, 0)) {
5157                                 varflags &= ~VSNUL;
5158                                 /*
5159                                  * Remove any recorded regions beyond
5160                                  * start of variable
5161                                  */
5162                                 removerecordregions(startloc);
5163                                 goto again;
5164                         }
5165                         goto end;
5166                 }
5167                 if (easy)
5168                         goto record;
5169                 goto end;
5170         }
5171
5172         if (varlen < 0 && uflag)
5173                 varunset(p, var, 0, 0);
5174
5175         if (subtype == VSLENGTH) {
5176                 cvtnum(varlen > 0 ? varlen : 0);
5177                 goto record;
5178         }
5179
5180         if (subtype == VSNORMAL) {
5181                 if (!easy)
5182                         goto end;
5183 record:
5184                 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5185                 goto end;
5186         }
5187
5188 #ifdef DEBUG
5189         switch (subtype) {
5190         case VSTRIMLEFT:
5191         case VSTRIMLEFTMAX:
5192         case VSTRIMRIGHT:
5193         case VSTRIMRIGHTMAX:
5194                 break;
5195         default:
5196                 abort();
5197         }
5198 #endif
5199
5200         if (varlen >= 0) {
5201                 /*
5202                  * Terminate the string and start recording the pattern
5203                  * right after it
5204                  */
5205                 STPUTC('\0', expdest);
5206                 patloc = expdest - (char *)stackblock();
5207                 if (subevalvar(p, NULL, patloc, subtype,
5208                                startloc, varflags, quotes) == 0) {
5209                         int amount = expdest - (
5210                                 (char *)stackblock() + patloc - 1
5211                         );
5212                         STADJUST(-amount, expdest);
5213                 }
5214                 /* Remove any recorded regions beyond start of variable */
5215                 removerecordregions(startloc);
5216                 goto record;
5217         }
5218
5219 end:
5220         if (subtype != VSNORMAL) {      /* skip to end of alternative */
5221                 int nesting = 1;
5222                 for (;;) {
5223                         if ((c = *p++) == CTLESC)
5224                                 p++;
5225                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5226                                 if (varlen >= 0)
5227                                         argbackq = argbackq->next;
5228                         } else if (c == CTLVAR) {
5229                                 if ((*p++ & VSTYPE) != VSNORMAL)
5230                                         nesting++;
5231                         } else if (c == CTLENDVAR) {
5232                                 if (--nesting == 0)
5233                                         break;
5234                         }
5235                 }
5236         }
5237         return p;
5238 }
5239
5240
5241 /*
5242  * Put a string on the stack.
5243  */
5244
5245 static void
5246 memtodest(const char *p, size_t len, int syntax, int quotes) {
5247         char *q = expdest;
5248
5249         q = makestrspace(len * 2, q);
5250
5251         while (len--) {
5252                 int c = *p++;
5253                 if (!c)
5254                         continue;
5255                 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5256                         USTPUTC(CTLESC, q);
5257                 USTPUTC(c, q);
5258         }
5259
5260         expdest = q;
5261 }
5262
5263
5264 static void
5265 strtodest(const char *p, int syntax, int quotes)
5266 {
5267         memtodest(p, strlen(p), syntax, quotes);
5268 }
5269
5270
5271 /*
5272  * Add the value of a specialized variable to the stack string.
5273  */
5274
5275 static ssize_t
5276 varvalue(char *name, int varflags, int flags)
5277 {
5278         int num;
5279         char *p;
5280         int i;
5281         int sep = 0;
5282         int sepq = 0;
5283         ssize_t len = 0;
5284         char **ap;
5285         int syntax;
5286         int quoted = varflags & VSQUOTE;
5287         int subtype = varflags & VSTYPE;
5288         int quotes = flags & (EXP_FULL | EXP_CASE);
5289
5290         if (quoted && (flags & EXP_FULL))
5291                 sep = 1 << CHAR_BIT;
5292
5293         syntax = quoted ? DQSYNTAX : BASESYNTAX;
5294         switch (*name) {
5295         case '$':
5296                 num = rootpid;
5297                 goto numvar;
5298         case '?':
5299                 num = exitstatus;
5300                 goto numvar;
5301         case '#':
5302                 num = shellparam.nparam;
5303                 goto numvar;
5304         case '!':
5305                 num = backgndpid;
5306                 if (num == 0)
5307                         return -1;
5308 numvar:
5309                 len = cvtnum(num);
5310                 break;
5311         case '-':
5312                 p = makestrspace(NOPTS, expdest);
5313                 for (i = NOPTS - 1; i >= 0; i--) {
5314                         if (optlist[i]) {
5315                                 USTPUTC(optletters(i), p);
5316                                 len++;
5317                         }
5318                 }
5319                 expdest = p;
5320                 break;
5321         case '@':
5322                 if (sep)
5323                         goto param;
5324                 /* fall through */
5325         case '*':
5326                 sep = ifsset() ? ifsval()[0] : ' ';
5327                 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5328                         sepq = 1;
5329 param:
5330                 if (!(ap = shellparam.p))
5331                         return -1;
5332                 while ((p = *ap++)) {
5333                         size_t partlen;
5334
5335                         partlen = strlen(p);
5336
5337                         len += partlen;
5338                         if (len > partlen && sep) {
5339                                 char *q;
5340
5341                                 len++;
5342                                 if (subtype == VSPLUS || subtype == VSLENGTH) {
5343                                         continue;
5344                                 }
5345                                 q = expdest;
5346                                 if (sepq)
5347                                         STPUTC(CTLESC, q);
5348                                 STPUTC(sep, q);
5349                                 expdest = q;
5350                         }
5351
5352                         if (!(subtype == VSPLUS || subtype == VSLENGTH))
5353                                 memtodest(p, partlen, syntax, quotes);
5354                 }
5355                 return len;
5356         case '0':
5357         case '1':
5358         case '2':
5359         case '3':
5360         case '4':
5361         case '5':
5362         case '6':
5363         case '7':
5364         case '8':
5365         case '9':
5366                 num = atoi(name);
5367                 if (num < 0 || num > shellparam.nparam)
5368                         return -1;
5369                 p = num ? shellparam.p[num - 1] : arg0;
5370                 goto value;
5371         default:
5372                 p = lookupvar(name);
5373 value:
5374                 if (!p)
5375                         return -1;
5376
5377                 len = strlen(p);
5378                 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5379                         memtodest(p, len, syntax, quotes);
5380                 return len;
5381         }
5382
5383         if (subtype == VSPLUS || subtype == VSLENGTH)
5384                 STADJUST(-len, expdest);
5385         return len;
5386 }
5387
5388
5389 /*
5390  * Record the fact that we have to scan this region of the
5391  * string for IFS characters.
5392  */
5393
5394 static void
5395 recordregion(int start, int end, int nulonly)
5396 {
5397         struct ifsregion *ifsp;
5398
5399         if (ifslastp == NULL) {
5400                 ifsp = &ifsfirst;
5401         } else {
5402                 INTOFF;
5403                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5404                 ifsp->next = NULL;
5405                 ifslastp->next = ifsp;
5406                 INTON;
5407         }
5408         ifslastp = ifsp;
5409         ifslastp->begoff = start;
5410         ifslastp->endoff = end;
5411         ifslastp->nulonly = nulonly;
5412 }
5413
5414
5415 /*
5416  * Break the argument string into pieces based upon IFS and add the
5417  * strings to the argument list.  The regions of the string to be
5418  * searched for IFS characters have been stored by recordregion.
5419  */
5420 static void
5421 ifsbreakup(char *string, struct arglist *arglist)
5422 {
5423         struct ifsregion *ifsp;
5424         struct strlist *sp;
5425         char *start;
5426         char *p;
5427         char *q;
5428         const char *ifs, *realifs;
5429         int ifsspc;
5430         int nulonly;
5431
5432
5433         start = string;
5434         if (ifslastp != NULL) {
5435                 ifsspc = 0;
5436                 nulonly = 0;
5437                 realifs = ifsset() ? ifsval() : defifs;
5438                 ifsp = &ifsfirst;
5439                 do {
5440                         p = string + ifsp->begoff;
5441                         nulonly = ifsp->nulonly;
5442                         ifs = nulonly ? nullstr : realifs;
5443                         ifsspc = 0;
5444                         while (p < string + ifsp->endoff) {
5445                                 q = p;
5446                                 if (*p == CTLESC)
5447                                         p++;
5448                                 if (strchr(ifs, *p)) {
5449                                         if (!nulonly)
5450                                                 ifsspc = (strchr(defifs, *p) != NULL);
5451                                         /* Ignore IFS whitespace at start */
5452                                         if (q == start && ifsspc) {
5453                                                 p++;
5454                                                 start = p;
5455                                                 continue;
5456                                         }
5457                                         *q = '\0';
5458                                         sp = (struct strlist *)stalloc(sizeof *sp);
5459                                         sp->text = start;
5460                                         *arglist->lastp = sp;
5461                                         arglist->lastp = &sp->next;
5462                                         p++;
5463                                         if (!nulonly) {
5464                                                 for (;;) {
5465                                                         if (p >= string + ifsp->endoff) {
5466                                                                 break;
5467                                                         }
5468                                                         q = p;
5469                                                         if (*p == CTLESC)
5470                                                                 p++;
5471                                                         if (strchr(ifs, *p) == NULL ) {
5472                                                                 p = q;
5473                                                                 break;
5474                                                         } else if (strchr(defifs, *p) == NULL) {
5475                                                                 if (ifsspc) {
5476                                                                         p++;
5477                                                                         ifsspc = 0;
5478                                                                 } else {
5479                                                                         p = q;
5480                                                                         break;
5481                                                                 }
5482                                                         } else
5483                                                                 p++;
5484                                                 }
5485                                         }
5486                                         start = p;
5487                                 } else
5488                                         p++;
5489                         }
5490                 } while ((ifsp = ifsp->next) != NULL);
5491                 if (nulonly)
5492                         goto add;
5493         }
5494
5495         if (!*start)
5496                 return;
5497
5498 add:
5499         sp = (struct strlist *)stalloc(sizeof *sp);
5500         sp->text = start;
5501         *arglist->lastp = sp;
5502         arglist->lastp = &sp->next;
5503 }
5504
5505 static void
5506 ifsfree(void)
5507 {
5508         struct ifsregion *p;
5509
5510         INTOFF;
5511         p = ifsfirst.next;
5512         do {
5513                 struct ifsregion *ifsp;
5514                 ifsp = p->next;
5515                 ckfree(p);
5516                 p = ifsp;
5517         } while (p);
5518         ifslastp = NULL;
5519         ifsfirst.next = NULL;
5520         INTON;
5521 }
5522
5523 static void expmeta(char *, char *);
5524 static struct strlist *expsort(struct strlist *);
5525 static struct strlist *msort(struct strlist *, int);
5526
5527 static char *expdir;
5528
5529
5530 static void
5531 expandmeta(struct strlist *str, int flag)
5532 {
5533         static const char metachars[] = {
5534                 '*', '?', '[', 0
5535         };
5536         /* TODO - EXP_REDIR */
5537
5538         while (str) {
5539                 struct strlist **savelastp;
5540                 struct strlist *sp;
5541                 char *p;
5542
5543                 if (fflag)
5544                         goto nometa;
5545                 if (!strpbrk(str->text, metachars))
5546                         goto nometa;
5547                 savelastp = exparg.lastp;
5548
5549                 INTOFF;
5550                 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5551                 {
5552                         int i = strlen(str->text);
5553                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5554                 }
5555
5556                 expmeta(expdir, p);
5557                 ckfree(expdir);
5558                 if (p != str->text)
5559                         ckfree(p);
5560                 INTON;
5561                 if (exparg.lastp == savelastp) {
5562                         /*
5563                          * no matches
5564                          */
5565 nometa:
5566                         *exparg.lastp = str;
5567                         rmescapes(str->text);
5568                         exparg.lastp = &str->next;
5569                 } else {
5570                         *exparg.lastp = NULL;
5571                         *savelastp = sp = expsort(*savelastp);
5572                         while (sp->next != NULL)
5573                                 sp = sp->next;
5574                         exparg.lastp = &sp->next;
5575                 }
5576                 str = str->next;
5577         }
5578 }
5579
5580 /*
5581  * Add a file name to the list.
5582  */
5583
5584 static void
5585 addfname(const char *name)
5586 {
5587         struct strlist *sp;
5588
5589         sp = (struct strlist *)stalloc(sizeof *sp);
5590         sp->text = sstrdup(name);
5591         *exparg.lastp = sp;
5592         exparg.lastp = &sp->next;
5593 }
5594
5595
5596 /*
5597  * Do metacharacter (i.e. *, ?, [...]) expansion.
5598  */
5599
5600 static void
5601 expmeta(char *enddir, char *name)
5602 {
5603         char *p;
5604         const char *cp;
5605         char *start;
5606         char *endname;
5607         int metaflag;
5608         struct stat statb;
5609         DIR *dirp;
5610         struct dirent *dp;
5611         int atend;
5612         int matchdot;
5613
5614         metaflag = 0;
5615         start = name;
5616         for (p = name; *p; p++) {
5617                 if (*p == '*' || *p == '?')
5618                         metaflag = 1;
5619                 else if (*p == '[') {
5620                         char *q = p + 1;
5621                         if (*q == '!')
5622                                 q++;
5623                         for (;;) {
5624                                 if (*q == '\\')
5625                                         q++;
5626                                 if (*q == '/' || *q == '\0')
5627                                         break;
5628                                 if (*++q == ']') {
5629                                         metaflag = 1;
5630                                         break;
5631                                 }
5632                         }
5633                 } else if (*p == '\\')
5634                         p++;
5635                 else if (*p == '/') {
5636                         if (metaflag)
5637                                 goto out;
5638                         start = p + 1;
5639                 }
5640         }
5641 out:
5642         if (metaflag == 0) {    /* we've reached the end of the file name */
5643                 if (enddir != expdir)
5644                         metaflag++;
5645                 p = name;
5646                 do {
5647                         if (*p == '\\')
5648                                 p++;
5649                         *enddir++ = *p;
5650                 } while (*p++);
5651                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5652                         addfname(expdir);
5653                 return;
5654         }
5655         endname = p;
5656         if (name < start) {
5657                 p = name;
5658                 do {
5659                         if (*p == '\\')
5660                                 p++;
5661                         *enddir++ = *p++;
5662                 } while (p < start);
5663         }
5664         if (enddir == expdir) {
5665                 cp = ".";
5666         } else if (enddir == expdir + 1 && *expdir == '/') {
5667                 cp = "/";
5668         } else {
5669                 cp = expdir;
5670                 enddir[-1] = '\0';
5671         }
5672         if ((dirp = opendir(cp)) == NULL)
5673                 return;
5674         if (enddir != expdir)
5675                 enddir[-1] = '/';
5676         if (*endname == 0) {
5677                 atend = 1;
5678         } else {
5679                 atend = 0;
5680                 *endname++ = '\0';
5681         }
5682         matchdot = 0;
5683         p = start;
5684         if (*p == '\\')
5685                 p++;
5686         if (*p == '.')
5687                 matchdot++;
5688         while (! intpending && (dp = readdir(dirp)) != NULL) {
5689                 if (dp->d_name[0] == '.' && ! matchdot)
5690                         continue;
5691                 if (pmatch(start, dp->d_name)) {
5692                         if (atend) {
5693                                 scopy(dp->d_name, enddir);
5694                                 addfname(expdir);
5695                         } else {
5696                                 for (p = enddir, cp = dp->d_name;
5697                                      (*p++ = *cp++) != '\0';)
5698                                         continue;
5699                                 p[-1] = '/';
5700                                 expmeta(p, endname);
5701                         }
5702                 }
5703         }
5704         closedir(dirp);
5705         if (! atend)
5706                 endname[-1] = '/';
5707 }
5708
5709 /*
5710  * Sort the results of file name expansion.  It calculates the number of
5711  * strings to sort and then calls msort (short for merge sort) to do the
5712  * work.
5713  */
5714
5715 static struct strlist *
5716 expsort(struct strlist *str)
5717 {
5718         int len;
5719         struct strlist *sp;
5720
5721         len = 0;
5722         for (sp = str ; sp ; sp = sp->next)
5723                 len++;
5724         return msort(str, len);
5725 }
5726
5727
5728 static struct strlist *
5729 msort(struct strlist *list, int len)
5730 {
5731         struct strlist *p, *q = NULL;
5732         struct strlist **lpp;
5733         int half;
5734         int n;
5735
5736         if (len <= 1)
5737                 return list;
5738         half = len >> 1;
5739         p = list;
5740         for (n = half ; --n >= 0 ; ) {
5741                 q = p;
5742                 p = p->next;
5743         }
5744         q->next = NULL;                 /* terminate first half of list */
5745         q = msort(list, half);          /* sort first half of list */
5746         p = msort(p, len - half);               /* sort second half */
5747         lpp = &list;
5748         for (;;) {
5749 #ifdef CONFIG_LOCALE_SUPPORT
5750                 if (strcoll(p->text, q->text) < 0)
5751 #else
5752                 if (strcmp(p->text, q->text) < 0)
5753 #endif
5754                                                 {
5755                         *lpp = p;
5756                         lpp = &p->next;
5757                         if ((p = *lpp) == NULL) {
5758                                 *lpp = q;
5759                                 break;
5760                         }
5761                 } else {
5762                         *lpp = q;
5763                         lpp = &q->next;
5764                         if ((q = *lpp) == NULL) {
5765                                 *lpp = p;
5766                                 break;
5767                         }
5768                 }
5769         }
5770         return list;
5771 }
5772
5773
5774 /*
5775  * Returns true if the pattern matches the string.
5776  */
5777
5778 static inline int
5779 patmatch(char *pattern, const char *string)
5780 {
5781         return pmatch(preglob(pattern, 0, 0), string);
5782 }
5783
5784
5785 /*
5786  * Remove any CTLESC characters from a string.
5787  */
5788
5789 static char *
5790 _rmescapes(char *str, int flag)
5791 {
5792         char *p, *q, *r;
5793         static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5794         unsigned inquotes;
5795         int notescaped;
5796         int globbing;
5797
5798         p = strpbrk(str, qchars);
5799         if (!p) {
5800                 return str;
5801         }
5802         q = p;
5803         r = str;
5804         if (flag & RMESCAPE_ALLOC) {
5805                 size_t len = p - str;
5806                 size_t fulllen = len + strlen(p) + 1;
5807
5808                 if (flag & RMESCAPE_GROW) {
5809                         r = makestrspace(fulllen, expdest);
5810                 } else if (flag & RMESCAPE_HEAP) {
5811                         r = ckmalloc(fulllen);
5812                 } else {
5813                         r = stalloc(fulllen);
5814                 }
5815                 q = r;
5816                 if (len > 0) {
5817                         q = mempcpy(q, str, len);
5818                 }
5819         }
5820         inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5821         globbing = flag & RMESCAPE_GLOB;
5822         notescaped = globbing;
5823         while (*p) {
5824                 if (*p == CTLQUOTEMARK) {
5825                         inquotes = ~inquotes;
5826                         p++;
5827                         notescaped = globbing;
5828                         continue;
5829                 }
5830                 if (*p == '\\') {
5831                         /* naked back slash */
5832                         notescaped = 0;
5833                         goto copy;
5834                 }
5835                 if (*p == CTLESC) {
5836                         p++;
5837                         if (notescaped && inquotes && *p != '/') {
5838                                 *q++ = '\\';
5839                         }
5840                 }
5841                 notescaped = globbing;
5842 copy:
5843                 *q++ = *p++;
5844         }
5845         *q = '\0';
5846         if (flag & RMESCAPE_GROW) {
5847                 expdest = r;
5848                 STADJUST(q - r + 1, expdest);
5849         }
5850         return r;
5851 }
5852
5853
5854 /*
5855  * See if a pattern matches in a case statement.
5856  */
5857
5858 int
5859 casematch(union node *pattern, char *val)
5860 {
5861         struct stackmark smark;
5862         int result;
5863
5864         setstackmark(&smark);
5865         argbackq = pattern->narg.backquote;
5866         STARTSTACKSTR(expdest);
5867         ifslastp = NULL;
5868         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5869         STACKSTRNUL(expdest);
5870         result = patmatch(stackblock(), val);
5871         popstackmark(&smark);
5872         return result;
5873 }
5874
5875 /*
5876  * Our own itoa().
5877  */
5878
5879 static int
5880 cvtnum(long num)
5881 {
5882         int len;
5883
5884         expdest = makestrspace(32, expdest);
5885         len = fmtstr(expdest, 32, "%ld", num);
5886         STADJUST(len, expdest);
5887         return len;
5888 }
5889
5890 static void
5891 varunset(const char *end, const char *var, const char *umsg, int varflags)
5892 {
5893         const char *msg;
5894         const char *tail;
5895
5896         tail = nullstr;
5897         msg = "parameter not set";
5898         if (umsg) {
5899                 if (*end == CTLENDVAR) {
5900                         if (varflags & VSNUL)
5901                                 tail = " or null";
5902                 } else
5903                         msg = umsg;
5904         }
5905         error("%.*s: %s%s", end - var - 1, var, msg, tail);
5906 }
5907
5908
5909 /*      $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $      */
5910
5911 /*
5912  * This implements the input routines used by the parser.
5913  */
5914
5915 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
5916 #define IBUFSIZ (BUFSIZ + 1)
5917
5918 static void pushfile(void);
5919
5920 /*
5921  * Read a line from the script.
5922  */
5923
5924 static inline char *
5925 pfgets(char *line, int len)
5926 {
5927         char *p = line;
5928         int nleft = len;
5929         int c;
5930
5931         while (--nleft > 0) {
5932                 c = pgetc2();
5933                 if (c == PEOF) {
5934                         if (p == line)
5935                                 return NULL;
5936                         break;
5937                 }
5938                 *p++ = c;
5939                 if (c == '\n')
5940                         break;
5941         }
5942         *p = '\0';
5943         return line;
5944 }
5945
5946
5947 /*
5948  * Read a character from the script, returning PEOF on end of file.
5949  * Nul characters in the input are silently discarded.
5950  */
5951
5952 #define pgetc_as_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5953
5954 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5955 #define pgetc_macro() pgetc()
5956 static int
5957 pgetc(void)
5958 {
5959         return pgetc_as_macro();
5960 }
5961 #else
5962 #define pgetc_macro()   pgetc_as_macro()
5963 static int
5964 pgetc(void)
5965 {
5966         return pgetc_macro();
5967 }
5968 #endif
5969
5970
5971 /*
5972  * Same as pgetc(), but ignores PEOA.
5973  */
5974 #ifdef CONFIG_ASH_ALIAS
5975 static int pgetc2(void)
5976 {
5977         int c;
5978
5979         do {
5980                 c = pgetc_macro();
5981         } while (c == PEOA);
5982         return c;
5983 }
5984 #else
5985 static inline int pgetc2(void)
5986 {
5987         return pgetc_macro();
5988 }
5989 #endif
5990
5991
5992 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5993 static const char *cmdedit_prompt;
5994 static inline void putprompt(const char *s)
5995 {
5996         cmdedit_prompt = s;
5997 }
5998 #else
5999 static inline void putprompt(const char *s)
6000 {
6001         out2str(s);
6002 }
6003 #endif
6004
6005 static inline int
6006 preadfd(void)
6007 {
6008         int nr;
6009         char *buf =  parsefile->buf;
6010         parsenextc = buf;
6011
6012 retry:
6013 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6014         if (!iflag || parsefile->fd)
6015                 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6016         else {
6017                 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6018                 if(nr == 0) {
6019                         /* Ctrl+C presend */
6020                         raise(SIGINT);
6021                         goto retry;
6022                 }
6023                 if(nr < 0) {
6024                         /* Ctrl+D presend */
6025                         nr = 0;
6026                 }
6027         }
6028 #else
6029         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6030 #endif
6031
6032         if (nr < 0) {
6033                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6034                         int flags = fcntl(0, F_GETFL, 0);
6035                         if (flags >= 0 && flags & O_NONBLOCK) {
6036                                 flags &=~ O_NONBLOCK;
6037                                 if (fcntl(0, F_SETFL, flags) >= 0) {
6038                                         out2str("sh: turning off NDELAY mode\n");
6039                                         goto retry;
6040                                 }
6041                         }
6042                 }
6043         }
6044         return nr;
6045 }
6046
6047 /*
6048  * Refill the input buffer and return the next input character:
6049  *
6050  * 1) If a string was pushed back on the input, pop it;
6051  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6052  *    from a string so we can't refill the buffer, return EOF.
6053  * 3) If the is more stuff in this buffer, use it else call read to fill it.
6054  * 4) Process input up to the next newline, deleting nul characters.
6055  */
6056
6057 int
6058 preadbuffer(void)
6059 {
6060         char *p, *q;
6061         int more;
6062         char savec;
6063
6064         while (parsefile->strpush) {
6065 #ifdef CONFIG_ASH_ALIAS
6066                 if (parsenleft == -1 && parsefile->strpush->ap &&
6067                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6068                         return PEOA;
6069                 }
6070 #endif
6071                 popstring();
6072                 if (--parsenleft >= 0)
6073                         return (*parsenextc++);
6074         }
6075         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6076                 return PEOF;
6077         flushall();
6078
6079 again:
6080         if (parselleft <= 0) {
6081                 if ((parselleft = preadfd()) <= 0) {
6082                         parselleft = parsenleft = EOF_NLEFT;
6083                         return PEOF;
6084                 }
6085         }
6086
6087         q = p = parsenextc;
6088
6089         /* delete nul characters */
6090         for (more = 1; more;) {
6091                 switch (*p) {
6092                 case '\0':
6093                         p++;    /* Skip nul */
6094                         goto check;
6095
6096                 case '\n':
6097                         parsenleft = q - parsenextc;
6098                         more = 0; /* Stop processing here */
6099                         break;
6100
6101                 }
6102
6103                 *q++ = *p++;
6104 check:
6105                 if (--parselleft <= 0 && more) {
6106                         parsenleft = q - parsenextc - 1;
6107                         if (parsenleft < 0)
6108                                 goto again;
6109                         more = 0;
6110                 }
6111         }
6112
6113         savec = *q;
6114         *q = '\0';
6115
6116         if (vflag) {
6117                 out2str(parsenextc);
6118         }
6119
6120         *q = savec;
6121
6122         return *parsenextc++;
6123 }
6124
6125 /*
6126  * Undo the last call to pgetc.  Only one character may be pushed back.
6127  * PEOF may be pushed back.
6128  */
6129
6130 void
6131 pungetc(void)
6132 {
6133         parsenleft++;
6134         parsenextc--;
6135 }
6136
6137 /*
6138  * Push a string back onto the input at this current parsefile level.
6139  * We handle aliases this way.
6140  */
6141 void
6142 pushstring(char *s, void *ap)
6143 {
6144         struct strpush *sp;
6145         size_t len;
6146
6147         len = strlen(s);
6148         INTOFF;
6149 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6150         if (parsefile->strpush) {
6151                 sp = ckmalloc(sizeof (struct strpush));
6152                 sp->prev = parsefile->strpush;
6153                 parsefile->strpush = sp;
6154         } else
6155                 sp = parsefile->strpush = &(parsefile->basestrpush);
6156         sp->prevstring = parsenextc;
6157         sp->prevnleft = parsenleft;
6158 #ifdef CONFIG_ASH_ALIAS
6159         sp->ap = (struct alias *)ap;
6160         if (ap) {
6161                 ((struct alias *)ap)->flag |= ALIASINUSE;
6162                 sp->string = s;
6163         }
6164 #endif
6165         parsenextc = s;
6166         parsenleft = len;
6167         INTON;
6168 }
6169
6170 void
6171 popstring(void)
6172 {
6173         struct strpush *sp = parsefile->strpush;
6174
6175         INTOFF;
6176 #ifdef CONFIG_ASH_ALIAS
6177         if (sp->ap) {
6178                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6179                         checkkwd |= CHKALIAS;
6180                 }
6181                 if (sp->string != sp->ap->val) {
6182                         ckfree(sp->string);
6183                 }
6184                 sp->ap->flag &= ~ALIASINUSE;
6185                 if (sp->ap->flag & ALIASDEAD) {
6186                         unalias(sp->ap->name);
6187                 }
6188         }
6189 #endif
6190         parsenextc = sp->prevstring;
6191         parsenleft = sp->prevnleft;
6192 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6193         parsefile->strpush = sp->prev;
6194         if (sp != &(parsefile->basestrpush))
6195                 ckfree(sp);
6196         INTON;
6197 }
6198
6199 /*
6200  * Set the input to take input from a file.  If push is set, push the
6201  * old input onto the stack first.
6202  */
6203
6204 void
6205 setinputfile(const char *fname, int push)
6206 {
6207         int fd;
6208         int fd2;
6209
6210         INTOFF;
6211         if ((fd = open(fname, O_RDONLY)) < 0)
6212                 error("Can't open %s", fname);
6213         if (fd < 10) {
6214                 fd2 = copyfd(fd, 10);
6215                 close(fd);
6216                 if (fd2 < 0)
6217                         error("Out of file descriptors");
6218                 fd = fd2;
6219         }
6220         setinputfd(fd, push);
6221         INTON;
6222 }
6223
6224
6225 /*
6226  * Like setinputfile, but takes an open file descriptor.  Call this with
6227  * interrupts off.
6228  */
6229
6230 static void
6231 setinputfd(int fd, int push)
6232 {
6233         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6234         if (push) {
6235                 pushfile();
6236                 parsefile->buf = 0;
6237         }
6238         parsefile->fd = fd;
6239         if (parsefile->buf == NULL)
6240                 parsefile->buf = ckmalloc(IBUFSIZ);
6241         parselleft = parsenleft = 0;
6242         plinno = 1;
6243 }
6244
6245
6246 /*
6247  * Like setinputfile, but takes input from a string.
6248  */
6249
6250 static void
6251 setinputstring(char *string)
6252 {
6253         INTOFF;
6254         pushfile();
6255         parsenextc = string;
6256         parsenleft = strlen(string);
6257         parsefile->buf = NULL;
6258         plinno = 1;
6259         INTON;
6260 }
6261
6262
6263 /*
6264  * To handle the "." command, a stack of input files is used.  Pushfile
6265  * adds a new entry to the stack and popfile restores the previous level.
6266  */
6267
6268 static void
6269 pushfile(void)
6270 {
6271         struct parsefile *pf;
6272
6273         parsefile->nleft = parsenleft;
6274         parsefile->lleft = parselleft;
6275         parsefile->nextc = parsenextc;
6276         parsefile->linno = plinno;
6277         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6278         pf->prev = parsefile;
6279         pf->fd = -1;
6280         pf->strpush = NULL;
6281         pf->basestrpush.prev = NULL;
6282         parsefile = pf;
6283 }
6284
6285
6286 static void
6287 popfile(void)
6288 {
6289         struct parsefile *pf = parsefile;
6290
6291         INTOFF;
6292         if (pf->fd >= 0)
6293                 close(pf->fd);
6294         if (pf->buf)
6295                 ckfree(pf->buf);
6296         while (pf->strpush)
6297                 popstring();
6298         parsefile = pf->prev;
6299         ckfree(pf);
6300         parsenleft = parsefile->nleft;
6301         parselleft = parsefile->lleft;
6302         parsenextc = parsefile->nextc;
6303         plinno = parsefile->linno;
6304         INTON;
6305 }
6306
6307
6308 /*
6309  * Return to top level.
6310  */
6311
6312 static void
6313 popallfiles(void)
6314 {
6315         while (parsefile != &basepf)
6316                 popfile();
6317 }
6318
6319
6320 /*
6321  * Close the file(s) that the shell is reading commands from.  Called
6322  * after a fork is done.
6323  */
6324
6325 static void
6326 closescript(void)
6327 {
6328         popallfiles();
6329         if (parsefile->fd > 0) {
6330                 close(parsefile->fd);
6331                 parsefile->fd = 0;
6332         }
6333 }
6334
6335 /*      $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $    */
6336
6337 /* mode flags for set_curjob */
6338 #define CUR_DELETE 2
6339 #define CUR_RUNNING 1
6340 #define CUR_STOPPED 0
6341
6342 /* mode flags for dowait */
6343 #define DOWAIT_NORMAL 0
6344 #define DOWAIT_BLOCK 1
6345
6346 /* array of jobs */
6347 static struct job *jobtab;
6348 /* size of array */
6349 static unsigned njobs;
6350 #if JOBS
6351 /* pgrp of shell on invocation */
6352 static int initialpgrp;
6353 static int ttyfd = -1;
6354 #endif
6355 /* current job */
6356 static struct job *curjob;
6357 /* number of presumed living untracked jobs */
6358 static int jobless;
6359
6360 static void set_curjob(struct job *, unsigned);
6361 #if JOBS
6362 static int restartjob(struct job *, int);
6363 static void xtcsetpgrp(int, pid_t);
6364 static char *commandtext(union node *);
6365 static void cmdlist(union node *, int);
6366 static void cmdtxt(union node *);
6367 static void cmdputs(const char *);
6368 static void showpipe(struct job *, FILE *);
6369 #endif
6370 static int sprint_status(char *, int, int);
6371 static void freejob(struct job *);
6372 static struct job *getjob(const char *, int);
6373 static struct job *growjobtab(void);
6374 static void forkchild(struct job *, union node *, int);
6375 static void forkparent(struct job *, union node *, int, pid_t);
6376 static int dowait(int, struct job *);
6377 static int getstatus(struct job *);
6378
6379 static void
6380 set_curjob(struct job *jp, unsigned mode)
6381 {
6382         struct job *jp1;
6383         struct job **jpp, **curp;
6384
6385         /* first remove from list */
6386         jpp = curp = &curjob;
6387         do {
6388                 jp1 = *jpp;
6389                 if (jp1 == jp)
6390                         break;
6391                 jpp = &jp1->prev_job;
6392         } while (1);
6393         *jpp = jp1->prev_job;
6394
6395         /* Then re-insert in correct position */
6396         jpp = curp;
6397         switch (mode) {
6398         default:
6399 #ifdef DEBUG
6400                 abort();
6401 #endif
6402         case CUR_DELETE:
6403                 /* job being deleted */
6404                 break;
6405         case CUR_RUNNING:
6406                 /* newly created job or backgrounded job,
6407                    put after all stopped jobs. */
6408                 do {
6409                         jp1 = *jpp;
6410 #ifdef JOBS
6411                         if (!jp1 || jp1->state != JOBSTOPPED)
6412 #endif
6413                                 break;
6414                         jpp = &jp1->prev_job;
6415                 } while (1);
6416                 /* FALLTHROUGH */
6417 #ifdef JOBS
6418         case CUR_STOPPED:
6419 #endif
6420                 /* newly stopped job - becomes curjob */
6421                 jp->prev_job = *jpp;
6422                 *jpp = jp;
6423                 break;
6424         }
6425 }
6426
6427 #if JOBS
6428 /*
6429  * Turn job control on and off.
6430  *
6431  * Note:  This code assumes that the third arg to ioctl is a character
6432  * pointer, which is true on Berkeley systems but not System V.  Since
6433  * System V doesn't have job control yet, this isn't a problem now.
6434  *
6435  * Called with interrupts off.
6436  */
6437
6438 void
6439 setjobctl(int on)
6440 {
6441         int fd;
6442         int pgrp;
6443
6444         if (on == jobctl || rootshell == 0)
6445                 return;
6446         if (on) {
6447                 int ofd;
6448                 ofd = fd = open(_PATH_TTY, O_RDWR);
6449                 if (fd < 0) {
6450                         fd += 3;
6451                         while (!isatty(fd) && --fd >= 0)
6452                                 ;
6453                 }
6454                 fd = fcntl(fd, F_DUPFD, 10);
6455                 close(ofd);
6456                 if (fd < 0)
6457                         goto out;
6458                 fcntl(fd, F_SETFD, FD_CLOEXEC);
6459                 do { /* while we are in the background */
6460                         if ((pgrp = tcgetpgrp(fd)) < 0) {
6461 out:
6462                                 sh_warnx("can't access tty; job control turned off");
6463                                 mflag = on = 0;
6464                                 goto close;
6465                         }
6466                         if (pgrp == getpgrp())
6467                                 break;
6468                         killpg(0, SIGTTIN);
6469                 } while (1);
6470                 initialpgrp = pgrp;
6471
6472                 setsignal(SIGTSTP);
6473                 setsignal(SIGTTOU);
6474                 setsignal(SIGTTIN);
6475                 pgrp = rootpid;
6476                 setpgid(0, pgrp);
6477                 xtcsetpgrp(fd, pgrp);
6478         } else {
6479                 /* turning job control off */
6480                 fd = ttyfd;
6481                 pgrp = initialpgrp;
6482                 xtcsetpgrp(fd, pgrp);
6483                 setpgid(0, pgrp);
6484                 setsignal(SIGTSTP);
6485                 setsignal(SIGTTOU);
6486                 setsignal(SIGTTIN);
6487 close:
6488                 close(fd);
6489                 fd = -1;
6490         }
6491         ttyfd = fd;
6492         jobctl = on;
6493 }
6494
6495 static int
6496 killcmd(int argc, char **argv)
6497 {
6498         int signo = -1;
6499         int list = 0;
6500         int i;
6501         pid_t pid;
6502         struct job *jp;
6503
6504         if (argc <= 1) {
6505 usage:
6506                 error(
6507 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6508 "kill -l [exitstatus]"
6509                 );
6510         }
6511
6512         if (**++argv == '-') {
6513                 signo = decode_signal(*argv + 1, 1);
6514                 if (signo < 0) {
6515                         int c;
6516
6517                         while ((c = nextopt("ls:")) != '\0')
6518                                 switch (c) {
6519                                 default:
6520 #ifdef DEBUG
6521                                         abort();
6522 #endif
6523                                 case 'l':
6524                                         list = 1;
6525                                         break;
6526                                 case 's':
6527                                         signo = decode_signal(optionarg, 1);
6528                                         if (signo < 0) {
6529                                                 error(
6530                                                         "invalid signal number or name: %s",
6531                                                         optionarg
6532                                                 );
6533                                         }
6534                                         break;
6535                                 }
6536                         argv = argptr;
6537                 } else
6538                         argv++;
6539         }
6540
6541         if (!list && signo < 0)
6542                 signo = SIGTERM;
6543
6544         if ((signo < 0 || !*argv) ^ list) {
6545                 goto usage;
6546         }
6547
6548         if (list) {
6549                 const char *name;
6550
6551                 if (!*argv) {
6552                         for (i = 1; i < NSIG; i++) {
6553                                 name = u_signal_names(0, &i, 1);
6554                                 if (name)
6555                                         out1fmt(snlfmt, name);
6556                         }
6557                         return 0;
6558                 }
6559                 name = u_signal_names(*argptr, &signo, -1);
6560                 if (name)
6561                         out1fmt(snlfmt, name);
6562                 else
6563                         error("invalid signal number or exit status: %s", *argptr);
6564                 return 0;
6565         }
6566
6567         i = 0;
6568         do {
6569                 if (**argv == '%') {
6570                         jp = getjob(*argv, 0);
6571                         pid = -jp->ps[0].pid;
6572                 } else
6573                         pid = number(*argv);
6574                 if (kill(pid, signo) != 0) {
6575                         sh_warnx("%m\n");
6576                         i = 1;
6577                 }
6578         } while (*++argv);
6579
6580         return i;
6581 }
6582 #endif /* JOBS */
6583
6584 #if defined(JOBS) || defined(DEBUG)
6585 static int
6586 jobno(const struct job *jp)
6587 {
6588         return jp - jobtab + 1;
6589 }
6590 #endif
6591
6592 #ifdef JOBS
6593 static int
6594 fgcmd(int argc, char **argv)
6595 {
6596         struct job *jp;
6597         FILE *out;
6598         int mode;
6599         int retval;
6600
6601         mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6602         nextopt(nullstr);
6603         argv = argptr;
6604         out = stdout;
6605         do {
6606                 jp = getjob(*argv, 1);
6607                 if (mode == FORK_BG) {
6608                         set_curjob(jp, CUR_RUNNING);
6609                         fprintf(out, "[%d] ", jobno(jp));
6610                 }
6611                 outstr(jp->ps->cmd, out);
6612                 showpipe(jp, out);
6613                 retval = restartjob(jp, mode);
6614         } while (*argv && *++argv);
6615         return retval;
6616 }
6617
6618 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6619
6620
6621 static int
6622 restartjob(struct job *jp, int mode)
6623 {
6624         struct procstat *ps;
6625         int i;
6626         int status;
6627         pid_t pgid;
6628
6629         INTOFF;
6630         if (jp->state == JOBDONE)
6631                 goto out;
6632         jp->state = JOBRUNNING;
6633         pgid = jp->ps->pid;
6634         if (mode == FORK_FG)
6635                 xtcsetpgrp(ttyfd, pgid);
6636         killpg(pgid, SIGCONT);
6637         ps = jp->ps;
6638         i = jp->nprocs;
6639         do {
6640                 if (WIFSTOPPED(ps->status)) {
6641                         ps->status = -1;
6642                 }
6643         } while (ps++, --i);
6644 out:
6645         status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6646         INTON;
6647         return status;
6648 }
6649 #endif
6650
6651 static int
6652 sprint_status(char *s, int status, int sigonly)
6653 {
6654         int col;
6655         int st;
6656
6657         col = 0;
6658         if (!WIFEXITED(status)) {
6659 #if JOBS
6660                 if (WIFSTOPPED(status))
6661                         st = WSTOPSIG(status);
6662                 else
6663 #endif
6664                         st = WTERMSIG(status);
6665                 if (sigonly) {
6666                         if (st == SIGINT || st == SIGPIPE)
6667                                 goto out;
6668 #if JOBS
6669                         if (WIFSTOPPED(status))
6670                                 goto out;
6671 #endif
6672                 }
6673                 st &= 0x7f;
6674                 col = fmtstr(s, 32, strsignal(st));
6675                 if (WCOREDUMP(status)) {
6676                         col += fmtstr(s + col, 16, " (core dumped)");
6677                 }
6678         } else if (!sigonly) {
6679                 st = WEXITSTATUS(status);
6680                 if (st)
6681                         col = fmtstr(s, 16, "Done(%d)", st);
6682                 else
6683                         col = fmtstr(s, 16, "Done");
6684         }
6685
6686 out:
6687         return col;
6688 }
6689
6690 #if JOBS
6691 static void
6692 showjob(FILE *out, struct job *jp, int mode)
6693 {
6694         struct procstat *ps;
6695         struct procstat *psend;
6696         int col;
6697         int indent;
6698         char s[80];
6699
6700         ps = jp->ps;
6701
6702         if (mode & SHOW_PGID) {
6703                 /* just output process (group) id of pipeline */
6704                 fprintf(out, "%d\n", ps->pid);
6705                 return;
6706         }
6707
6708         col = fmtstr(s, 16, "[%d]   ", jobno(jp));
6709         indent = col;
6710
6711         if (jp == curjob)
6712                 s[col - 2] = '+';
6713         else if (curjob && jp == curjob->prev_job)
6714                 s[col - 2] = '-';
6715
6716         if (mode & SHOW_PID)
6717                 col += fmtstr(s + col, 16, "%d ", ps->pid);
6718
6719         psend = ps + jp->nprocs;
6720
6721         if (jp->state == JOBRUNNING) {
6722                 scopy("Running", s + col);
6723                 col += strlen("Running");
6724         } else {
6725                 int status = psend[-1].status;
6726 #if JOBS
6727                 if (jp->state == JOBSTOPPED)
6728                         status = jp->stopstatus;
6729 #endif
6730                 col += sprint_status(s + col, status, 0);
6731         }
6732
6733         goto start;
6734
6735         do {
6736                 /* for each process */
6737                 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6738
6739 start:
6740                 fprintf(out, "%s%*c%s",
6741                         s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6742                 );
6743                 if (!(mode & SHOW_PID)) {
6744                         showpipe(jp, out);
6745                         break;
6746                 }
6747                 if (++ps == psend) {
6748                         outcslow('\n', out);
6749                         break;
6750                 }
6751         } while (1);
6752
6753         jp->changed = 0;
6754
6755         if (jp->state == JOBDONE) {
6756                 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6757                 freejob(jp);
6758         }
6759 }
6760
6761
6762 static int
6763 jobscmd(int argc, char **argv)
6764 {
6765         int mode, m;
6766         FILE *out;
6767
6768         mode = 0;
6769         while ((m = nextopt("lp")))
6770                 if (m == 'l')
6771                         mode = SHOW_PID;
6772                 else
6773                         mode = SHOW_PGID;
6774
6775         out = stdout;
6776         argv = argptr;
6777         if (*argv)
6778                 do
6779                         showjob(out, getjob(*argv,0), mode);
6780                 while (*++argv);
6781         else
6782                 showjobs(out, mode);
6783
6784         return 0;
6785 }
6786
6787
6788 /*
6789  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
6790  * statuses have changed since the last call to showjobs.
6791  */
6792
6793 static void
6794 showjobs(FILE *out, int mode)
6795 {
6796         struct job *jp;
6797
6798         TRACE(("showjobs(%x) called\n", mode));
6799
6800         /* If not even one one job changed, there is nothing to do */
6801         while (dowait(DOWAIT_NORMAL, NULL) > 0)
6802                 continue;
6803
6804         for (jp = curjob; jp; jp = jp->prev_job) {
6805                 if (!(mode & SHOW_CHANGED) || jp->changed)
6806                         showjob(out, jp, mode);
6807         }
6808 }
6809 #endif /* JOBS */
6810
6811 /*
6812  * Mark a job structure as unused.
6813  */
6814
6815 static void
6816 freejob(struct job *jp)
6817 {
6818         struct procstat *ps;
6819         int i;
6820
6821         INTOFF;
6822         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6823                 if (ps->cmd != nullstr)
6824                         ckfree(ps->cmd);
6825         }
6826         if (jp->ps != &jp->ps0)
6827                 ckfree(jp->ps);
6828         jp->used = 0;
6829         set_curjob(jp, CUR_DELETE);
6830         INTON;
6831 }
6832
6833
6834 static int
6835 waitcmd(int argc, char **argv)
6836 {
6837         struct job *job;
6838         int retval;
6839         struct job *jp;
6840
6841         EXSIGON();
6842
6843         nextopt(nullstr);
6844         retval = 0;
6845
6846         argv = argptr;
6847         if (!*argv) {
6848                 /* wait for all jobs */
6849                 for (;;) {
6850                         jp = curjob;
6851                         while (1) {
6852                                 if (!jp) {
6853                                         /* no running procs */
6854                                         goto out;
6855                                 }
6856                                 if (jp->state == JOBRUNNING)
6857                                         break;
6858                                 jp->waited = 1;
6859                                 jp = jp->prev_job;
6860                         }
6861                         dowait(DOWAIT_BLOCK, 0);
6862                 }
6863         }
6864
6865         retval = 127;
6866         do {
6867                 if (**argv != '%') {
6868                         pid_t pid = number(*argv);
6869                         job = curjob;
6870                         goto start;
6871                         do {
6872                                 if (job->ps[job->nprocs - 1].pid == pid)
6873                                         break;
6874                                 job = job->prev_job;
6875 start:
6876                                 if (!job)
6877                                         goto repeat;
6878                         } while (1);
6879                 } else
6880                         job = getjob(*argv, 0);
6881                 /* loop until process terminated or stopped */
6882                 while (job->state == JOBRUNNING)
6883                         dowait(DOWAIT_BLOCK, 0);
6884                 job->waited = 1;
6885                 retval = getstatus(job);
6886 repeat:
6887                 ;
6888         } while (*++argv);
6889
6890 out:
6891         return retval;
6892 }
6893
6894
6895 /*
6896  * Convert a job name to a job structure.
6897  */
6898
6899 static struct job *
6900 getjob(const char *name, int getctl)
6901 {
6902         struct job *jp;
6903         struct job *found;
6904         const char *err_msg = "No such job: %s";
6905         unsigned num;
6906         int c;
6907         const char *p;
6908         char *(*match)(const char *, const char *);
6909
6910         jp = curjob;
6911         p = name;
6912         if (!p)
6913                 goto currentjob;
6914
6915         if (*p != '%')
6916                 goto err;
6917
6918         c = *++p;
6919         if (!c)
6920                 goto currentjob;
6921
6922         if (!p[1]) {
6923                 if (c == '+' || c == '%') {
6924 currentjob:
6925                         err_msg = "No current job";
6926                         goto check;
6927                 } else if (c == '-') {
6928                         if (jp)
6929                                 jp = jp->prev_job;
6930                         err_msg = "No previous job";
6931 check:
6932                         if (!jp)
6933                                 goto err;
6934                         goto gotit;
6935                 }
6936         }
6937
6938         if (is_number(p)) {
6939                 num = atoi(p);
6940                 if (num < njobs) {
6941                         jp = jobtab + num - 1;
6942                         if (jp->used)
6943                                 goto gotit;
6944                         goto err;
6945                 }
6946         }
6947
6948         match = prefix;
6949         if (*p == '?') {
6950                 match = strstr;
6951                 p++;
6952         }
6953
6954         found = 0;
6955         while (1) {
6956                 if (!jp)
6957                         goto err;
6958                 if (match(jp->ps[0].cmd, p)) {
6959                         if (found)
6960                                 goto err;
6961                         found = jp;
6962                         err_msg = "%s: ambiguous";
6963                 }
6964                 jp = jp->prev_job;
6965         }
6966
6967 gotit:
6968 #if JOBS
6969         err_msg = "job %s not created under job control";
6970         if (getctl && jp->jobctl == 0)
6971                 goto err;
6972 #endif
6973         return jp;
6974 err:
6975         error(err_msg, name);
6976 }
6977
6978
6979 /*
6980  * Return a new job structure.
6981  * Called with interrupts off.
6982  */
6983
6984 static struct job *
6985 makejob(union node *node, int nprocs)
6986 {
6987         int i;
6988         struct job *jp;
6989
6990         for (i = njobs, jp = jobtab ; ; jp++) {
6991                 if (--i < 0) {
6992                         jp = growjobtab();
6993                         break;
6994                 }
6995                 if (jp->used == 0)
6996                         break;
6997                 if (jp->state != JOBDONE || !jp->waited)
6998                         continue;
6999 #if JOBS
7000                 if (jobctl)
7001                         continue;
7002 #endif
7003                 freejob(jp);
7004                 break;
7005         }
7006         memset(jp, 0, sizeof(*jp));
7007 #if JOBS
7008         if (jobctl)
7009                 jp->jobctl = 1;
7010 #endif
7011         jp->prev_job = curjob;
7012         curjob = jp;
7013         jp->used = 1;
7014         jp->ps = &jp->ps0;
7015         if (nprocs > 1) {
7016                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7017         }
7018         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7019             jobno(jp)));
7020         return jp;
7021 }
7022
7023 static struct job *
7024 growjobtab(void)
7025 {
7026         size_t len;
7027         ptrdiff_t offset;
7028         struct job *jp, *jq;
7029
7030         len = njobs * sizeof(*jp);
7031         jq = jobtab;
7032         jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7033
7034         offset = (char *)jp - (char *)jq;
7035         if (offset) {
7036                 /* Relocate pointers */
7037                 size_t l = len;
7038
7039                 jq = (struct job *)((char *)jq + l);
7040                 while (l) {
7041                         l -= sizeof(*jp);
7042                         jq--;
7043 #define joff(p) ((struct job *)((char *)(p) + l))
7044 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7045                         if (likely(joff(jp)->ps == &jq->ps0))
7046                                 jmove(joff(jp)->ps);
7047                         if (joff(jp)->prev_job)
7048                                 jmove(joff(jp)->prev_job);
7049                 }
7050                 if (curjob)
7051                         jmove(curjob);
7052 #undef joff
7053 #undef jmove
7054         }
7055
7056         njobs += 4;
7057         jobtab = jp;
7058         jp = (struct job *)((char *)jp + len);
7059         jq = jp + 3;
7060         do {
7061                 jq->used = 0;
7062         } while (--jq >= jp);
7063         return jp;
7064 }
7065
7066
7067 /*
7068  * Fork off a subshell.  If we are doing job control, give the subshell its
7069  * own process group.  Jp is a job structure that the job is to be added to.
7070  * N is the command that will be evaluated by the child.  Both jp and n may
7071  * be NULL.  The mode parameter can be one of the following:
7072  *      FORK_FG - Fork off a foreground process.
7073  *      FORK_BG - Fork off a background process.
7074  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
7075  *                   process group even if job control is on.
7076  *
7077  * When job control is turned off, background processes have their standard
7078  * input redirected to /dev/null (except for the second and later processes
7079  * in a pipeline).
7080  *
7081  * Called with interrupts off.
7082  */
7083
7084 static inline void
7085 forkchild(struct job *jp, union node *n, int mode)
7086 {
7087         int wasroot;
7088
7089         TRACE(("Child shell %d\n", getpid()));
7090         wasroot = rootshell;
7091         rootshell = 0;
7092
7093         closescript();
7094         clear_traps();
7095 #if JOBS
7096         /* do job control only in root shell */
7097         jobctl = 0;
7098         if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7099                 pid_t pgrp;
7100
7101                 if (jp->nprocs == 0)
7102                         pgrp = getpid();
7103                 else
7104                         pgrp = jp->ps[0].pid;
7105                 /* This can fail because we are doing it in the parent also */
7106                 (void)setpgid(0, pgrp);
7107                 if (mode == FORK_FG)
7108                         xtcsetpgrp(ttyfd, pgrp);
7109                 setsignal(SIGTSTP);
7110                 setsignal(SIGTTOU);
7111         } else
7112 #endif
7113         if (mode == FORK_BG) {
7114                 ignoresig(SIGINT);
7115                 ignoresig(SIGQUIT);
7116                 if (jp->nprocs == 0) {
7117                         close(0);
7118                         if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7119                                 error("Can't open %s", _PATH_DEVNULL);
7120                 }
7121         }
7122         if (wasroot && iflag) {
7123                 setsignal(SIGINT);
7124                 setsignal(SIGQUIT);
7125                 setsignal(SIGTERM);
7126         }
7127         for (jp = curjob; jp; jp = jp->prev_job)
7128                 freejob(jp);
7129         jobless = 0;
7130 }
7131
7132 static inline void
7133 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7134 {
7135         TRACE(("In parent shell:  child = %d\n", pid));
7136         if (!jp) {
7137                 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7138                 jobless++;
7139                 return;
7140         }
7141 #if JOBS
7142         if (mode != FORK_NOJOB && jp->jobctl) {
7143                 int pgrp;
7144
7145                 if (jp->nprocs == 0)
7146                         pgrp = pid;
7147                 else
7148                         pgrp = jp->ps[0].pid;
7149                 /* This can fail because we are doing it in the child also */
7150                 (void)setpgid(pid, pgrp);
7151         }
7152 #endif
7153         if (mode == FORK_BG) {
7154                 backgndpid = pid;               /* set $! */
7155                 set_curjob(jp, CUR_RUNNING);
7156         }
7157         if (jp) {
7158                 struct procstat *ps = &jp->ps[jp->nprocs++];
7159                 ps->pid = pid;
7160                 ps->status = -1;
7161                 ps->cmd = nullstr;
7162 #if JOBS
7163                 if (jobctl && n)
7164                         ps->cmd = commandtext(n);
7165 #endif
7166         }
7167 }
7168
7169 static int
7170 forkshell(struct job *jp, union node *n, int mode)
7171 {
7172         int pid;
7173
7174         TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7175         pid = fork();
7176         if (pid < 0) {
7177                 TRACE(("Fork failed, errno=%d", errno));
7178                 if (jp)
7179                         freejob(jp);
7180                 error("Cannot fork");
7181         }
7182         if (pid == 0)
7183                 forkchild(jp, n, mode);
7184         else
7185                 forkparent(jp, n, mode, pid);
7186         return pid;
7187 }
7188
7189 /*
7190  * Wait for job to finish.
7191  *
7192  * Under job control we have the problem that while a child process is
7193  * running interrupts generated by the user are sent to the child but not
7194  * to the shell.  This means that an infinite loop started by an inter-
7195  * active user may be hard to kill.  With job control turned off, an
7196  * interactive user may place an interactive program inside a loop.  If
7197  * the interactive program catches interrupts, the user doesn't want
7198  * these interrupts to also abort the loop.  The approach we take here
7199  * is to have the shell ignore interrupt signals while waiting for a
7200  * forground process to terminate, and then send itself an interrupt
7201  * signal if the child process was terminated by an interrupt signal.
7202  * Unfortunately, some programs want to do a bit of cleanup and then
7203  * exit on interrupt; unless these processes terminate themselves by
7204  * sending a signal to themselves (instead of calling exit) they will
7205  * confuse this approach.
7206  *
7207  * Called with interrupts off.
7208  */
7209
7210 int
7211 waitforjob(struct job *jp)
7212 {
7213         int st;
7214
7215         TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7216         while (jp->state == JOBRUNNING) {
7217                 dowait(DOWAIT_BLOCK, jp);
7218         }
7219         st = getstatus(jp);
7220 #if JOBS
7221         if (jp->jobctl) {
7222                 xtcsetpgrp(ttyfd, rootpid);
7223                 /*
7224                  * This is truly gross.
7225                  * If we're doing job control, then we did a TIOCSPGRP which
7226                  * caused us (the shell) to no longer be in the controlling
7227                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
7228                  * intuit from the subprocess exit status whether a SIGINT
7229                  * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
7230                  */
7231                 if (jp->sigint)
7232                         raise(SIGINT);
7233         }
7234         if (jp->state == JOBDONE)
7235 #endif
7236                 freejob(jp);
7237         return st;
7238 }
7239
7240
7241 /*
7242  * Do a wait system call.  If job control is compiled in, we accept
7243  * stopped processes.  If block is zero, we return a value of zero
7244  * rather than blocking.
7245  *
7246  * System V doesn't have a non-blocking wait system call.  It does
7247  * have a SIGCLD signal that is sent to a process when one of it's
7248  * children dies.  The obvious way to use SIGCLD would be to install
7249  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7250  * was received, and have waitproc bump another counter when it got
7251  * the status of a process.  Waitproc would then know that a wait
7252  * system call would not block if the two counters were different.
7253  * This approach doesn't work because if a process has children that
7254  * have not been waited for, System V will send it a SIGCLD when it
7255  * installs a signal handler for SIGCLD.  What this means is that when
7256  * a child exits, the shell will be sent SIGCLD signals continuously
7257  * until is runs out of stack space, unless it does a wait call before
7258  * restoring the signal handler.  The code below takes advantage of
7259  * this (mis)feature by installing a signal handler for SIGCLD and
7260  * then checking to see whether it was called.  If there are any
7261  * children to be waited for, it will be.
7262  *
7263  * If neither SYSV nor BSD is defined, we don't implement nonblocking
7264  * waits at all.  In this case, the user will not be informed when
7265  * a background process until the next time she runs a real program
7266  * (as opposed to running a builtin command or just typing return),
7267  * and the jobs command may give out of date information.
7268  */
7269
7270 static inline int
7271 waitproc(int block, int *status)
7272 {
7273         int flags = 0;
7274
7275 #if JOBS
7276         if (jobctl)
7277                 flags |= WUNTRACED;
7278 #endif
7279         if (block == 0)
7280                 flags |= WNOHANG;
7281         return wait3(status, flags, (struct rusage *)NULL);
7282 }
7283
7284 /*
7285  * Wait for a process to terminate.
7286  */
7287
7288 static int
7289 dowait(int block, struct job *job)
7290 {
7291         int pid;
7292         int status;
7293         struct job *jp;
7294         struct job *thisjob;
7295         int state;
7296
7297         TRACE(("dowait(%d) called\n", block));
7298         pid = waitproc(block, &status);
7299         TRACE(("wait returns pid %d, status=%d\n", pid, status));
7300         if (pid <= 0)
7301                 return pid;
7302         INTOFF;
7303         thisjob = NULL;
7304         for (jp = curjob; jp; jp = jp->prev_job) {
7305                 struct procstat *sp;
7306                 struct procstat *spend;
7307                 if (jp->state == JOBDONE)
7308                         continue;
7309                 state = JOBDONE;
7310                 spend = jp->ps + jp->nprocs;
7311                 sp = jp->ps;
7312                 do {
7313                         if (sp->pid == pid) {
7314                                 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7315                                 sp->status = status;
7316                                 thisjob = jp;
7317                         }
7318                         if (sp->status == -1)
7319                                 state = JOBRUNNING;
7320 #ifdef JOBS
7321                         if (state == JOBRUNNING)
7322                                 continue;
7323                         if (WIFSTOPPED(sp->status)) {
7324                                 jp->stopstatus = sp->status;
7325                                 state = JOBSTOPPED;
7326                         }
7327 #endif
7328                 } while (++sp < spend);
7329                 if (thisjob)
7330                         goto gotjob;
7331         }
7332 #ifdef JOBS
7333         if (!WIFSTOPPED(status))
7334 #endif
7335
7336                 jobless--;
7337         goto out;
7338
7339 gotjob:
7340         if (state != JOBRUNNING) {
7341                 thisjob->changed = 1;
7342
7343                 if (thisjob->state != state) {
7344                         TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7345                         thisjob->state = state;
7346 #ifdef JOBS
7347                         if (state == JOBSTOPPED) {
7348                                 set_curjob(thisjob, CUR_STOPPED);
7349                         }
7350 #endif
7351                 }
7352         }
7353
7354 out:
7355         INTON;
7356
7357         if (thisjob && thisjob == job) {
7358                 char s[48 + 1];
7359                 int len;
7360
7361                 len = sprint_status(s, status, 1);
7362                 if (len) {
7363                         s[len] = '\n';
7364                         s[len + 1] = 0;
7365                         out2str(s);
7366                 }
7367         }
7368         return pid;
7369 }
7370
7371
7372 /*
7373  * return 1 if there are stopped jobs, otherwise 0
7374  */
7375
7376 int
7377 stoppedjobs(void)
7378 {
7379         struct job *jp;
7380         int retval;
7381
7382         retval = 0;
7383         if (job_warning)
7384                 goto out;
7385         jp = curjob;
7386         if (jp && jp->state == JOBSTOPPED) {
7387                 out2str("You have stopped jobs.\n");
7388                 job_warning = 2;
7389                 retval++;
7390         }
7391
7392 out:
7393         return retval;
7394 }
7395
7396 /*
7397  * Return a string identifying a command (to be printed by the
7398  * jobs command).
7399  */
7400
7401 #if JOBS
7402 static char *cmdnextc;
7403
7404 static char *
7405 commandtext(union node *n)
7406 {
7407         char *name;
7408
7409         STARTSTACKSTR(cmdnextc);
7410         cmdtxt(n);
7411         name = stackblock();
7412         TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7413                 name, cmdnextc, cmdnextc));
7414         return savestr(name);
7415 }
7416
7417 static void
7418 cmdtxt(union node *n)
7419 {
7420         union node *np;
7421         struct nodelist *lp;
7422         const char *p;
7423         char s[2];
7424
7425         switch (n->type) {
7426         default:
7427 #if DEBUG
7428                 abort();
7429 #endif
7430         case NPIPE:
7431                 lp = n->npipe.cmdlist;
7432                 for (;;) {
7433                         cmdtxt(lp->n);
7434                         lp = lp->next;
7435                         if (!lp)
7436                                 break;
7437                         cmdputs(" | ");
7438                 }
7439                 break;
7440         case NSEMI:
7441                 p = "; ";
7442                 goto binop;
7443         case NAND:
7444                 p = " && ";
7445                 goto binop;
7446         case NOR:
7447                 p = " || ";
7448 binop:
7449                 cmdtxt(n->nbinary.ch1);
7450                 cmdputs(p);
7451                 n = n->nbinary.ch2;
7452                 goto donode;
7453         case NREDIR:
7454         case NBACKGND:
7455                 n = n->nredir.n;
7456                 goto donode;
7457         case NNOT:
7458                 cmdputs("!");
7459                 n = n->nnot.com;
7460 donode:
7461                 cmdtxt(n);
7462                 break;
7463         case NIF:
7464                 cmdputs("if ");
7465                 cmdtxt(n->nif.test);
7466                 cmdputs("; then ");
7467                 n = n->nif.ifpart;
7468                 if (n->nif.elsepart) {
7469                         cmdtxt(n);
7470                         cmdputs("; else ");
7471                         n = n->nif.elsepart;
7472                 }
7473                 p = "; fi";
7474                 goto dotail;
7475         case NSUBSHELL:
7476                 cmdputs("(");
7477                 n = n->nredir.n;
7478                 p = ")";
7479                 goto dotail;
7480         case NWHILE:
7481                 p = "while ";
7482                 goto until;
7483         case NUNTIL:
7484                 p = "until ";
7485 until:
7486                 cmdputs(p);
7487                 cmdtxt(n->nbinary.ch1);
7488                 n = n->nbinary.ch2;
7489                 p = "; done";
7490 dodo:
7491                 cmdputs("; do ");
7492 dotail:
7493                 cmdtxt(n);
7494                 goto dotail2;
7495         case NFOR:
7496                 cmdputs("for ");
7497                 cmdputs(n->nfor.var);
7498                 cmdputs(" in ");
7499                 cmdlist(n->nfor.args, 1);
7500                 n = n->nfor.body;
7501                 p = "; done";
7502                 goto dodo;
7503         case NDEFUN:
7504                 cmdputs(n->narg.text);
7505                 p = "() { ... }";
7506                 goto dotail2;
7507         case NCMD:
7508                 cmdlist(n->ncmd.args, 1);
7509                 cmdlist(n->ncmd.redirect, 0);
7510                 break;
7511         case NARG:
7512                 p = n->narg.text;
7513 dotail2:
7514                 cmdputs(p);
7515                 break;
7516         case NHERE:
7517         case NXHERE:
7518                 p = "<<...";
7519                 goto dotail2;
7520         case NCASE:
7521                 cmdputs("case ");
7522                 cmdputs(n->ncase.expr->narg.text);
7523                 cmdputs(" in ");
7524                 for (np = n->ncase.cases; np; np = np->nclist.next) {
7525                         cmdtxt(np->nclist.pattern);
7526                         cmdputs(") ");
7527                         cmdtxt(np->nclist.body);
7528                         cmdputs(";; ");
7529                 }
7530                 p = "esac";
7531                 goto dotail2;
7532         case NTO:
7533                 p = ">";
7534                 goto redir;
7535         case NCLOBBER:
7536                 p = ">|";
7537                 goto redir;
7538         case NAPPEND:
7539                 p = ">>";
7540                 goto redir;
7541         case NTOFD:
7542                 p = ">&";
7543                 goto redir;
7544         case NFROM:
7545                 p = "<";
7546                 goto redir;
7547         case NFROMFD:
7548                 p = "<&";
7549                 goto redir;
7550         case NFROMTO:
7551                 p = "<>";
7552 redir:
7553                 s[0] = n->nfile.fd + '0';
7554                 s[1] = '\0';
7555                 cmdputs(s);
7556                 cmdputs(p);
7557                 if (n->type == NTOFD || n->type == NFROMFD) {
7558                         s[0] = n->ndup.dupfd + '0';
7559                         p = s;
7560                         goto dotail2;
7561                 } else {
7562                         n = n->nfile.fname;
7563                         goto donode;
7564                 }
7565         }
7566 }
7567
7568 static void
7569 cmdlist(union node *np, int sep)
7570 {
7571         for (; np; np = np->narg.next) {
7572                 if (!sep)
7573                         cmdputs(spcstr);
7574                 cmdtxt(np);
7575                 if (sep && np->narg.next)
7576                         cmdputs(spcstr);
7577         }
7578 }
7579
7580 static void
7581 cmdputs(const char *s)
7582 {
7583         const char *p, *str;
7584         char c, cc[2] = " ";
7585         char *nextc;
7586         int subtype = 0;
7587         int quoted = 0;
7588         static const char *const vstype[16] = {
7589                 nullstr, "}", "-", "+", "?", "=",
7590                 "#", "##", "%", "%%"
7591         };
7592
7593         nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7594         p = s;
7595         while ((c = *p++) != 0) {
7596                 str = 0;
7597                 switch (c) {
7598                 case CTLESC:
7599                         c = *p++;
7600                         break;
7601                 case CTLVAR:
7602                         subtype = *p++;
7603                         if ((subtype & VSTYPE) == VSLENGTH)
7604                                 str = "${#";
7605                         else
7606                                 str = "${";
7607                         if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7608                                 quoted ^= 1;
7609                                 c = '"';
7610                         } else
7611                                 goto dostr;
7612                         break;
7613                 case CTLENDVAR:
7614                         quoted >>= 1;
7615                         subtype = 0;
7616                         if (quoted & 1) {
7617                                 str = "\"}";
7618                                 goto dostr;
7619                         }
7620                         c = '}';
7621                         break;
7622                 case CTLBACKQ:
7623                         str = "$(...)";
7624                         goto dostr;
7625                 case CTLBACKQ+CTLQUOTE:
7626                         str = "\"$(...)\"";
7627                         goto dostr;
7628 #ifdef CONFIG_ASH_MATH_SUPPORT
7629                 case CTLARI:
7630                         str = "$((";
7631                         goto dostr;
7632                 case CTLENDARI:
7633                         str = "))";
7634                         goto dostr;
7635 #endif
7636                 case CTLQUOTEMARK:
7637                         quoted ^= 1;
7638                         c = '"';
7639                         break;
7640                 case '=':
7641                         if (subtype == 0)
7642                                 break;
7643                         str = vstype[subtype & VSTYPE];
7644                         if (subtype & VSNUL)
7645                                 c = ':';
7646                         else
7647                                 c = *str++;
7648                         if (c != '}')
7649                                 quoted <<= 1;
7650                         break;
7651                 case '\'':
7652                 case '\\':
7653                 case '"':
7654                 case '$':
7655                         /* These can only happen inside quotes */
7656                         cc[0] = c;
7657                         str = cc;
7658                         c = '\\';
7659                         break;
7660                 default:
7661                         break;
7662                 }
7663                 USTPUTC(c, nextc);
7664                 if (!str)
7665                         continue;
7666 dostr:
7667                 while ((c = *str++)) {
7668                         USTPUTC(c, nextc);
7669                 }
7670         }
7671         if (quoted & 1) {
7672                 USTPUTC('"', nextc);
7673         }
7674         *nextc = 0;
7675         cmdnextc = nextc;
7676 }
7677
7678
7679 static void
7680 showpipe(struct job *jp, FILE *out)
7681 {
7682         struct procstat *sp;
7683         struct procstat *spend;
7684
7685         spend = jp->ps + jp->nprocs;
7686         for (sp = jp->ps + 1; sp < spend; sp++)
7687                 fprintf(out, " | %s", sp->cmd);
7688         outcslow('\n', out);
7689         flushall();
7690 }
7691
7692 static void
7693 xtcsetpgrp(int fd, pid_t pgrp)
7694 {
7695         if (tcsetpgrp(fd, pgrp))
7696                 error("Cannot set tty process group (%m)");
7697 }
7698 #endif /* JOBS */
7699
7700 static int
7701 getstatus(struct job *job) {
7702         int status;
7703         int retval;
7704
7705         status = job->ps[job->nprocs - 1].status;
7706         retval = WEXITSTATUS(status);
7707         if (!WIFEXITED(status)) {
7708 #if JOBS
7709                 retval = WSTOPSIG(status);
7710                 if (!WIFSTOPPED(status))
7711 #endif
7712                 {
7713                         /* XXX: limits number of signals */
7714                         retval = WTERMSIG(status);
7715 #if JOBS
7716                         if (retval == SIGINT)
7717                                 job->sigint = 1;
7718 #endif
7719                 }
7720                 retval += 128;
7721         }
7722         TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7723                 jobno(job), job->nprocs, status, retval));
7724         return retval;
7725 }
7726
7727 #ifdef CONFIG_ASH_MAIL
7728 /*      $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $       */
7729
7730 /*
7731  * Routines to check for mail.  (Perhaps make part of main.c?)
7732  */
7733
7734 #define MAXMBOXES 10
7735
7736 /* times of mailboxes */
7737 static time_t mailtime[MAXMBOXES];
7738 /* Set if MAIL or MAILPATH is changed. */
7739 static int mail_var_path_changed;
7740
7741
7742
7743 /*
7744  * Print appropriate message(s) if mail has arrived.
7745  * If mail_var_path_changed is set,
7746  * then the value of MAIL has mail_var_path_changed,
7747  * so we just update the values.
7748  */
7749
7750 static void
7751 chkmail(void)
7752 {
7753         const char *mpath;
7754         char *p;
7755         char *q;
7756         time_t *mtp;
7757         struct stackmark smark;
7758         struct stat statb;
7759
7760         setstackmark(&smark);
7761         mpath = mpathset() ? mpathval() : mailval();
7762         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7763                 p = padvance(&mpath, nullstr);
7764                 if (p == NULL)
7765                         break;
7766                 if (*p == '\0')
7767                         continue;
7768                 for (q = p ; *q ; q++);
7769 #ifdef DEBUG
7770                 if (q[-1] != '/')
7771                         abort();
7772 #endif
7773                 q[-1] = '\0';                   /* delete trailing '/' */
7774                 if (stat(p, &statb) < 0) {
7775                         *mtp = 0;
7776                         continue;
7777                 }
7778                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7779                         fprintf(
7780                                 stderr, snlfmt,
7781                                 pathopt ? pathopt : "you have mail"
7782                         );
7783                 }
7784                 *mtp = statb.st_mtime;
7785         }
7786         mail_var_path_changed = 0;
7787         popstackmark(&smark);
7788 }
7789
7790
7791 static void
7792 changemail(const char *val)
7793 {
7794         mail_var_path_changed++;
7795 }
7796
7797 #endif /* CONFIG_ASH_MAIL */
7798
7799 /*      $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $       */
7800
7801
7802 #if PROFILE
7803 static short profile_buf[16384];
7804 extern int etext();
7805 #endif
7806
7807 static int isloginsh;
7808
7809 static void read_profile(const char *);
7810
7811 /*
7812  * Main routine.  We initialize things, parse the arguments, execute
7813  * profiles if we're a login shell, and then call cmdloop to execute
7814  * commands.  The setjmp call sets up the location to jump to when an
7815  * exception occurs.  When an exception occurs the variable "state"
7816  * is used to figure out how far we had gotten.
7817  */
7818
7819 int
7820 ash_main(int argc, char **argv)
7821 {
7822         char *shinit;
7823         volatile int state;
7824         struct jmploc jmploc;
7825         struct stackmark smark;
7826
7827 #ifdef __GLIBC__
7828         dash_errno = __errno_location();
7829 #endif
7830
7831 #if PROFILE
7832         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7833 #endif
7834         state = 0;
7835         if (setjmp(jmploc.loc)) {
7836                 int status;
7837                 int e;
7838
7839                 reset();
7840
7841                 e = exception;
7842                 switch (exception) {
7843                 case EXEXEC:
7844                         status = exerrno;
7845                         break;
7846
7847                 case EXERROR:
7848                         status = 2;
7849                         break;
7850
7851                 default:
7852                         status = exitstatus;
7853                         break;
7854                 }
7855                 exitstatus = status;
7856
7857                 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7858                         exitshell();
7859
7860                 if (e == EXINT) {
7861                         outcslow('\n', stderr);
7862                 }
7863                 popstackmark(&smark);
7864                 FORCEINTON;                             /* enable interrupts */
7865                 if (state == 1)
7866                         goto state1;
7867                 else if (state == 2)
7868                         goto state2;
7869                 else if (state == 3)
7870                         goto state3;
7871                 else
7872                         goto state4;
7873         }
7874         handler = &jmploc;
7875 #ifdef DEBUG
7876         opentrace();
7877         trputs("Shell args:  ");  trargs(argv);
7878 #endif
7879         rootpid = getpid();
7880         rootshell = 1;
7881         init();
7882         setstackmark(&smark);
7883         procargs(argc, argv);
7884 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7885         if ( iflag ) {
7886                 const char *hp = lookupvar("HISTFILE");
7887
7888                 if(hp == NULL ) {
7889                         hp = lookupvar("HOME");
7890                         if(hp != NULL) {
7891                                 char *defhp = concat_path_file(hp, ".ash_history");
7892                                 setvar("HISTFILE", defhp, 0);
7893                                 free(defhp);
7894                         }
7895                 }
7896         }
7897 #endif
7898         if (argv[0] && argv[0][0] == '-')
7899                 isloginsh = 1;
7900         if (isloginsh) {
7901                 state = 1;
7902                 read_profile("/etc/profile");
7903 state1:
7904                 state = 2;
7905                 read_profile(".profile");
7906         }
7907 state2:
7908         state = 3;
7909         if (
7910 #ifndef linux
7911                 getuid() == geteuid() && getgid() == getegid() &&
7912 #endif
7913                 iflag
7914         ) {
7915                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7916                         read_profile(shinit);
7917                 }
7918         }
7919 state3:
7920         state = 4;
7921         if (minusc)
7922                 evalstring(minusc);
7923
7924         if (sflag || minusc == NULL) {
7925 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7926             if ( iflag ) {
7927                 const char *hp = lookupvar("HISTFILE");
7928
7929                 if(hp != NULL )
7930                         load_history ( hp );
7931             }
7932 #endif
7933 state4: /* XXX ??? - why isn't this before the "if" statement */
7934                 cmdloop(1);
7935         }
7936 #if PROFILE
7937         monitor(0);
7938 #endif
7939 #if GPROF
7940         {
7941                 extern void _mcleanup(void);
7942                 _mcleanup();
7943         }
7944 #endif
7945         exitshell();
7946         /* NOTREACHED */
7947 }
7948
7949
7950 /*
7951  * Read and execute commands.  "Top" is nonzero for the top level command
7952  * loop; it turns on prompting if the shell is interactive.
7953  */
7954
7955 static void
7956 cmdloop(int top)
7957 {
7958         union node *n;
7959         struct stackmark smark;
7960         int inter;
7961         int numeof = 0;
7962
7963         TRACE(("cmdloop(%d) called\n", top));
7964         for (;;) {
7965                 setstackmark(&smark);
7966                 if (pendingsigs)
7967                         dotrap();
7968 #if JOBS
7969                 if (jobctl)
7970                         showjobs(stderr, SHOW_CHANGED);
7971 #endif
7972                 inter = 0;
7973                 if (iflag && top) {
7974                         inter++;
7975 #ifdef CONFIG_ASH_MAIL
7976                         chkmail();
7977 #endif
7978                 }
7979                 n = parsecmd(inter);
7980                 /* showtree(n); DEBUG */
7981                 if (n == NEOF) {
7982                         if (!top || numeof >= 50)
7983                                 break;
7984                         if (!stoppedjobs()) {
7985                                 if (!Iflag)
7986                                         break;
7987                                 out2str("\nUse \"exit\" to leave shell.\n");
7988                         }
7989                         numeof++;
7990                 } else if (n != NULL && nflag == 0) {
7991                         job_warning = (job_warning == 2) ? 1 : 0;
7992                         numeof = 0;
7993                         evaltree(n, 0);
7994                 }
7995                 popstackmark(&smark);
7996                 if (evalskip) {
7997                         evalskip = 0;
7998                         break;
7999                 }
8000         }
8001 }
8002
8003
8004 /*
8005  * Read /etc/profile or .profile.  Return on error.
8006  */
8007
8008 static void
8009 read_profile(const char *name)
8010 {
8011         int fd;
8012         int xflag_set = 0;
8013         int vflag_set = 0;
8014
8015         INTOFF;
8016         if ((fd = open(name, O_RDONLY)) >= 0)
8017                 setinputfd(fd, 1);
8018         INTON;
8019         if (fd < 0)
8020                 return;
8021         /* -q turns off -x and -v just when executing init files */
8022         if (qflag)  {
8023             if (xflag)
8024                     xflag = 0, xflag_set = 1;
8025             if (vflag)
8026                     vflag = 0, vflag_set = 1;
8027         }
8028         cmdloop(0);
8029         if (qflag)  {
8030             if (xflag_set)
8031                     xflag = 1;
8032             if (vflag_set)
8033                     vflag = 1;
8034         }
8035         popfile();
8036 }
8037
8038
8039 /*
8040  * Read a file containing shell functions.
8041  */
8042
8043 static void
8044 readcmdfile(char *name)
8045 {
8046         int fd;
8047
8048         INTOFF;
8049         if ((fd = open(name, O_RDONLY)) >= 0)
8050                 setinputfd(fd, 1);
8051         else
8052                 error("Can't open %s", name);
8053         INTON;
8054         cmdloop(0);
8055         popfile();
8056 }
8057
8058
8059 /*
8060  * Take commands from a file.  To be compatible we should do a path
8061  * search for the file, which is necessary to find sub-commands.
8062  */
8063
8064 static inline char *
8065 find_dot_file(char *name)
8066 {
8067         char *fullname;
8068         const char *path = pathval();
8069         struct stat statb;
8070
8071         /* don't try this for absolute or relative paths */
8072         if (strchr(name, '/'))
8073                 return name;
8074
8075         while ((fullname = padvance(&path, name)) != NULL) {
8076                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8077                         /*
8078                          * Don't bother freeing here, since it will
8079                          * be freed by the caller.
8080                          */
8081                         return fullname;
8082                 }
8083                 stunalloc(fullname);
8084         }
8085
8086         /* not found in the PATH */
8087         error(not_found_msg, name);
8088         /* NOTREACHED */
8089 }
8090
8091 int
8092 dotcmd(int argc, char **argv)
8093 {
8094         exitstatus = 0;
8095
8096         if (argc >= 2) {                /* That's what SVR2 does */
8097                 char *fullname;
8098                 struct stackmark smark;
8099
8100                 setstackmark(&smark);
8101                 fullname = find_dot_file(argv[1]);
8102                 setinputfile(fullname, 1);
8103                 commandname = fullname;
8104                 cmdloop(0);
8105                 popfile();
8106                 popstackmark(&smark);
8107         }
8108         return exitstatus;
8109 }
8110
8111
8112 static int
8113 exitcmd(int argc, char **argv)
8114 {
8115         if (stoppedjobs())
8116                 return 0;
8117         if (argc > 1)
8118                 exitstatus = number(argv[1]);
8119         exraise(EXEXIT);
8120         /* NOTREACHED */
8121 }
8122
8123 /*      $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $        */
8124
8125 /*
8126  * Same for malloc, realloc, but returns an error when out of space.
8127  */
8128
8129 static pointer
8130 ckrealloc(pointer p, size_t nbytes)
8131 {
8132         p = realloc(p, nbytes);
8133         if (p == NULL)
8134                 error(bb_msg_memory_exhausted);
8135         return p;
8136 }
8137
8138 static pointer
8139 ckmalloc(size_t nbytes)
8140 {
8141         return ckrealloc(NULL, nbytes);
8142 }
8143
8144 /*
8145  * Make a copy of a string in safe storage.
8146  */
8147
8148 static char *
8149 savestr(const char *s)
8150 {
8151         char *p = strdup(s);
8152         if (!p)
8153                 error(bb_msg_memory_exhausted);
8154         return p;
8155 }
8156
8157
8158 /*
8159  * Parse trees for commands are allocated in lifo order, so we use a stack
8160  * to make this more efficient, and also to avoid all sorts of exception
8161  * handling code to handle interrupts in the middle of a parse.
8162  *
8163  * The size 504 was chosen because the Ultrix malloc handles that size
8164  * well.
8165  */
8166
8167
8168 static pointer
8169 stalloc(size_t nbytes)
8170 {
8171         char *p;
8172         size_t aligned;
8173
8174         aligned = SHELL_ALIGN(nbytes);
8175         if (aligned > stacknleft) {
8176                 size_t len;
8177                 size_t blocksize;
8178                 struct stack_block *sp;
8179
8180                 blocksize = aligned;
8181                 if (blocksize < MINSIZE)
8182                         blocksize = MINSIZE;
8183                 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8184                 if (len < blocksize)
8185                         error(bb_msg_memory_exhausted);
8186                 INTOFF;
8187                 sp = ckmalloc(len);
8188                 sp->prev = stackp;
8189                 stacknxt = sp->space;
8190                 stacknleft = blocksize;
8191                 sstrend = stacknxt + blocksize;
8192                 stackp = sp;
8193                 INTON;
8194         }
8195         p = stacknxt;
8196         stacknxt += aligned;
8197         stacknleft -= aligned;
8198         return p;
8199 }
8200
8201
8202 void
8203 stunalloc(pointer p)
8204 {
8205 #ifdef DEBUG
8206         if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8207                 write(2, "stunalloc\n", 10);
8208                 abort();
8209         }
8210 #endif
8211         stacknleft += stacknxt - (char *)p;
8212         stacknxt = p;
8213 }
8214
8215
8216 void
8217 setstackmark(struct stackmark *mark)
8218 {
8219         mark->stackp = stackp;
8220         mark->stacknxt = stacknxt;
8221         mark->stacknleft = stacknleft;
8222         mark->marknext = markp;
8223         markp = mark;
8224 }
8225
8226
8227 void
8228 popstackmark(struct stackmark *mark)
8229 {
8230         struct stack_block *sp;
8231
8232         INTOFF;
8233         markp = mark->marknext;
8234         while (stackp != mark->stackp) {
8235                 sp = stackp;
8236                 stackp = sp->prev;
8237                 ckfree(sp);
8238         }
8239         stacknxt = mark->stacknxt;
8240         stacknleft = mark->stacknleft;
8241         sstrend = mark->stacknxt + mark->stacknleft;
8242         INTON;
8243 }
8244
8245
8246 /*
8247  * When the parser reads in a string, it wants to stick the string on the
8248  * stack and only adjust the stack pointer when it knows how big the
8249  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
8250  * of space on top of the stack and stackblocklen returns the length of
8251  * this block.  Growstackblock will grow this space by at least one byte,
8252  * possibly moving it (like realloc).  Grabstackblock actually allocates the
8253  * part of the block that has been used.
8254  */
8255
8256 void
8257 growstackblock(void)
8258 {
8259         size_t newlen;
8260
8261         newlen = stacknleft * 2;
8262         if (newlen < stacknleft)
8263                 error(bb_msg_memory_exhausted);
8264         if (newlen < 128)
8265                 newlen += 128;
8266
8267         if (stacknxt == stackp->space && stackp != &stackbase) {
8268                 struct stack_block *oldstackp;
8269                 struct stackmark *xmark;
8270                 struct stack_block *sp;
8271                 struct stack_block *prevstackp;
8272                 size_t grosslen;
8273
8274                 INTOFF;
8275                 oldstackp = stackp;
8276                 sp = stackp;
8277                 prevstackp = sp->prev;
8278                 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8279                 sp = ckrealloc((pointer)sp, grosslen);
8280                 sp->prev = prevstackp;
8281                 stackp = sp;
8282                 stacknxt = sp->space;
8283                 stacknleft = newlen;
8284                 sstrend = sp->space + newlen;
8285
8286                 /*
8287                  * Stack marks pointing to the start of the old block
8288                  * must be relocated to point to the new block
8289                  */
8290                 xmark = markp;
8291                 while (xmark != NULL && xmark->stackp == oldstackp) {
8292                         xmark->stackp = stackp;
8293                         xmark->stacknxt = stacknxt;
8294                         xmark->stacknleft = stacknleft;
8295                         xmark = xmark->marknext;
8296                 }
8297                 INTON;
8298         } else {
8299                 char *oldspace = stacknxt;
8300                 int oldlen = stacknleft;
8301                 char *p = stalloc(newlen);
8302
8303                 /* free the space we just allocated */
8304                 stacknxt = memcpy(p, oldspace, oldlen);
8305                 stacknleft += newlen;
8306         }
8307 }
8308
8309 static inline void
8310 grabstackblock(size_t len)
8311 {
8312         len = SHELL_ALIGN(len);
8313         stacknxt += len;
8314         stacknleft -= len;
8315 }
8316
8317 /*
8318  * The following routines are somewhat easier to use than the above.
8319  * The user declares a variable of type STACKSTR, which may be declared
8320  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
8321  * the user uses the macro STPUTC to add characters to the string.  In
8322  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8323  * grown as necessary.  When the user is done, she can just leave the
8324  * string there and refer to it using stackblock().  Or she can allocate
8325  * the space for it using grabstackstr().  If it is necessary to allow
8326  * someone else to use the stack temporarily and then continue to grow
8327  * the string, the user should use grabstack to allocate the space, and
8328  * then call ungrabstr(p) to return to the previous mode of operation.
8329  *
8330  * USTPUTC is like STPUTC except that it doesn't check for overflow.
8331  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8332  * is space for at least one character.
8333  */
8334
8335 void *
8336 growstackstr(void)
8337 {
8338         size_t len = stackblocksize();
8339         if (herefd >= 0 && len >= 1024) {
8340                 xwrite(herefd, stackblock(), len);
8341                 return stackblock();
8342         }
8343         growstackblock();
8344         return stackblock() + len;
8345 }
8346
8347 /*
8348  * Called from CHECKSTRSPACE.
8349  */
8350
8351 char *
8352 makestrspace(size_t newlen, char *p)
8353 {
8354         size_t len = p - stacknxt;
8355         size_t size = stackblocksize();
8356
8357         for (;;) {
8358                 size_t nleft;
8359
8360                 size = stackblocksize();
8361                 nleft = size - len;
8362                 if (nleft >= newlen)
8363                         break;
8364                 growstackblock();
8365         }
8366         return stackblock() + len;
8367 }
8368
8369 char *
8370 stnputs(const char *s, size_t n, char *p)
8371 {
8372         p = makestrspace(n, p);
8373         p = mempcpy(p, s, n);
8374         return p;
8375 }
8376
8377 char *
8378 stputs(const char *s, char *p)
8379 {
8380         return stnputs(s, strlen(s), p);
8381 }
8382
8383 /*      $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $   */
8384
8385 /*
8386  * String functions.
8387  *
8388  *      number(s)               Convert a string of digits to an integer.
8389  *      is_number(s)            Return true if s is a string of digits.
8390  */
8391
8392 /*
8393  * prefix -- see if pfx is a prefix of string.
8394  */
8395
8396 char *
8397 prefix(const char *string, const char *pfx)
8398 {
8399         while (*pfx) {
8400                 if (*pfx++ != *string++)
8401                         return 0;
8402         }
8403         return (char *) string;
8404 }
8405
8406
8407 /*
8408  * Convert a string of digits to an integer, printing an error message on
8409  * failure.
8410  */
8411
8412 int
8413 number(const char *s)
8414 {
8415
8416         if (! is_number(s))
8417                 error(illnum, s);
8418         return atoi(s);
8419 }
8420
8421
8422 /*
8423  * Check for a valid number.  This should be elsewhere.
8424  */
8425
8426 int
8427 is_number(const char *p)
8428 {
8429         do {
8430                 if (! is_digit(*p))
8431                         return 0;
8432         } while (*++p != '\0');
8433         return 1;
8434 }
8435
8436
8437 /*
8438  * Produce a possibly single quoted string suitable as input to the shell.
8439  * The return string is allocated on the stack.
8440  */
8441
8442 char *
8443 single_quote(const char *s) {
8444         char *p;
8445
8446         STARTSTACKSTR(p);
8447
8448         do {
8449                 char *q;
8450                 size_t len;
8451
8452                 len = strchrnul(s, '\'') - s;
8453
8454                 q = p = makestrspace(len + 3, p);
8455
8456                 *q++ = '\'';
8457                 q = mempcpy(q, s, len);
8458                 *q++ = '\'';
8459                 s += len;
8460
8461                 STADJUST(q - p, p);
8462
8463                 len = strspn(s, "'");
8464                 if (!len)
8465                         break;
8466
8467                 q = p = makestrspace(len + 3, p);
8468
8469                 *q++ = '"';
8470                 q = mempcpy(q, s, len);
8471                 *q++ = '"';
8472                 s += len;
8473
8474                 STADJUST(q - p, p);
8475         } while (*s);
8476
8477         USTPUTC(0, p);
8478
8479         return stackblock();
8480 }
8481
8482 /*
8483  * Like strdup but works with the ash stack.
8484  */
8485
8486 char *
8487 sstrdup(const char *p)
8488 {
8489         size_t len = strlen(p) + 1;
8490         return memcpy(stalloc(len), p, len);
8491 }
8492
8493
8494 static void
8495 calcsize(union node *n)
8496 {
8497       if (n == NULL)
8498             return;
8499       funcblocksize += nodesize[n->type];
8500       switch (n->type) {
8501       case NCMD:
8502             calcsize(n->ncmd.redirect);
8503             calcsize(n->ncmd.args);
8504             calcsize(n->ncmd.assign);
8505             break;
8506       case NPIPE:
8507             sizenodelist(n->npipe.cmdlist);
8508             break;
8509       case NREDIR:
8510       case NBACKGND:
8511       case NSUBSHELL:
8512             calcsize(n->nredir.redirect);
8513             calcsize(n->nredir.n);
8514             break;
8515       case NAND:
8516       case NOR:
8517       case NSEMI:
8518       case NWHILE:
8519       case NUNTIL:
8520             calcsize(n->nbinary.ch2);
8521             calcsize(n->nbinary.ch1);
8522             break;
8523       case NIF:
8524             calcsize(n->nif.elsepart);
8525             calcsize(n->nif.ifpart);
8526             calcsize(n->nif.test);
8527             break;
8528       case NFOR:
8529             funcstringsize += strlen(n->nfor.var) + 1;
8530             calcsize(n->nfor.body);
8531             calcsize(n->nfor.args);
8532             break;
8533       case NCASE:
8534             calcsize(n->ncase.cases);
8535             calcsize(n->ncase.expr);
8536             break;
8537       case NCLIST:
8538             calcsize(n->nclist.body);
8539             calcsize(n->nclist.pattern);
8540             calcsize(n->nclist.next);
8541             break;
8542       case NDEFUN:
8543       case NARG:
8544             sizenodelist(n->narg.backquote);
8545             funcstringsize += strlen(n->narg.text) + 1;
8546             calcsize(n->narg.next);
8547             break;
8548       case NTO:
8549       case NCLOBBER:
8550       case NFROM:
8551       case NFROMTO:
8552       case NAPPEND:
8553             calcsize(n->nfile.fname);
8554             calcsize(n->nfile.next);
8555             break;
8556       case NTOFD:
8557       case NFROMFD:
8558             calcsize(n->ndup.vname);
8559             calcsize(n->ndup.next);
8560             break;
8561       case NHERE:
8562       case NXHERE:
8563             calcsize(n->nhere.doc);
8564             calcsize(n->nhere.next);
8565             break;
8566       case NNOT:
8567             calcsize(n->nnot.com);
8568             break;
8569       };
8570 }
8571
8572
8573 static void
8574 sizenodelist(struct nodelist *lp)
8575 {
8576         while (lp) {
8577                 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8578                 calcsize(lp->n);
8579                 lp = lp->next;
8580         }
8581 }
8582
8583
8584 static union node *
8585 copynode(union node *n)
8586 {
8587       union node *new;
8588
8589       if (n == NULL)
8590             return NULL;
8591       new = funcblock;
8592       funcblock = (char *) funcblock + nodesize[n->type];
8593       switch (n->type) {
8594       case NCMD:
8595             new->ncmd.redirect = copynode(n->ncmd.redirect);
8596             new->ncmd.args = copynode(n->ncmd.args);
8597             new->ncmd.assign = copynode(n->ncmd.assign);
8598             break;
8599       case NPIPE:
8600             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8601             new->npipe.backgnd = n->npipe.backgnd;
8602             break;
8603       case NREDIR:
8604       case NBACKGND:
8605       case NSUBSHELL:
8606             new->nredir.redirect = copynode(n->nredir.redirect);
8607             new->nredir.n = copynode(n->nredir.n);
8608             break;
8609       case NAND:
8610       case NOR:
8611       case NSEMI:
8612       case NWHILE:
8613       case NUNTIL:
8614             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8615             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8616             break;
8617       case NIF:
8618             new->nif.elsepart = copynode(n->nif.elsepart);
8619             new->nif.ifpart = copynode(n->nif.ifpart);
8620             new->nif.test = copynode(n->nif.test);
8621             break;
8622       case NFOR:
8623             new->nfor.var = nodesavestr(n->nfor.var);
8624             new->nfor.body = copynode(n->nfor.body);
8625             new->nfor.args = copynode(n->nfor.args);
8626             break;
8627       case NCASE:
8628             new->ncase.cases = copynode(n->ncase.cases);
8629             new->ncase.expr = copynode(n->ncase.expr);
8630             break;
8631       case NCLIST:
8632             new->nclist.body = copynode(n->nclist.body);
8633             new->nclist.pattern = copynode(n->nclist.pattern);
8634             new->nclist.next = copynode(n->nclist.next);
8635             break;
8636       case NDEFUN:
8637       case NARG:
8638             new->narg.backquote = copynodelist(n->narg.backquote);
8639             new->narg.text = nodesavestr(n->narg.text);
8640             new->narg.next = copynode(n->narg.next);
8641             break;
8642       case NTO:
8643       case NCLOBBER:
8644       case NFROM:
8645       case NFROMTO:
8646       case NAPPEND:
8647             new->nfile.fname = copynode(n->nfile.fname);
8648             new->nfile.fd = n->nfile.fd;
8649             new->nfile.next = copynode(n->nfile.next);
8650             break;
8651       case NTOFD:
8652       case NFROMFD:
8653             new->ndup.vname = copynode(n->ndup.vname);
8654             new->ndup.dupfd = n->ndup.dupfd;
8655             new->ndup.fd = n->ndup.fd;
8656             new->ndup.next = copynode(n->ndup.next);
8657             break;
8658       case NHERE:
8659       case NXHERE:
8660             new->nhere.doc = copynode(n->nhere.doc);
8661             new->nhere.fd = n->nhere.fd;
8662             new->nhere.next = copynode(n->nhere.next);
8663             break;
8664       case NNOT:
8665             new->nnot.com = copynode(n->nnot.com);
8666             break;
8667       };
8668       new->type = n->type;
8669         return new;
8670 }
8671
8672
8673 static struct nodelist *
8674 copynodelist(struct nodelist *lp)
8675 {
8676         struct nodelist *start;
8677         struct nodelist **lpp;
8678
8679         lpp = &start;
8680         while (lp) {
8681                 *lpp = funcblock;
8682                 funcblock = (char *) funcblock +
8683                     SHELL_ALIGN(sizeof(struct nodelist));
8684                 (*lpp)->n = copynode(lp->n);
8685                 lp = lp->next;
8686                 lpp = &(*lpp)->next;
8687         }
8688         *lpp = NULL;
8689         return start;
8690 }
8691
8692
8693 static char *
8694 nodesavestr(char   *s)
8695 {
8696         char   *rtn = funcstring;
8697
8698         funcstring = stpcpy(funcstring, s) + 1;
8699         return rtn;
8700 }
8701
8702
8703 /*
8704  * Free a parse tree.
8705  */
8706
8707 static void
8708 freefunc(struct funcnode *f)
8709 {
8710         if (f && --f->count < 0)
8711                 ckfree(f);
8712 }
8713
8714
8715 static void options(int);
8716 static void setoption(int, int);
8717
8718
8719 /*
8720  * Process the shell command line arguments.
8721  */
8722
8723 void
8724 procargs(int argc, char **argv)
8725 {
8726         int i;
8727         const char *xminusc;
8728         char **xargv;
8729
8730         xargv = argv;
8731         arg0 = xargv[0];
8732         if (argc > 0)
8733                 xargv++;
8734         for (i = 0; i < NOPTS; i++)
8735                 optlist[i] = 2;
8736         argptr = xargv;
8737         options(1);
8738         xargv = argptr;
8739         xminusc = minusc;
8740         if (*xargv == NULL) {
8741                 if (xminusc)
8742                         error("-c requires an argument");
8743                 sflag = 1;
8744         }
8745         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8746                 iflag = 1;
8747         if (mflag == 2)
8748                 mflag = iflag;
8749         for (i = 0; i < NOPTS; i++)
8750                 if (optlist[i] == 2)
8751                         optlist[i] = 0;
8752 #if DEBUG == 2
8753         debug = 1;
8754 #endif
8755         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8756         if (xminusc) {
8757                 minusc = *xargv++;
8758                 if (*xargv)
8759                         goto setarg0;
8760         } else if (!sflag) {
8761                 setinputfile(*xargv, 0);
8762 setarg0:
8763                 arg0 = *xargv++;
8764                 commandname = arg0;
8765         }
8766
8767         shellparam.p = xargv;
8768 #ifdef CONFIG_ASH_GETOPTS
8769         shellparam.optind = 1;
8770         shellparam.optoff = -1;
8771 #endif
8772         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8773         while (*xargv) {
8774                 shellparam.nparam++;
8775                 xargv++;
8776         }
8777         optschanged();
8778 }
8779
8780
8781 void
8782 optschanged(void)
8783 {
8784 #ifdef DEBUG
8785         opentrace();
8786 #endif
8787         setinteractive(iflag);
8788         setjobctl(mflag);
8789 }
8790
8791 static inline void
8792 minus_o(char *name, int val)
8793 {
8794         int i;
8795
8796         if (name == NULL) {
8797                 out1str("Current option settings\n");
8798                 for (i = 0; i < NOPTS; i++)
8799                         out1fmt("%-16s%s\n", optnames(i),
8800                                 optlist[i] ? "on" : "off");
8801         } else {
8802                 for (i = 0; i < NOPTS; i++)
8803                         if (equal(name, optnames(i))) {
8804                                 optlist[i] = val;
8805                                 return;
8806                         }
8807                 error("Illegal option -o %s", name);
8808         }
8809 }
8810
8811 /*
8812  * Process shell options.  The global variable argptr contains a pointer
8813  * to the argument list; we advance it past the options.
8814  */
8815
8816 static void
8817 options(int cmdline)
8818 {
8819         char *p;
8820         int val;
8821         int c;
8822
8823         if (cmdline)
8824                 minusc = NULL;
8825         while ((p = *argptr) != NULL) {
8826                 argptr++;
8827                 if ((c = *p++) == '-') {
8828                         val = 1;
8829                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8830                                 if (!cmdline) {
8831                                         /* "-" means turn off -x and -v */
8832                                         if (p[0] == '\0')
8833                                                 xflag = vflag = 0;
8834                                         /* "--" means reset params */
8835                                         else if (*argptr == NULL)
8836                                                 setparam(argptr);
8837                                 }
8838                                 break;    /* "-" or  "--" terminates options */
8839                         }
8840                 } else if (c == '+') {
8841                         val = 0;
8842                 } else {
8843                         argptr--;
8844                         break;
8845                 }
8846                 while ((c = *p++) != '\0') {
8847                         if (c == 'c' && cmdline) {
8848                                 minusc = p;     /* command is after shell args*/
8849                         } else if (c == 'o') {
8850                                 minus_o(*argptr, val);
8851                                 if (*argptr)
8852                                         argptr++;
8853                         } else if (cmdline && (c == '-')) {     // long options
8854                                 if (strcmp(p, "login") == 0)
8855                                         isloginsh = 1;
8856                                 break;
8857                         } else {
8858                                 setoption(c, val);
8859                         }
8860                 }
8861         }
8862 }
8863
8864
8865 static void
8866 setoption(int flag, int val)
8867 {
8868         int i;
8869
8870         for (i = 0; i < NOPTS; i++)
8871                 if (optletters(i) == flag) {
8872                         optlist[i] = val;
8873                         return;
8874                 }
8875         error("Illegal option -%c", flag);
8876         /* NOTREACHED */
8877 }
8878
8879
8880
8881 /*
8882  * Set the shell parameters.
8883  */
8884
8885 void
8886 setparam(char **argv)
8887 {
8888         char **newparam;
8889         char **ap;
8890         int nparam;
8891
8892         for (nparam = 0 ; argv[nparam] ; nparam++);
8893         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8894         while (*argv) {
8895                 *ap++ = savestr(*argv++);
8896         }
8897         *ap = NULL;
8898         freeparam(&shellparam);
8899         shellparam.malloc = 1;
8900         shellparam.nparam = nparam;
8901         shellparam.p = newparam;
8902 #ifdef CONFIG_ASH_GETOPTS
8903         shellparam.optind = 1;
8904         shellparam.optoff = -1;
8905 #endif
8906 }
8907
8908
8909 /*
8910  * Free the list of positional parameters.
8911  */
8912
8913 void
8914 freeparam(volatile struct shparam *param)
8915 {
8916         char **ap;
8917
8918         if (param->malloc) {
8919                 for (ap = param->p ; *ap ; ap++)
8920                         ckfree(*ap);
8921                 ckfree(param->p);
8922         }
8923 }
8924
8925
8926
8927 /*
8928  * The shift builtin command.
8929  */
8930
8931 int
8932 shiftcmd(int argc, char **argv)
8933 {
8934         int n;
8935         char **ap1, **ap2;
8936
8937         n = 1;
8938         if (argc > 1)
8939                 n = number(argv[1]);
8940         if (n > shellparam.nparam)
8941                 error("can't shift that many");
8942         INTOFF;
8943         shellparam.nparam -= n;
8944         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8945                 if (shellparam.malloc)
8946                         ckfree(*ap1);
8947         }
8948         ap2 = shellparam.p;
8949         while ((*ap2++ = *ap1++) != NULL);
8950 #ifdef CONFIG_ASH_GETOPTS
8951         shellparam.optind = 1;
8952         shellparam.optoff = -1;
8953 #endif
8954         INTON;
8955         return 0;
8956 }
8957
8958
8959
8960 /*
8961  * The set command builtin.
8962  */
8963
8964 int
8965 setcmd(int argc, char **argv)
8966 {
8967         if (argc == 1)
8968                 return showvars(nullstr, 0, VUNSET);
8969         INTOFF;
8970         options(0);
8971         optschanged();
8972         if (*argptr != NULL) {
8973                 setparam(argptr);
8974         }
8975         INTON;
8976         return 0;
8977 }
8978
8979
8980 #ifdef CONFIG_ASH_GETOPTS
8981 static void
8982 getoptsreset(value)
8983         const char *value;
8984 {
8985         shellparam.optind = number(value);
8986         shellparam.optoff = -1;
8987 }
8988 #endif
8989
8990 #ifdef CONFIG_LOCALE_SUPPORT
8991 static void change_lc_all(const char *value)
8992 {
8993         if (value != 0 && *value != 0)
8994                 setlocale(LC_ALL, value);
8995 }
8996
8997 static void change_lc_ctype(const char *value)
8998 {
8999         if (value != 0 && *value != 0)
9000                 setlocale(LC_CTYPE, value);
9001 }
9002
9003 #endif
9004
9005 #ifdef CONFIG_ASH_GETOPTS
9006 static int
9007 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9008 {
9009         char *p, *q;
9010         char c = '?';
9011         int done = 0;
9012         int err = 0;
9013         char s[12];
9014         char **optnext;
9015
9016         if(*param_optind < 1)
9017                 return 1;
9018         optnext = optfirst + *param_optind - 1;
9019
9020         if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9021                 p = NULL;
9022         else
9023                 p = optnext[-1] + *optoff;
9024         if (p == NULL || *p == '\0') {
9025                 /* Current word is done, advance */
9026                 p = *optnext;
9027                 if (p == NULL || *p != '-' || *++p == '\0') {
9028 atend:
9029                         p = NULL;
9030                         done = 1;
9031                         goto out;
9032                 }
9033                 optnext++;
9034                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9035                         goto atend;
9036         }
9037
9038         c = *p++;
9039         for (q = optstr; *q != c; ) {
9040                 if (*q == '\0') {
9041                         if (optstr[0] == ':') {
9042                                 s[0] = c;
9043                                 s[1] = '\0';
9044                                 err |= setvarsafe("OPTARG", s, 0);
9045                         } else {
9046                                 fprintf(stderr, "Illegal option -%c\n", c);
9047                                 (void) unsetvar("OPTARG");
9048                         }
9049                         c = '?';
9050                         goto out;
9051                 }
9052                 if (*++q == ':')
9053                         q++;
9054         }
9055
9056         if (*++q == ':') {
9057                 if (*p == '\0' && (p = *optnext) == NULL) {
9058                         if (optstr[0] == ':') {
9059                                 s[0] = c;
9060                                 s[1] = '\0';
9061                                 err |= setvarsafe("OPTARG", s, 0);
9062                                 c = ':';
9063                         } else {
9064                                 fprintf(stderr, "No arg for -%c option\n", c);
9065                                 (void) unsetvar("OPTARG");
9066                                 c = '?';
9067                         }
9068                         goto out;
9069                 }
9070
9071                 if (p == *optnext)
9072                         optnext++;
9073                 err |= setvarsafe("OPTARG", p, 0);
9074                 p = NULL;
9075         } else
9076                 err |= setvarsafe("OPTARG", nullstr, 0);
9077
9078 out:
9079         *optoff = p ? p - *(optnext - 1) : -1;
9080         *param_optind = optnext - optfirst + 1;
9081         fmtstr(s, sizeof(s), "%d", *param_optind);
9082         err |= setvarsafe("OPTIND", s, VNOFUNC);
9083         s[0] = c;
9084         s[1] = '\0';
9085         err |= setvarsafe(optvar, s, 0);
9086         if (err) {
9087                 *param_optind = 1;
9088                 *optoff = -1;
9089                 flushall();
9090                 exraise(EXERROR);
9091         }
9092         return done;
9093 }
9094
9095 /*
9096  * The getopts builtin.  Shellparam.optnext points to the next argument
9097  * to be processed.  Shellparam.optptr points to the next character to
9098  * be processed in the current argument.  If shellparam.optnext is NULL,
9099  * then it's the first time getopts has been called.
9100  */
9101
9102 int
9103 getoptscmd(int argc, char **argv)
9104 {
9105         char **optbase;
9106
9107         if (argc < 3)
9108                 error("Usage: getopts optstring var [arg]");
9109         else if (argc == 3) {
9110                 optbase = shellparam.p;
9111                 if (shellparam.optind > shellparam.nparam + 1) {
9112                         shellparam.optind = 1;
9113                         shellparam.optoff = -1;
9114                 }
9115         }
9116         else {
9117                 optbase = &argv[3];
9118                 if (shellparam.optind > argc - 2) {
9119                         shellparam.optind = 1;
9120                         shellparam.optoff = -1;
9121                 }
9122         }
9123
9124         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9125                        &shellparam.optoff);
9126 }
9127 #endif /* CONFIG_ASH_GETOPTS */
9128
9129 /*
9130  * XXX - should get rid of.  have all builtins use getopt(3).  the
9131  * library getopt must have the BSD extension static variable "optreset"
9132  * otherwise it can't be used within the shell safely.
9133  *
9134  * Standard option processing (a la getopt) for builtin routines.  The
9135  * only argument that is passed to nextopt is the option string; the
9136  * other arguments are unnecessary.  It return the character, or '\0' on
9137  * end of input.
9138  */
9139
9140 static int
9141 nextopt(const char *optstring)
9142 {
9143         char *p;
9144         const char *q;
9145         char c;
9146
9147         if ((p = optptr) == NULL || *p == '\0') {
9148                 p = *argptr;
9149                 if (p == NULL || *p != '-' || *++p == '\0')
9150                         return '\0';
9151                 argptr++;
9152                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9153                         return '\0';
9154         }
9155         c = *p++;
9156         for (q = optstring ; *q != c ; ) {
9157                 if (*q == '\0')
9158                         error("Illegal option -%c", c);
9159                 if (*++q == ':')
9160                         q++;
9161         }
9162         if (*++q == ':') {
9163                 if (*p == '\0' && (p = *argptr++) == NULL)
9164                         error("No arg for -%c option", c);
9165                 optionarg = p;
9166                 p = NULL;
9167         }
9168         optptr = p;
9169         return c;
9170 }
9171
9172
9173 /*      $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $     */
9174
9175 void
9176 outstr(const char *p, FILE *file)
9177 {
9178         INTOFF;
9179         fputs(p, file);
9180         INTON;
9181 }
9182
9183 void
9184 flushall(void)
9185 {
9186         INTOFF;
9187         fflush(stdout);
9188         fflush(stderr);
9189         INTON;
9190 }
9191
9192 void
9193 flushout(FILE *dest)
9194 {
9195         INTOFF;
9196         fflush(dest);
9197         INTON;
9198 }
9199
9200 static void
9201 outcslow(int c, FILE *dest)
9202 {
9203         INTOFF;
9204         putc(c, dest);
9205         fflush(dest);
9206         INTON;
9207 }
9208
9209
9210 static int
9211 out1fmt(const char *fmt, ...)
9212 {
9213         va_list ap;
9214         int r;
9215
9216         INTOFF;
9217         va_start(ap, fmt);
9218         r = vprintf(fmt, ap);
9219         va_end(ap);
9220         INTON;
9221         return r;
9222 }
9223
9224
9225 int
9226 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9227 {
9228         va_list ap;
9229         int ret;
9230
9231         va_start(ap, fmt);
9232         INTOFF;
9233         ret = vsnprintf(outbuf, length, fmt, ap);
9234         va_end(ap);
9235         INTON;
9236         return ret;
9237 }
9238
9239
9240 /*
9241  * Version of write which resumes after a signal is caught.
9242  */
9243
9244 static void
9245 xwrite(int fd, const void *p, size_t n)
9246 {
9247         ssize_t i;
9248
9249         do {
9250                 i = bb_full_write(fd, p, n);
9251         } while (i < 0 && errno == EINTR);
9252 }
9253
9254
9255 /*      $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $     */
9256
9257
9258 /*
9259  * Shell command parser.
9260  */
9261
9262 #define EOFMARKLEN 79
9263
9264
9265 struct heredoc {
9266         struct heredoc *next;   /* next here document in list */
9267         union node *here;               /* redirection node */
9268         char *eofmark;          /* string indicating end of input */
9269         int striptabs;          /* if set, strip leading tabs */
9270 };
9271
9272
9273
9274 static struct heredoc *heredoclist;    /* list of here documents to read */
9275
9276
9277 static union node *list(int);
9278 static union node *andor(void);
9279 static union node *pipeline(void);
9280 static union node *command(void);
9281 static union node *simplecmd(void);
9282 static union node *makename(void);
9283 static void parsefname(void);
9284 static void parseheredoc(void);
9285 static char peektoken(void);
9286 static int readtoken(void);
9287 static int xxreadtoken(void);
9288 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9289 static int noexpand(char *);
9290 static void synexpect(int) __attribute__((__noreturn__));
9291 static void synerror(const char *) __attribute__((__noreturn__));
9292 static void setprompt(int);
9293
9294
9295 static inline int
9296 goodname(const char *p)
9297 {
9298         return !*endofname(p);
9299 }
9300
9301 static inline int
9302 isassignment(const char *p)
9303 {
9304         const char *q = endofname(p);
9305         if (p == q)
9306                 return 0;
9307         return *q == '=';
9308 }
9309
9310
9311 /*
9312  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9313  * valid parse tree indicating a blank line.)
9314  */
9315
9316 union node *
9317 parsecmd(int interact)
9318 {
9319         int t;
9320
9321         tokpushback = 0;
9322         doprompt = interact;
9323         if (doprompt)
9324                 setprompt(doprompt);
9325         needprompt = 0;
9326         t = readtoken();
9327         if (t == TEOF)
9328                 return NEOF;
9329         if (t == TNL)
9330                 return NULL;
9331         tokpushback++;
9332         return list(1);
9333 }
9334
9335
9336 static union node *
9337 list(int nlflag)
9338 {
9339         union node *n1, *n2, *n3;
9340         int tok;
9341
9342         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9343         if (nlflag == 2 && peektoken())
9344                 return NULL;
9345         n1 = NULL;
9346         for (;;) {
9347                 n2 = andor();
9348                 tok = readtoken();
9349                 if (tok == TBACKGND) {
9350                         if (n2->type == NPIPE) {
9351                                 n2->npipe.backgnd = 1;
9352                         } else {
9353                                 if (n2->type != NREDIR) {
9354                                         n3 = stalloc(sizeof(struct nredir));
9355                                         n3->nredir.n = n2;
9356                                         n3->nredir.redirect = NULL;
9357                                         n2 = n3;
9358                                 }
9359                                 n2->type = NBACKGND;
9360                         }
9361                 }
9362                 if (n1 == NULL) {
9363                         n1 = n2;
9364                 }
9365                 else {
9366                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9367                         n3->type = NSEMI;
9368                         n3->nbinary.ch1 = n1;
9369                         n3->nbinary.ch2 = n2;
9370                         n1 = n3;
9371                 }
9372                 switch (tok) {
9373                 case TBACKGND:
9374                 case TSEMI:
9375                         tok = readtoken();
9376                         /* fall through */
9377                 case TNL:
9378                         if (tok == TNL) {
9379                                 parseheredoc();
9380                                 if (nlflag == 1)
9381                                         return n1;
9382                         } else {
9383                                 tokpushback++;
9384                         }
9385                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9386                         if (peektoken())
9387                                 return n1;
9388                         break;
9389                 case TEOF:
9390                         if (heredoclist)
9391                                 parseheredoc();
9392                         else
9393                                 pungetc();              /* push back EOF on input */
9394                         return n1;
9395                 default:
9396                         if (nlflag == 1)
9397                                 synexpect(-1);
9398                         tokpushback++;
9399                         return n1;
9400                 }
9401         }
9402 }
9403
9404
9405
9406 static union node *
9407 andor(void)
9408 {
9409         union node *n1, *n2, *n3;
9410         int t;
9411
9412         n1 = pipeline();
9413         for (;;) {
9414                 if ((t = readtoken()) == TAND) {
9415                         t = NAND;
9416                 } else if (t == TOR) {
9417                         t = NOR;
9418                 } else {
9419                         tokpushback++;
9420                         return n1;
9421                 }
9422                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9423                 n2 = pipeline();
9424                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9425                 n3->type = t;
9426                 n3->nbinary.ch1 = n1;
9427                 n3->nbinary.ch2 = n2;
9428                 n1 = n3;
9429         }
9430 }
9431
9432
9433
9434 static union node *
9435 pipeline(void)
9436 {
9437         union node *n1, *n2, *pipenode;
9438         struct nodelist *lp, *prev;
9439         int negate;
9440
9441         negate = 0;
9442         TRACE(("pipeline: entered\n"));
9443         if (readtoken() == TNOT) {
9444                 negate = !negate;
9445                 checkkwd = CHKKWD | CHKALIAS;
9446         } else
9447                 tokpushback++;
9448         n1 = command();
9449         if (readtoken() == TPIPE) {
9450                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9451                 pipenode->type = NPIPE;
9452                 pipenode->npipe.backgnd = 0;
9453                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9454                 pipenode->npipe.cmdlist = lp;
9455                 lp->n = n1;
9456                 do {
9457                         prev = lp;
9458                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9459                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9460                         lp->n = command();
9461                         prev->next = lp;
9462                 } while (readtoken() == TPIPE);
9463                 lp->next = NULL;
9464                 n1 = pipenode;
9465         }
9466         tokpushback++;
9467         if (negate) {
9468                 n2 = (union node *)stalloc(sizeof (struct nnot));
9469                 n2->type = NNOT;
9470                 n2->nnot.com = n1;
9471                 return n2;
9472         } else
9473                 return n1;
9474 }
9475
9476
9477
9478 static union node *
9479 command(void)
9480 {
9481         union node *n1, *n2;
9482         union node *ap, **app;
9483         union node *cp, **cpp;
9484         union node *redir, **rpp;
9485         union node **rpp2;
9486         int t;
9487
9488         redir = NULL;
9489         rpp2 = &redir;
9490
9491         switch (readtoken()) {
9492         default:
9493                 synexpect(-1);
9494                 /* NOTREACHED */
9495         case TIF:
9496                 n1 = (union node *)stalloc(sizeof (struct nif));
9497                 n1->type = NIF;
9498                 n1->nif.test = list(0);
9499                 if (readtoken() != TTHEN)
9500                         synexpect(TTHEN);
9501                 n1->nif.ifpart = list(0);
9502                 n2 = n1;
9503                 while (readtoken() == TELIF) {
9504                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9505                         n2 = n2->nif.elsepart;
9506                         n2->type = NIF;
9507                         n2->nif.test = list(0);
9508                         if (readtoken() != TTHEN)
9509                                 synexpect(TTHEN);
9510                         n2->nif.ifpart = list(0);
9511                 }
9512                 if (lasttoken == TELSE)
9513                         n2->nif.elsepart = list(0);
9514                 else {
9515                         n2->nif.elsepart = NULL;
9516                         tokpushback++;
9517                 }
9518                 t = TFI;
9519                 break;
9520         case TWHILE:
9521         case TUNTIL: {
9522                 int got;
9523                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9524                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9525                 n1->nbinary.ch1 = list(0);
9526                 if ((got=readtoken()) != TDO) {
9527 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9528                         synexpect(TDO);
9529                 }
9530                 n1->nbinary.ch2 = list(0);
9531                 t = TDONE;
9532                 break;
9533         }
9534         case TFOR:
9535                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9536                         synerror("Bad for loop variable");
9537                 n1 = (union node *)stalloc(sizeof (struct nfor));
9538                 n1->type = NFOR;
9539                 n1->nfor.var = wordtext;
9540                 checkkwd = CHKKWD | CHKALIAS;
9541                 if (readtoken() == TIN) {
9542                         app = &ap;
9543                         while (readtoken() == TWORD) {
9544                                 n2 = (union node *)stalloc(sizeof (struct narg));
9545                                 n2->type = NARG;
9546                                 n2->narg.text = wordtext;
9547                                 n2->narg.backquote = backquotelist;
9548                                 *app = n2;
9549                                 app = &n2->narg.next;
9550                         }
9551                         *app = NULL;
9552                         n1->nfor.args = ap;
9553                         if (lasttoken != TNL && lasttoken != TSEMI)
9554                                 synexpect(-1);
9555                 } else {
9556                         n2 = (union node *)stalloc(sizeof (struct narg));
9557                         n2->type = NARG;
9558                         n2->narg.text = (char *)dolatstr;
9559                         n2->narg.backquote = NULL;
9560                         n2->narg.next = NULL;
9561                         n1->nfor.args = n2;
9562                         /*
9563                          * Newline or semicolon here is optional (but note
9564                          * that the original Bourne shell only allowed NL).
9565                          */
9566                         if (lasttoken != TNL && lasttoken != TSEMI)
9567                                 tokpushback++;
9568                 }
9569                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9570                 if (readtoken() != TDO)
9571                         synexpect(TDO);
9572                 n1->nfor.body = list(0);
9573                 t = TDONE;
9574                 break;
9575         case TCASE:
9576                 n1 = (union node *)stalloc(sizeof (struct ncase));
9577                 n1->type = NCASE;
9578                 if (readtoken() != TWORD)
9579                         synexpect(TWORD);
9580                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9581                 n2->type = NARG;
9582                 n2->narg.text = wordtext;
9583                 n2->narg.backquote = backquotelist;
9584                 n2->narg.next = NULL;
9585                 do {
9586                         checkkwd = CHKKWD | CHKALIAS;
9587                 } while (readtoken() == TNL);
9588                 if (lasttoken != TIN)
9589                         synexpect(TIN);
9590                 cpp = &n1->ncase.cases;
9591 next_case:
9592                 checkkwd = CHKNL | CHKKWD;
9593                 t = readtoken();
9594                 while(t != TESAC) {
9595                         if (lasttoken == TLP)
9596                                 readtoken();
9597                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9598                         cp->type = NCLIST;
9599                         app = &cp->nclist.pattern;
9600                         for (;;) {
9601                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9602                                 ap->type = NARG;
9603                                 ap->narg.text = wordtext;
9604                                 ap->narg.backquote = backquotelist;
9605                                 if (readtoken() != TPIPE)
9606                                         break;
9607                                 app = &ap->narg.next;
9608                                 readtoken();
9609                         }
9610                         ap->narg.next = NULL;
9611                         if (lasttoken != TRP)
9612                                 synexpect(TRP);
9613                         cp->nclist.body = list(2);
9614
9615                         cpp = &cp->nclist.next;
9616
9617                         checkkwd = CHKNL | CHKKWD;
9618                         if ((t = readtoken()) != TESAC) {
9619                                 if (t != TENDCASE)
9620                                         synexpect(TENDCASE);
9621                                 else
9622                                         goto next_case;
9623                         }
9624                 }
9625                 *cpp = NULL;
9626                 goto redir;
9627         case TLP:
9628                 n1 = (union node *)stalloc(sizeof (struct nredir));
9629                 n1->type = NSUBSHELL;
9630                 n1->nredir.n = list(0);
9631                 n1->nredir.redirect = NULL;
9632                 t = TRP;
9633                 break;
9634         case TBEGIN:
9635                 n1 = list(0);
9636                 t = TEND;
9637                 break;
9638         case TWORD:
9639         case TREDIR:
9640                 tokpushback++;
9641                 return simplecmd();
9642         }
9643
9644         if (readtoken() != t)
9645                 synexpect(t);
9646
9647 redir:
9648         /* Now check for redirection which may follow command */
9649         checkkwd = CHKKWD | CHKALIAS;
9650         rpp = rpp2;
9651         while (readtoken() == TREDIR) {
9652                 *rpp = n2 = redirnode;
9653                 rpp = &n2->nfile.next;
9654                 parsefname();
9655         }
9656         tokpushback++;
9657         *rpp = NULL;
9658         if (redir) {
9659                 if (n1->type != NSUBSHELL) {
9660                         n2 = (union node *)stalloc(sizeof (struct nredir));
9661                         n2->type = NREDIR;
9662                         n2->nredir.n = n1;
9663                         n1 = n2;
9664                 }
9665                 n1->nredir.redirect = redir;
9666         }
9667
9668         return n1;
9669 }
9670
9671
9672 static union node *
9673 simplecmd(void) {
9674         union node *args, **app;
9675         union node *n = NULL;
9676         union node *vars, **vpp;
9677         union node **rpp, *redir;
9678         int savecheckkwd;
9679
9680         args = NULL;
9681         app = &args;
9682         vars = NULL;
9683         vpp = &vars;
9684         redir = NULL;
9685         rpp = &redir;
9686
9687         savecheckkwd = CHKALIAS;
9688         for (;;) {
9689                 checkkwd = savecheckkwd;
9690                 switch (readtoken()) {
9691                 case TWORD:
9692                         n = (union node *)stalloc(sizeof (struct narg));
9693                         n->type = NARG;
9694                         n->narg.text = wordtext;
9695                         n->narg.backquote = backquotelist;
9696                         if (savecheckkwd && isassignment(wordtext)) {
9697                                 *vpp = n;
9698                                 vpp = &n->narg.next;
9699                         } else {
9700                                 *app = n;
9701                                 app = &n->narg.next;
9702                                 savecheckkwd = 0;
9703                         }
9704                         break;
9705                 case TREDIR:
9706                         *rpp = n = redirnode;
9707                         rpp = &n->nfile.next;
9708                         parsefname();   /* read name of redirection file */
9709                         break;
9710                 case TLP:
9711                         if (
9712                                 args && app == &args->narg.next &&
9713                                 !vars && !redir
9714                         ) {
9715                                 struct builtincmd *bcmd;
9716                                 const char *name;
9717
9718                                 /* We have a function */
9719                                 if (readtoken() != TRP)
9720                                         synexpect(TRP);
9721                                 name = n->narg.text;
9722                                 if (
9723                                         !goodname(name) || (
9724                                                 (bcmd = find_builtin(name)) &&
9725                                                 IS_BUILTIN_SPECIAL(bcmd)
9726                                         )
9727                                 )
9728                                         synerror("Bad function name");
9729                                 n->type = NDEFUN;
9730                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9731                                 n->narg.next = command();
9732                                 return n;
9733                         }
9734                         /* fall through */
9735                 default:
9736                         tokpushback++;
9737                         goto out;
9738                 }
9739         }
9740 out:
9741         *app = NULL;
9742         *vpp = NULL;
9743         *rpp = NULL;
9744         n = (union node *)stalloc(sizeof (struct ncmd));
9745         n->type = NCMD;
9746         n->ncmd.args = args;
9747         n->ncmd.assign = vars;
9748         n->ncmd.redirect = redir;
9749         return n;
9750 }
9751
9752 static union node *
9753 makename(void)
9754 {
9755         union node *n;
9756
9757         n = (union node *)stalloc(sizeof (struct narg));
9758         n->type = NARG;
9759         n->narg.next = NULL;
9760         n->narg.text = wordtext;
9761         n->narg.backquote = backquotelist;
9762         return n;
9763 }
9764
9765 void fixredir(union node *n, const char *text, int err)
9766 {
9767         TRACE(("Fix redir %s %d\n", text, err));
9768         if (!err)
9769                 n->ndup.vname = NULL;
9770
9771         if (is_digit(text[0]) && text[1] == '\0')
9772                 n->ndup.dupfd = digit_val(text[0]);
9773         else if (text[0] == '-' && text[1] == '\0')
9774                 n->ndup.dupfd = -1;
9775         else {
9776
9777                 if (err)
9778                         synerror("Bad fd number");
9779                 else
9780                         n->ndup.vname = makename();
9781         }
9782 }
9783
9784
9785 static void
9786 parsefname(void)
9787 {
9788         union node *n = redirnode;
9789
9790         if (readtoken() != TWORD)
9791                 synexpect(-1);
9792         if (n->type == NHERE) {
9793                 struct heredoc *here = heredoc;
9794                 struct heredoc *p;
9795                 int i;
9796
9797                 if (quoteflag == 0)
9798                         n->type = NXHERE;
9799                 TRACE(("Here document %d\n", n->type));
9800                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9801                         synerror("Illegal eof marker for << redirection");
9802                 rmescapes(wordtext);
9803                 here->eofmark = wordtext;
9804                 here->next = NULL;
9805                 if (heredoclist == NULL)
9806                         heredoclist = here;
9807                 else {
9808                         for (p = heredoclist ; p->next ; p = p->next);
9809                         p->next = here;
9810                 }
9811         } else if (n->type == NTOFD || n->type == NFROMFD) {
9812                 fixredir(n, wordtext, 0);
9813         } else {
9814                 n->nfile.fname = makename();
9815         }
9816 }
9817
9818
9819 /*
9820  * Input any here documents.
9821  */
9822
9823 static void
9824 parseheredoc(void)
9825 {
9826         struct heredoc *here;
9827         union node *n;
9828
9829         here = heredoclist;
9830         heredoclist = 0;
9831
9832         while (here) {
9833                 if (needprompt) {
9834                         setprompt(2);
9835                         needprompt = 0;
9836                 }
9837                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9838                                 here->eofmark, here->striptabs);
9839                 n = (union node *)stalloc(sizeof (struct narg));
9840                 n->narg.type = NARG;
9841                 n->narg.next = NULL;
9842                 n->narg.text = wordtext;
9843                 n->narg.backquote = backquotelist;
9844                 here->here->nhere.doc = n;
9845                 here = here->next;
9846         }
9847 }
9848
9849 static char peektoken(void)
9850 {
9851         int t;
9852
9853         t = readtoken();
9854         tokpushback++;
9855         return tokname_array[t][0];
9856 }
9857
9858 static int
9859 readtoken(void)
9860 {
9861         int t;
9862 #ifdef DEBUG
9863         int alreadyseen = tokpushback;
9864 #endif
9865
9866 #ifdef CONFIG_ASH_ALIAS
9867 top:
9868 #endif
9869
9870         t = xxreadtoken();
9871
9872         /*
9873          * eat newlines
9874          */
9875         if (checkkwd & CHKNL) {
9876                 while (t == TNL) {
9877                         parseheredoc();
9878                         t = xxreadtoken();
9879                 }
9880         }
9881
9882         if (t != TWORD || quoteflag) {
9883                 goto out;
9884         }
9885
9886         /*
9887          * check for keywords
9888          */
9889         if (checkkwd & CHKKWD) {
9890                 const char *const *pp;
9891
9892                 if ((pp = findkwd(wordtext))) {
9893                         lasttoken = t = pp - tokname_array;
9894                         TRACE(("keyword %s recognized\n", tokname(t)));
9895                         goto out;
9896                 }
9897         }
9898
9899         if (checkkwd & CHKALIAS) {
9900 #ifdef CONFIG_ASH_ALIAS
9901                 struct alias *ap;
9902                 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9903                         if (*ap->val) {
9904                                 pushstring(ap->val, ap);
9905                         }
9906                         goto top;
9907                 }
9908 #endif
9909         }
9910 out:
9911         checkkwd = 0;
9912 #ifdef DEBUG
9913         if (!alreadyseen)
9914             TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9915         else
9916             TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9917 #endif
9918         return (t);
9919 }
9920
9921
9922 /*
9923  * Read the next input token.
9924  * If the token is a word, we set backquotelist to the list of cmds in
9925  *      backquotes.  We set quoteflag to true if any part of the word was
9926  *      quoted.
9927  * If the token is TREDIR, then we set redirnode to a structure containing
9928  *      the redirection.
9929  * In all cases, the variable startlinno is set to the number of the line
9930  *      on which the token starts.
9931  *
9932  * [Change comment:  here documents and internal procedures]
9933  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
9934  *  word parsing code into a separate routine.  In this case, readtoken
9935  *  doesn't need to have any internal procedures, but parseword does.
9936  *  We could also make parseoperator in essence the main routine, and
9937  *  have parseword (readtoken1?) handle both words and redirection.]
9938  */
9939
9940 #define NEW_xxreadtoken
9941 #ifdef NEW_xxreadtoken
9942
9943 /* singles must be first! */
9944 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9945
9946 static const char xxreadtoken_tokens[] = {
9947         TNL, TLP, TRP,          /* only single occurrence allowed */
9948         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9949         TEOF,                   /* corresponds to trailing nul */
9950         TAND, TOR, TENDCASE,    /* if double occurrence */
9951 };
9952
9953 #define xxreadtoken_doubles \
9954         (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9955 #define xxreadtoken_singles \
9956         (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9957
9958 static int xxreadtoken()
9959 {
9960         int c;
9961
9962         if (tokpushback) {
9963                 tokpushback = 0;
9964                 return lasttoken;
9965         }
9966         if (needprompt) {
9967                 setprompt(2);
9968                 needprompt = 0;
9969         }
9970         startlinno = plinno;
9971         for (;;) {                      /* until token or start of word found */
9972                 c = pgetc_macro();
9973
9974                 if ((c != ' ') && (c != '\t')
9975 #ifdef CONFIG_ASH_ALIAS
9976                         && (c != PEOA)
9977 #endif
9978                         ) {
9979                         if (c == '#') {
9980                                 while ((c = pgetc()) != '\n' && c != PEOF);
9981                                 pungetc();
9982                         } else if (c == '\\') {
9983                                 if (pgetc() != '\n') {
9984                                         pungetc();
9985                                         goto READTOKEN1;
9986                                 }
9987                                 startlinno = ++plinno;
9988                                 if (doprompt)
9989                                         setprompt(2);
9990                         } else {
9991                                 const char *p
9992                                         = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9993
9994                                 if (c != PEOF) {
9995                                         if (c == '\n') {
9996                                                 plinno++;
9997                                                 needprompt = doprompt;
9998                                         }
9999
10000                                         p = strchr(xxreadtoken_chars, c);
10001                                         if (p == NULL) {
10002                                           READTOKEN1:
10003                                                 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10004                                         }
10005
10006                                         if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10007                                                 if (pgetc() == *p) {    /* double occurrence? */
10008                                                         p += xxreadtoken_doubles + 1;
10009                                                 } else {
10010                                                         pungetc();
10011                                                 }
10012                                         }
10013                                 }
10014
10015                                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10016                         }
10017                 }
10018         }
10019 }
10020
10021
10022 #else
10023 #define RETURN(token)   return lasttoken = token
10024
10025 static int
10026 xxreadtoken(void)
10027 {
10028         int c;
10029
10030         if (tokpushback) {
10031                 tokpushback = 0;
10032                 return lasttoken;
10033         }
10034         if (needprompt) {
10035                 setprompt(2);
10036                 needprompt = 0;
10037         }
10038         startlinno = plinno;
10039         for (;;) {      /* until token or start of word found */
10040                 c = pgetc_macro();
10041                 switch (c) {
10042                 case ' ': case '\t':
10043 #ifdef CONFIG_ASH_ALIAS
10044                 case PEOA:
10045 #endif
10046                         continue;
10047                 case '#':
10048                         while ((c = pgetc()) != '\n' && c != PEOF);
10049                         pungetc();
10050                         continue;
10051                 case '\\':
10052                         if (pgetc() == '\n') {
10053                                 startlinno = ++plinno;
10054                                 if (doprompt)
10055                                         setprompt(2);
10056                                 continue;
10057                         }
10058                         pungetc();
10059                         goto breakloop;
10060                 case '\n':
10061                         plinno++;
10062                         needprompt = doprompt;
10063                         RETURN(TNL);
10064                 case PEOF:
10065                         RETURN(TEOF);
10066                 case '&':
10067                         if (pgetc() == '&')
10068                                 RETURN(TAND);
10069                         pungetc();
10070                         RETURN(TBACKGND);
10071                 case '|':
10072                         if (pgetc() == '|')
10073                                 RETURN(TOR);
10074                         pungetc();
10075                         RETURN(TPIPE);
10076                 case ';':
10077                         if (pgetc() == ';')
10078                                 RETURN(TENDCASE);
10079                         pungetc();
10080                         RETURN(TSEMI);
10081                 case '(':
10082                         RETURN(TLP);
10083                 case ')':
10084                         RETURN(TRP);
10085                 default:
10086                         goto breakloop;
10087                 }
10088         }
10089 breakloop:
10090         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10091 #undef RETURN
10092 }
10093 #endif /* NEW_xxreadtoken */
10094
10095
10096 /*
10097  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10098  * is not NULL, read a here document.  In the latter case, eofmark is the
10099  * word which marks the end of the document and striptabs is true if
10100  * leading tabs should be stripped from the document.  The argument firstc
10101  * is the first character of the input token or document.
10102  *
10103  * Because C does not have internal subroutines, I have simulated them
10104  * using goto's to implement the subroutine linkage.  The following macros
10105  * will run code that appears at the end of readtoken1.
10106  */
10107
10108 #define CHECKEND()      {goto checkend; checkend_return:;}
10109 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10110 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10111 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10112 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10113 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10114
10115 static int
10116 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10117 {
10118         int c = firstc;
10119         char *out;
10120         int len;
10121         char line[EOFMARKLEN + 1];
10122         struct nodelist *bqlist;
10123         int quotef;
10124         int dblquote;
10125         int varnest;    /* levels of variables expansion */
10126         int arinest;    /* levels of arithmetic expansion */
10127         int parenlevel; /* levels of parens in arithmetic */
10128         int dqvarnest;  /* levels of variables expansion within double quotes */
10129         int oldstyle;
10130         int prevsyntax; /* syntax before arithmetic */
10131 #if __GNUC__
10132         /* Avoid longjmp clobbering */
10133         (void) &out;
10134         (void) &quotef;
10135         (void) &dblquote;
10136         (void) &varnest;
10137         (void) &arinest;
10138         (void) &parenlevel;
10139         (void) &dqvarnest;
10140         (void) &oldstyle;
10141         (void) &prevsyntax;
10142         (void) &syntax;
10143 #endif
10144
10145         startlinno = plinno;
10146         dblquote = 0;
10147         if (syntax == DQSYNTAX)
10148                 dblquote = 1;
10149         quotef = 0;
10150         bqlist = NULL;
10151         varnest = 0;
10152         arinest = 0;
10153         parenlevel = 0;
10154         dqvarnest = 0;
10155
10156         STARTSTACKSTR(out);
10157         loop: { /* for each line, until end of word */
10158                 CHECKEND();     /* set c to PEOF if at end of here document */
10159                 for (;;) {      /* until end of line or end of word */
10160                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10161                         switch(SIT(c, syntax)) {
10162                         case CNL:       /* '\n' */
10163                                 if (syntax == BASESYNTAX)
10164                                         goto endword;   /* exit outer loop */
10165                                 USTPUTC(c, out);
10166                                 plinno++;
10167                                 if (doprompt)
10168                                         setprompt(2);
10169                                 c = pgetc();
10170                                 goto loop;              /* continue outer loop */
10171                         case CWORD:
10172                                 USTPUTC(c, out);
10173                                 break;
10174                         case CCTL:
10175                                 if (eofmark == NULL || dblquote)
10176                                         USTPUTC(CTLESC, out);
10177                                 USTPUTC(c, out);
10178                                 break;
10179                         case CBACK:     /* backslash */
10180                                 c = pgetc2();
10181                                 if (c == PEOF) {
10182                                         USTPUTC(CTLESC, out);
10183                                         USTPUTC('\\', out);
10184                                         pungetc();
10185                                 } else if (c == '\n') {
10186                                         if (doprompt)
10187                                                 setprompt(2);
10188                                 } else {
10189                                         if (
10190                                                 dblquote &&
10191                                                 c != '\\' && c != '`' &&
10192                                                 c != '$' && (
10193                                                         c != '"' ||
10194                                                         eofmark != NULL
10195                                                 )
10196                                         ) {
10197                                                 USTPUTC(CTLESC, out);
10198                                                 USTPUTC('\\', out);
10199                                         }
10200                                         if (SIT(c, SQSYNTAX) == CCTL)
10201                                                 USTPUTC(CTLESC, out);
10202                                         USTPUTC(c, out);
10203                                         quotef++;
10204                                 }
10205                                 break;
10206                         case CSQUOTE:
10207                                 syntax = SQSYNTAX;
10208 quotemark:
10209                                 if (eofmark == NULL) {
10210                                         USTPUTC(CTLQUOTEMARK, out);
10211                                 }
10212                                 break;
10213                         case CDQUOTE:
10214                                 syntax = DQSYNTAX;
10215                                 dblquote = 1;
10216                                 goto quotemark;
10217                         case CENDQUOTE:
10218                                 if (eofmark != NULL && arinest == 0 &&
10219                                     varnest == 0) {
10220                                         USTPUTC(c, out);
10221                                 } else {
10222                                         if (dqvarnest == 0) {
10223                                                 syntax = BASESYNTAX;
10224                                                 dblquote = 0;
10225                                         }
10226                                         quotef++;
10227                                         goto quotemark;
10228                                 }
10229                                 break;
10230                         case CVAR:      /* '$' */
10231                                 PARSESUB();             /* parse substitution */
10232                                 break;
10233                         case CENDVAR:   /* '}' */
10234                                 if (varnest > 0) {
10235                                         varnest--;
10236                                         if (dqvarnest > 0) {
10237                                                 dqvarnest--;
10238                                         }
10239                                         USTPUTC(CTLENDVAR, out);
10240                                 } else {
10241                                         USTPUTC(c, out);
10242                                 }
10243                                 break;
10244 #ifdef CONFIG_ASH_MATH_SUPPORT
10245                         case CLP:       /* '(' in arithmetic */
10246                                 parenlevel++;
10247                                 USTPUTC(c, out);
10248                                 break;
10249                         case CRP:       /* ')' in arithmetic */
10250                                 if (parenlevel > 0) {
10251                                         USTPUTC(c, out);
10252                                         --parenlevel;
10253                                 } else {
10254                                         if (pgetc() == ')') {
10255                                                 if (--arinest == 0) {
10256                                                         USTPUTC(CTLENDARI, out);
10257                                                         syntax = prevsyntax;
10258                                                         if (syntax == DQSYNTAX)
10259                                                                 dblquote = 1;
10260                                                         else
10261                                                                 dblquote = 0;
10262                                                 } else
10263                                                         USTPUTC(')', out);
10264                                         } else {
10265                                                 /*
10266                                                  * unbalanced parens
10267                                                  *  (don't 2nd guess - no error)
10268                                                  */
10269                                                 pungetc();
10270                                                 USTPUTC(')', out);
10271                                         }
10272                                 }
10273                                 break;
10274 #endif
10275                         case CBQUOTE:   /* '`' */
10276                                 PARSEBACKQOLD();
10277                                 break;
10278                         case CENDFILE:
10279                                 goto endword;           /* exit outer loop */
10280                         case CIGN:
10281                                 break;
10282                         default:
10283                                 if (varnest == 0)
10284                                         goto endword;   /* exit outer loop */
10285 #ifdef CONFIG_ASH_ALIAS
10286                                 if (c != PEOA)
10287 #endif
10288                                         USTPUTC(c, out);
10289
10290                         }
10291                         c = pgetc_macro();
10292                 }
10293         }
10294 endword:
10295 #ifdef CONFIG_ASH_MATH_SUPPORT
10296         if (syntax == ARISYNTAX)
10297                 synerror("Missing '))'");
10298 #endif
10299         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10300                 synerror("Unterminated quoted string");
10301         if (varnest != 0) {
10302                 startlinno = plinno;
10303                 /* { */
10304                 synerror("Missing '}'");
10305         }
10306         USTPUTC('\0', out);
10307         len = out - (char *)stackblock();
10308         out = stackblock();
10309         if (eofmark == NULL) {
10310                 if ((c == '>' || c == '<')
10311                  && quotef == 0
10312                  && len <= 2
10313                  && (*out == '\0' || is_digit(*out))) {
10314                         PARSEREDIR();
10315                         return lasttoken = TREDIR;
10316                 } else {
10317                         pungetc();
10318                 }
10319         }
10320         quoteflag = quotef;
10321         backquotelist = bqlist;
10322         grabstackblock(len);
10323         wordtext = out;
10324         return lasttoken = TWORD;
10325 /* end of readtoken routine */
10326
10327
10328
10329 /*
10330  * Check to see whether we are at the end of the here document.  When this
10331  * is called, c is set to the first character of the next input line.  If
10332  * we are at the end of the here document, this routine sets the c to PEOF.
10333  */
10334
10335 checkend: {
10336         if (eofmark) {
10337 #ifdef CONFIG_ASH_ALIAS
10338                 if (c == PEOA) {
10339                         c = pgetc2();
10340                 }
10341 #endif
10342                 if (striptabs) {
10343                         while (c == '\t') {
10344                                 c = pgetc2();
10345                         }
10346                 }
10347                 if (c == *eofmark) {
10348                         if (pfgets(line, sizeof line) != NULL) {
10349                                 char *p, *q;
10350
10351                                 p = line;
10352                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10353                                 if (*p == '\n' && *q == '\0') {
10354                                         c = PEOF;
10355                                         plinno++;
10356                                         needprompt = doprompt;
10357                                 } else {
10358                                         pushstring(line, NULL);
10359                                 }
10360                         }
10361                 }
10362         }
10363         goto checkend_return;
10364 }
10365
10366
10367 /*
10368  * Parse a redirection operator.  The variable "out" points to a string
10369  * specifying the fd to be redirected.  The variable "c" contains the
10370  * first character of the redirection operator.
10371  */
10372
10373 parseredir: {
10374         char fd = *out;
10375         union node *np;
10376
10377         np = (union node *)stalloc(sizeof (struct nfile));
10378         if (c == '>') {
10379                 np->nfile.fd = 1;
10380                 c = pgetc();
10381                 if (c == '>')
10382                         np->type = NAPPEND;
10383                 else if (c == '|')
10384                         np->type = NCLOBBER;
10385                 else if (c == '&')
10386                         np->type = NTOFD;
10387                 else {
10388                         np->type = NTO;
10389                         pungetc();
10390                 }
10391         } else {        /* c == '<' */
10392                 np->nfile.fd = 0;
10393                 switch (c = pgetc()) {
10394                 case '<':
10395                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10396                                 np = (union node *)stalloc(sizeof (struct nhere));
10397                                 np->nfile.fd = 0;
10398                         }
10399                         np->type = NHERE;
10400                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10401                         heredoc->here = np;
10402                         if ((c = pgetc()) == '-') {
10403                                 heredoc->striptabs = 1;
10404                         } else {
10405                                 heredoc->striptabs = 0;
10406                                 pungetc();
10407                         }
10408                         break;
10409
10410                 case '&':
10411                         np->type = NFROMFD;
10412                         break;
10413
10414                 case '>':
10415                         np->type = NFROMTO;
10416                         break;
10417
10418                 default:
10419                         np->type = NFROM;
10420                         pungetc();
10421                         break;
10422                 }
10423         }
10424         if (fd != '\0')
10425                 np->nfile.fd = digit_val(fd);
10426         redirnode = np;
10427         goto parseredir_return;
10428 }
10429
10430
10431 /*
10432  * Parse a substitution.  At this point, we have read the dollar sign
10433  * and nothing else.
10434  */
10435
10436 parsesub: {
10437         int subtype;
10438         int typeloc;
10439         int flags;
10440         char *p;
10441         static const char types[] = "}-+?=";
10442
10443         c = pgetc();
10444         if (
10445                 c <= PEOA_OR_PEOF  ||
10446                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10447         ) {
10448                 USTPUTC('$', out);
10449                 pungetc();
10450         } else if (c == '(') {  /* $(command) or $((arith)) */
10451                 if (pgetc() == '(') {
10452 #ifdef CONFIG_ASH_MATH_SUPPORT
10453                         PARSEARITH();
10454 #else
10455                         synerror("We unsupport $((arith))");
10456 #endif
10457                 } else {
10458                         pungetc();
10459                         PARSEBACKQNEW();
10460                 }
10461         } else {
10462                 USTPUTC(CTLVAR, out);
10463                 typeloc = out - (char *)stackblock();
10464                 USTPUTC(VSNORMAL, out);
10465                 subtype = VSNORMAL;
10466                 if (c == '{') {
10467                         c = pgetc();
10468                         if (c == '#') {
10469                                 if ((c = pgetc()) == '}')
10470                                         c = '#';
10471                                 else
10472                                         subtype = VSLENGTH;
10473                         }
10474                         else
10475                                 subtype = 0;
10476                 }
10477                 if (c > PEOA_OR_PEOF && is_name(c)) {
10478                         do {
10479                                 STPUTC(c, out);
10480                                 c = pgetc();
10481                         } while (c > PEOA_OR_PEOF && is_in_name(c));
10482                 } else if (is_digit(c)) {
10483                         do {
10484                                 STPUTC(c, out);
10485                                 c = pgetc();
10486                         } while (is_digit(c));
10487                 }
10488                 else if (is_special(c)) {
10489                         USTPUTC(c, out);
10490                         c = pgetc();
10491                 }
10492                 else
10493 badsub:                 synerror("Bad substitution");
10494
10495                 STPUTC('=', out);
10496                 flags = 0;
10497                 if (subtype == 0) {
10498                         switch (c) {
10499                         case ':':
10500                                 flags = VSNUL;
10501                                 c = pgetc();
10502                                 /*FALLTHROUGH*/
10503                         default:
10504                                 p = strchr(types, c);
10505                                 if (p == NULL)
10506                                         goto badsub;
10507                                 subtype = p - types + VSNORMAL;
10508                                 break;
10509                         case '%':
10510                         case '#':
10511                                 {
10512                                         int cc = c;
10513                                         subtype = c == '#' ? VSTRIMLEFT :
10514                                                              VSTRIMRIGHT;
10515                                         c = pgetc();
10516                                         if (c == cc)
10517                                                 subtype++;
10518                                         else
10519                                                 pungetc();
10520                                         break;
10521                                 }
10522                         }
10523                 } else {
10524                         pungetc();
10525                 }
10526                 if (dblquote || arinest)
10527                         flags |= VSQUOTE;
10528                 *((char *)stackblock() + typeloc) = subtype | flags;
10529                 if (subtype != VSNORMAL) {
10530                         varnest++;
10531                         if (dblquote || arinest) {
10532                                 dqvarnest++;
10533                         }
10534                 }
10535         }
10536         goto parsesub_return;
10537 }
10538
10539
10540 /*
10541  * Called to parse command substitutions.  Newstyle is set if the command
10542  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10543  * list of commands (passed by reference), and savelen is the number of
10544  * characters on the top of the stack which must be preserved.
10545  */
10546
10547 parsebackq: {
10548         struct nodelist **nlpp;
10549         int savepbq;
10550         union node *n;
10551         char *volatile str;
10552         struct jmploc jmploc;
10553         struct jmploc *volatile savehandler;
10554         size_t savelen;
10555         int saveprompt;
10556 #ifdef __GNUC__
10557         (void) &saveprompt;
10558 #endif
10559
10560         savepbq = parsebackquote;
10561         if (setjmp(jmploc.loc)) {
10562                 if (str)
10563                         ckfree(str);
10564                 parsebackquote = 0;
10565                 handler = savehandler;
10566                 longjmp(handler->loc, 1);
10567         }
10568         INTOFF;
10569         str = NULL;
10570         savelen = out - (char *)stackblock();
10571         if (savelen > 0) {
10572                 str = ckmalloc(savelen);
10573                 memcpy(str, stackblock(), savelen);
10574         }
10575         savehandler = handler;
10576         handler = &jmploc;
10577         INTON;
10578         if (oldstyle) {
10579                 /* We must read until the closing backquote, giving special
10580                    treatment to some slashes, and then push the string and
10581                    reread it as input, interpreting it normally.  */
10582                 char *pout;
10583                 int pc;
10584                 size_t psavelen;
10585                 char *pstr;
10586
10587
10588                 STARTSTACKSTR(pout);
10589                 for (;;) {
10590                         if (needprompt) {
10591                                 setprompt(2);
10592                                 needprompt = 0;
10593                         }
10594                         switch (pc = pgetc()) {
10595                         case '`':
10596                                 goto done;
10597
10598                         case '\\':
10599                                 if ((pc = pgetc()) == '\n') {
10600                                         plinno++;
10601                                         if (doprompt)
10602                                                 setprompt(2);
10603                                         /*
10604                                          * If eating a newline, avoid putting
10605                                          * the newline into the new character
10606                                          * stream (via the STPUTC after the
10607                                          * switch).
10608                                          */
10609                                         continue;
10610                                 }
10611                                 if (pc != '\\' && pc != '`' && pc != '$'
10612                                     && (!dblquote || pc != '"'))
10613                                         STPUTC('\\', pout);
10614                                 if (pc > PEOA_OR_PEOF) {
10615                                         break;
10616                                 }
10617                                 /* fall through */
10618
10619                         case PEOF:
10620 #ifdef CONFIG_ASH_ALIAS
10621                         case PEOA:
10622 #endif
10623                                 startlinno = plinno;
10624                                 synerror("EOF in backquote substitution");
10625
10626                         case '\n':
10627                                 plinno++;
10628                                 needprompt = doprompt;
10629                                 break;
10630
10631                         default:
10632                                 break;
10633                         }
10634                         STPUTC(pc, pout);
10635                 }
10636 done:
10637                 STPUTC('\0', pout);
10638                 psavelen = pout - (char *)stackblock();
10639                 if (psavelen > 0) {
10640                         pstr = grabstackstr(pout);
10641                         setinputstring(pstr);
10642                 }
10643         }
10644         nlpp = &bqlist;
10645         while (*nlpp)
10646                 nlpp = &(*nlpp)->next;
10647         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10648         (*nlpp)->next = NULL;
10649         parsebackquote = oldstyle;
10650
10651         if (oldstyle) {
10652                 saveprompt = doprompt;
10653                 doprompt = 0;
10654         }
10655
10656         n = list(2);
10657
10658         if (oldstyle)
10659                 doprompt = saveprompt;
10660         else {
10661                 if (readtoken() != TRP)
10662                         synexpect(TRP);
10663         }
10664
10665         (*nlpp)->n = n;
10666         if (oldstyle) {
10667                 /*
10668                  * Start reading from old file again, ignoring any pushed back
10669                  * tokens left from the backquote parsing
10670                  */
10671                 popfile();
10672                 tokpushback = 0;
10673         }
10674         while (stackblocksize() <= savelen)
10675                 growstackblock();
10676         STARTSTACKSTR(out);
10677         if (str) {
10678                 memcpy(out, str, savelen);
10679                 STADJUST(savelen, out);
10680                 INTOFF;
10681                 ckfree(str);
10682                 str = NULL;
10683                 INTON;
10684         }
10685         parsebackquote = savepbq;
10686         handler = savehandler;
10687         if (arinest || dblquote)
10688                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10689         else
10690                 USTPUTC(CTLBACKQ, out);
10691         if (oldstyle)
10692                 goto parsebackq_oldreturn;
10693         else
10694                 goto parsebackq_newreturn;
10695 }
10696
10697 #ifdef CONFIG_ASH_MATH_SUPPORT
10698 /*
10699  * Parse an arithmetic expansion (indicate start of one and set state)
10700  */
10701 parsearith: {
10702
10703         if (++arinest == 1) {
10704                 prevsyntax = syntax;
10705                 syntax = ARISYNTAX;
10706                 USTPUTC(CTLARI, out);
10707                 if (dblquote)
10708                         USTPUTC('"',out);
10709                 else
10710                         USTPUTC(' ',out);
10711         } else {
10712                 /*
10713                  * we collapse embedded arithmetic expansion to
10714                  * parenthesis, which should be equivalent
10715                  */
10716                 USTPUTC('(', out);
10717         }
10718         goto parsearith_return;
10719 }
10720 #endif
10721
10722 } /* end of readtoken */
10723
10724
10725
10726 /*
10727  * Returns true if the text contains nothing to expand (no dollar signs
10728  * or backquotes).
10729  */
10730
10731 static int
10732 noexpand(char *text)
10733 {
10734         char *p;
10735         char c;
10736
10737         p = text;
10738         while ((c = *p++) != '\0') {
10739                 if (c == CTLQUOTEMARK)
10740                         continue;
10741                 if (c == CTLESC)
10742                         p++;
10743                 else if (SIT(c, BASESYNTAX) == CCTL)
10744                         return 0;
10745         }
10746         return 1;
10747 }
10748
10749
10750 /*
10751  * Return of a legal variable name (a letter or underscore followed by zero or
10752  * more letters, underscores, and digits).
10753  */
10754
10755 char *
10756 endofname(const char *name)
10757 {
10758         char *p;
10759
10760         p = (char *) name;
10761         if (! is_name(*p))
10762                 return p;
10763         while (*++p) {
10764                 if (! is_in_name(*p))
10765                         break;
10766         }
10767         return p;
10768 }
10769
10770
10771 /*
10772  * Called when an unexpected token is read during the parse.  The argument
10773  * is the token that is expected, or -1 if more than one type of token can
10774  * occur at this point.
10775  */
10776
10777 static void synexpect(int token)
10778 {
10779         char msg[64];
10780         int l;
10781
10782         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10783         if (token >= 0)
10784                 sprintf(msg + l, " (expecting %s)", tokname(token));
10785         synerror(msg);
10786         /* NOTREACHED */
10787 }
10788
10789 static void
10790 synerror(const char *msg)
10791 {
10792         error("Syntax error: %s", msg);
10793         /* NOTREACHED */
10794 }
10795
10796
10797 /*
10798  * called by editline -- any expansions to the prompt
10799  *    should be added here.
10800  */
10801
10802 static void setprompt(int whichprompt)
10803 {
10804         const char *prompt;
10805
10806         switch (whichprompt) {
10807         case 1:
10808                 prompt = ps1val();
10809                 break;
10810         case 2:
10811                 prompt = ps2val();
10812                 break;
10813         default:                        /* 0 */
10814                 prompt = nullstr;
10815         }
10816         putprompt(prompt);
10817 }
10818
10819
10820 static const char *const *findkwd(const char *s)
10821 {
10822         return bsearch(s, tokname_array + KWDOFFSET,
10823                        (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10824                                    sizeof(const char *), pstrcmp);
10825 }
10826
10827 /*      $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $      */
10828
10829 /*
10830  * Code for dealing with input/output redirection.
10831  */
10832
10833 #define EMPTY -2                /* marks an unused slot in redirtab */
10834 #ifndef PIPE_BUF
10835 # define PIPESIZE 4096          /* amount of buffering in a pipe */
10836 #else
10837 # define PIPESIZE PIPE_BUF
10838 #endif
10839
10840 /*
10841  * Open a file in noclobber mode.
10842  * The code was copied from bash.
10843  */
10844 static inline int
10845 noclobberopen(const char *fname)
10846 {
10847         int r, fd;
10848         struct stat finfo, finfo2;
10849
10850         /*
10851          * If the file exists and is a regular file, return an error
10852          * immediately.
10853          */
10854         r = stat(fname, &finfo);
10855         if (r == 0 && S_ISREG(finfo.st_mode)) {
10856                 errno = EEXIST;
10857                 return -1;
10858         }
10859
10860         /*
10861          * If the file was not present (r != 0), make sure we open it
10862          * exclusively so that if it is created before we open it, our open
10863          * will fail.  Make sure that we do not truncate an existing file.
10864          * Note that we don't turn on O_EXCL unless the stat failed -- if the
10865          * file was not a regular file, we leave O_EXCL off.
10866          */
10867         if (r != 0)
10868                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10869         fd = open(fname, O_WRONLY|O_CREAT, 0666);
10870
10871         /* If the open failed, return the file descriptor right away. */
10872         if (fd < 0)
10873                 return fd;
10874
10875         /*
10876          * OK, the open succeeded, but the file may have been changed from a
10877          * non-regular file to a regular file between the stat and the open.
10878          * We are assuming that the O_EXCL open handles the case where FILENAME
10879          * did not exist and is symlinked to an existing file between the stat
10880          * and open.
10881          */
10882
10883         /*
10884          * If we can open it and fstat the file descriptor, and neither check
10885          * revealed that it was a regular file, and the file has not been
10886          * replaced, return the file descriptor.
10887          */
10888          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10889              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10890                 return fd;
10891
10892         /* The file has been replaced.  badness. */
10893         close(fd);
10894         errno = EEXIST;
10895         return -1;
10896 }
10897
10898 /*
10899  * Handle here documents.  Normally we fork off a process to write the
10900  * data to a pipe.  If the document is short, we can stuff the data in
10901  * the pipe without forking.
10902  */
10903
10904 static inline int
10905 openhere(union node *redir)
10906 {
10907         int pip[2];
10908         size_t len = 0;
10909
10910         if (pipe(pip) < 0)
10911                 error("Pipe call failed");
10912         if (redir->type == NHERE) {
10913                 len = strlen(redir->nhere.doc->narg.text);
10914                 if (len <= PIPESIZE) {
10915                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
10916                         goto out;
10917                 }
10918         }
10919         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10920                 close(pip[0]);
10921                 signal(SIGINT, SIG_IGN);
10922                 signal(SIGQUIT, SIG_IGN);
10923                 signal(SIGHUP, SIG_IGN);
10924 #ifdef SIGTSTP
10925                 signal(SIGTSTP, SIG_IGN);
10926 #endif
10927                 signal(SIGPIPE, SIG_DFL);
10928                 if (redir->type == NHERE)
10929                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
10930                 else
10931                         expandhere(redir->nhere.doc, pip[1]);
10932                 _exit(0);
10933         }
10934 out:
10935         close(pip[1]);
10936         return pip[0];
10937 }
10938
10939 static int
10940 openredirect(union node *redir)
10941 {
10942         char *fname;
10943         int f;
10944
10945         switch (redir->nfile.type) {
10946         case NFROM:
10947                 fname = redir->nfile.expfname;
10948                 if ((f = open(fname, O_RDONLY)) < 0)
10949                         goto eopen;
10950                 break;
10951         case NFROMTO:
10952                 fname = redir->nfile.expfname;
10953                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10954                         goto ecreate;
10955                 break;
10956         case NTO:
10957                 /* Take care of noclobber mode. */
10958                 if (Cflag) {
10959                         fname = redir->nfile.expfname;
10960                         if ((f = noclobberopen(fname)) < 0)
10961                                 goto ecreate;
10962                         break;
10963                 }
10964                 /* FALLTHROUGH */
10965         case NCLOBBER:
10966                 fname = redir->nfile.expfname;
10967                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10968                         goto ecreate;
10969                 break;
10970         case NAPPEND:
10971                 fname = redir->nfile.expfname;
10972                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10973                         goto ecreate;
10974                 break;
10975         default:
10976 #ifdef DEBUG
10977                 abort();
10978 #endif
10979                 /* Fall through to eliminate warning. */
10980         case NTOFD:
10981         case NFROMFD:
10982                 f = -1;
10983                 break;
10984         case NHERE:
10985         case NXHERE:
10986                 f = openhere(redir);
10987                 break;
10988         }
10989
10990         return f;
10991 ecreate:
10992         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10993 eopen:
10994         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10995 }
10996
10997 static inline void
10998 dupredirect(union node *redir, int f)
10999 {
11000         int fd = redir->nfile.fd;
11001
11002         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11003                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11004                                 copyfd(redir->ndup.dupfd, fd);
11005                 }
11006                 return;
11007         }
11008
11009         if (f != fd) {
11010                 copyfd(f, fd);
11011                 close(f);
11012         }
11013         return;
11014 }
11015
11016 /*
11017  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
11018  * old file descriptors are stashed away so that the redirection can be
11019  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
11020  * standard output, and the standard error if it becomes a duplicate of
11021  * stdout, is saved in memory.
11022  */
11023
11024 static void
11025 redirect(union node *redir, int flags)
11026 {
11027         union node *n;
11028         struct redirtab *sv;
11029         int i;
11030         int fd;
11031         int newfd;
11032         int *p;
11033         nullredirs++;
11034         if (!redir) {
11035                 return;
11036         }
11037         sv = NULL;
11038         INTOFF;
11039         if (flags & REDIR_PUSH) {
11040                 struct redirtab *q;
11041                 q = ckmalloc(sizeof (struct redirtab));
11042                 q->next = redirlist;
11043                 redirlist = q;
11044                 q->nullredirs = nullredirs - 1;
11045                 for (i = 0 ; i < 10 ; i++)
11046                         q->renamed[i] = EMPTY;
11047                 nullredirs = 0;
11048                 sv = q;
11049         }
11050         n = redir;
11051         do {
11052                 fd = n->nfile.fd;
11053                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11054                     n->ndup.dupfd == fd)
11055                         continue; /* redirect from/to same file descriptor */
11056
11057                 newfd = openredirect(n);
11058                 if (fd == newfd)
11059                         continue;
11060                 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11061                         i = fcntl(fd, F_DUPFD, 10);
11062
11063                         if (i == -1) {
11064                                 i = errno;
11065                                 if (i != EBADF) {
11066                                         close(newfd);
11067                                         errno = i;
11068                                         error("%d: %m", fd);
11069                                         /* NOTREACHED */
11070                                 }
11071                         } else {
11072                                 *p = i;
11073                                 close(fd);
11074                         }
11075                 } else {
11076                         close(fd);
11077                 }
11078                 dupredirect(n, newfd);
11079         } while ((n = n->nfile.next));
11080         INTON;
11081         if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11082                 preverrout_fd = sv->renamed[2];
11083 }
11084
11085
11086 /*
11087  * Undo the effects of the last redirection.
11088  */
11089
11090 void
11091 popredir(int drop)
11092 {
11093         struct redirtab *rp;
11094         int i;
11095
11096         if (--nullredirs >= 0)
11097                 return;
11098         INTOFF;
11099         rp = redirlist;
11100         for (i = 0 ; i < 10 ; i++) {
11101                 if (rp->renamed[i] != EMPTY) {
11102                         if (!drop) {
11103                                 close(i);
11104                                 copyfd(rp->renamed[i], i);
11105                         }
11106                         close(rp->renamed[i]);
11107                 }
11108         }
11109         redirlist = rp->next;
11110         nullredirs = rp->nullredirs;
11111         ckfree(rp);
11112         INTON;
11113 }
11114
11115 /*
11116  * Undo all redirections.  Called on error or interrupt.
11117  */
11118
11119 /*
11120  * Discard all saved file descriptors.
11121  */
11122
11123 void
11124 clearredir(int drop)
11125 {
11126         for (;;) {
11127                 nullredirs = 0;
11128                 if (!redirlist)
11129                         break;
11130                 popredir(drop);
11131         }
11132 }
11133
11134
11135 /*
11136  * Copy a file descriptor to be >= to.  Returns -1
11137  * if the source file descriptor is closed, EMPTY if there are no unused
11138  * file descriptors left.
11139  */
11140
11141 int
11142 copyfd(int from, int to)
11143 {
11144         int newfd;
11145
11146         newfd = fcntl(from, F_DUPFD, to);
11147         if (newfd < 0) {
11148                 if (errno == EMFILE)
11149                         return EMPTY;
11150                 else
11151                         error("%d: %m", from);
11152         }
11153         return newfd;
11154 }
11155
11156
11157 int
11158 redirectsafe(union node *redir, int flags)
11159 {
11160         int err;
11161         volatile int saveint;
11162         struct jmploc *volatile savehandler = handler;
11163         struct jmploc jmploc;
11164
11165         SAVEINT(saveint);
11166         if (!(err = setjmp(jmploc.loc) * 2)) {
11167                 handler = &jmploc;
11168                 redirect(redir, flags);
11169         }
11170         handler = savehandler;
11171         if (err && exception != EXERROR)
11172                 longjmp(handler->loc, 1);
11173         RESTOREINT(saveint);
11174         return err;
11175 }
11176
11177 /*      $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $    */
11178
11179 #ifdef DEBUG
11180 static void shtree(union node *, int, char *, FILE*);
11181 static void shcmd(union node *, FILE *);
11182 static void sharg(union node *, FILE *);
11183 static void indent(int, char *, FILE *);
11184 static void trstring(char *);
11185
11186
11187 void
11188 showtree(union node *n)
11189 {
11190         trputs("showtree called\n");
11191         shtree(n, 1, NULL, stdout);
11192 }
11193
11194
11195 static void
11196 shtree(union node *n, int ind, char *pfx, FILE *fp)
11197 {
11198         struct nodelist *lp;
11199         const char *s;
11200
11201         if (n == NULL)
11202                 return;
11203
11204         indent(ind, pfx, fp);
11205         switch(n->type) {
11206         case NSEMI:
11207                 s = "; ";
11208                 goto binop;
11209         case NAND:
11210                 s = " && ";
11211                 goto binop;
11212         case NOR:
11213                 s = " || ";
11214 binop:
11215                 shtree(n->nbinary.ch1, ind, NULL, fp);
11216            /*    if (ind < 0) */
11217                         fputs(s, fp);
11218                 shtree(n->nbinary.ch2, ind, NULL, fp);
11219                 break;
11220         case NCMD:
11221                 shcmd(n, fp);
11222                 if (ind >= 0)
11223                         putc('\n', fp);
11224                 break;
11225         case NPIPE:
11226                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11227                         shcmd(lp->n, fp);
11228                         if (lp->next)
11229                                 fputs(" | ", fp);
11230                 }
11231                 if (n->npipe.backgnd)
11232                         fputs(" &", fp);
11233                 if (ind >= 0)
11234                         putc('\n', fp);
11235                 break;
11236         default:
11237                 fprintf(fp, "<node type %d>", n->type);
11238                 if (ind >= 0)
11239                         putc('\n', fp);
11240                 break;
11241         }
11242 }
11243
11244
11245 static void
11246 shcmd(union node *cmd, FILE *fp)
11247 {
11248         union node *np;
11249         int first;
11250         const char *s;
11251         int dftfd;
11252
11253         first = 1;
11254         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11255                 if (! first)
11256                         putchar(' ');
11257                 sharg(np, fp);
11258                 first = 0;
11259         }
11260         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11261                 if (! first)
11262                         putchar(' ');
11263                 switch (np->nfile.type) {
11264                         case NTO:       s = ">";  dftfd = 1; break;
11265                         case NCLOBBER:  s = ">|"; dftfd = 1; break;
11266                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11267                         case NTOFD:     s = ">&"; dftfd = 1; break;
11268                         case NFROM:     s = "<";  dftfd = 0; break;
11269                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11270                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11271                         default:        s = "*error*"; dftfd = 0; break;
11272                 }
11273                 if (np->nfile.fd != dftfd)
11274                         fprintf(fp, "%d", np->nfile.fd);
11275                 fputs(s, fp);
11276                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11277                         fprintf(fp, "%d", np->ndup.dupfd);
11278                 } else {
11279                         sharg(np->nfile.fname, fp);
11280                 }
11281                 first = 0;
11282         }
11283 }
11284
11285
11286
11287 static void
11288 sharg(union node *arg, FILE *fp)
11289 {
11290         char *p;
11291         struct nodelist *bqlist;
11292         int subtype;
11293
11294         if (arg->type != NARG) {
11295                 out1fmt("<node type %d>\n", arg->type);
11296                 abort();
11297         }
11298         bqlist = arg->narg.backquote;
11299         for (p = arg->narg.text ; *p ; p++) {
11300                 switch (*p) {
11301                 case CTLESC:
11302                         putc(*++p, fp);
11303                         break;
11304                 case CTLVAR:
11305                         putc('$', fp);
11306                         putc('{', fp);
11307                         subtype = *++p;
11308                         if (subtype == VSLENGTH)
11309                                 putc('#', fp);
11310
11311                         while (*p != '=')
11312                                 putc(*p++, fp);
11313
11314                         if (subtype & VSNUL)
11315                                 putc(':', fp);
11316
11317                         switch (subtype & VSTYPE) {
11318                         case VSNORMAL:
11319                                 putc('}', fp);
11320                                 break;
11321                         case VSMINUS:
11322                                 putc('-', fp);
11323                                 break;
11324                         case VSPLUS:
11325                                 putc('+', fp);
11326                                 break;
11327                         case VSQUESTION:
11328                                 putc('?', fp);
11329                                 break;
11330                         case VSASSIGN:
11331                                 putc('=', fp);
11332                                 break;
11333                         case VSTRIMLEFT:
11334                                 putc('#', fp);
11335                                 break;
11336                         case VSTRIMLEFTMAX:
11337                                 putc('#', fp);
11338                                 putc('#', fp);
11339                                 break;
11340                         case VSTRIMRIGHT:
11341                                 putc('%', fp);
11342                                 break;
11343                         case VSTRIMRIGHTMAX:
11344                                 putc('%', fp);
11345                                 putc('%', fp);
11346                                 break;
11347                         case VSLENGTH:
11348                                 break;
11349                         default:
11350                                 out1fmt("<subtype %d>", subtype);
11351                         }
11352                         break;
11353                 case CTLENDVAR:
11354                      putc('}', fp);
11355                      break;
11356                 case CTLBACKQ:
11357                 case CTLBACKQ|CTLQUOTE:
11358                         putc('$', fp);
11359                         putc('(', fp);
11360                         shtree(bqlist->n, -1, NULL, fp);
11361                         putc(')', fp);
11362                         break;
11363                 default:
11364                         putc(*p, fp);
11365                         break;
11366                 }
11367         }
11368 }
11369
11370
11371 static void
11372 indent(int amount, char *pfx, FILE *fp)
11373 {
11374         int i;
11375
11376         for (i = 0 ; i < amount ; i++) {
11377                 if (pfx && i == amount - 1)
11378                         fputs(pfx, fp);
11379                 putc('\t', fp);
11380         }
11381 }
11382
11383
11384
11385 /*
11386  * Debugging stuff.
11387  */
11388
11389
11390 FILE *tracefile;
11391
11392
11393 void
11394 trputc(int c)
11395 {
11396         if (debug != 1)
11397                 return;
11398         putc(c, tracefile);
11399 }
11400
11401 void
11402 trace(const char *fmt, ...)
11403 {
11404         va_list va;
11405
11406         if (debug != 1)
11407                 return;
11408         va_start(va, fmt);
11409         (void) vfprintf(tracefile, fmt, va);
11410         va_end(va);
11411 }
11412
11413 void
11414 tracev(const char *fmt, va_list va)
11415 {
11416         if (debug != 1)
11417                 return;
11418         (void) vfprintf(tracefile, fmt, va);
11419 }
11420
11421
11422 void
11423 trputs(const char *s)
11424 {
11425         if (debug != 1)
11426                 return;
11427         fputs(s, tracefile);
11428 }
11429
11430
11431 static void
11432 trstring(char *s)
11433 {
11434         char *p;
11435         char c;
11436
11437         if (debug != 1)
11438                 return;
11439         putc('"', tracefile);
11440         for (p = s ; *p ; p++) {
11441                 switch (*p) {
11442                 case '\n':  c = 'n';  goto backslash;
11443                 case '\t':  c = 't';  goto backslash;
11444                 case '\r':  c = 'r';  goto backslash;
11445                 case '"':  c = '"';  goto backslash;
11446                 case '\\':  c = '\\';  goto backslash;
11447                 case CTLESC:  c = 'e';  goto backslash;
11448                 case CTLVAR:  c = 'v';  goto backslash;
11449                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11450                 case CTLBACKQ:  c = 'q';  goto backslash;
11451                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11452 backslash:        putc('\\', tracefile);
11453                         putc(c, tracefile);
11454                         break;
11455                 default:
11456                         if (*p >= ' ' && *p <= '~')
11457                                 putc(*p, tracefile);
11458                         else {
11459                                 putc('\\', tracefile);
11460                                 putc(*p >> 6 & 03, tracefile);
11461                                 putc(*p >> 3 & 07, tracefile);
11462                                 putc(*p & 07, tracefile);
11463                         }
11464                         break;
11465                 }
11466         }
11467         putc('"', tracefile);
11468 }
11469
11470
11471 void
11472 trargs(char **ap)
11473 {
11474         if (debug != 1)
11475                 return;
11476         while (*ap) {
11477                 trstring(*ap++);
11478                 if (*ap)
11479                         putc(' ', tracefile);
11480                 else
11481                         putc('\n', tracefile);
11482         }
11483 }
11484
11485
11486 void
11487 opentrace(void)
11488 {
11489         char s[100];
11490 #ifdef O_APPEND
11491         int flags;
11492 #endif
11493
11494         if (debug != 1) {
11495                 if (tracefile)
11496                         fflush(tracefile);
11497                 /* leave open because libedit might be using it */
11498                 return;
11499         }
11500         scopy("./trace", s);
11501         if (tracefile) {
11502                 if (!freopen(s, "a", tracefile)) {
11503                         fprintf(stderr, "Can't re-open %s\n", s);
11504                         debug = 0;
11505                         return;
11506                 }
11507         } else {
11508                 if ((tracefile = fopen(s, "a")) == NULL) {
11509                         fprintf(stderr, "Can't open %s\n", s);
11510                         debug = 0;
11511                         return;
11512                 }
11513         }
11514 #ifdef O_APPEND
11515         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11516                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11517 #endif
11518         setlinebuf(tracefile);
11519         fputs("\nTracing started.\n", tracefile);
11520 }
11521 #endif /* DEBUG */
11522
11523
11524 /*      $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $       */
11525
11526 /*
11527  * Sigmode records the current value of the signal handlers for the various
11528  * modes.  A value of zero means that the current handler is not known.
11529  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11530  */
11531
11532 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
11533 #define S_CATCH 2               /* signal is caught */
11534 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
11535 #define S_HARD_IGN 4            /* signal is ignored permenantly */
11536 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
11537
11538
11539
11540 /*
11541  * The trap builtin.
11542  */
11543
11544 int
11545 trapcmd(int argc, char **argv)
11546 {
11547         char *action;
11548         char **ap;
11549         int signo;
11550
11551         nextopt(nullstr);
11552         ap = argptr;
11553         if (!*ap) {
11554                 for (signo = 0 ; signo < NSIG ; signo++) {
11555                         if (trap[signo] != NULL) {
11556                                 const char *sn;
11557
11558                                 sn = u_signal_names(0, &signo, 0);
11559                                 if (sn == NULL)
11560                                         sn = "???";
11561                                 out1fmt("trap -- %s %s\n",
11562                                         single_quote(trap[signo]), sn);
11563                         }
11564                 }
11565                 return 0;
11566         }
11567         if (!ap[1])
11568                 action = NULL;
11569         else
11570                 action = *ap++;
11571         while (*ap) {
11572                 if ((signo = decode_signal(*ap, 0)) < 0)
11573                         error("%s: bad trap", *ap);
11574                 INTOFF;
11575                 if (action) {
11576                         if (action[0] == '-' && action[1] == '\0')
11577                                 action = NULL;
11578                         else
11579                                 action = savestr(action);
11580                 }
11581                 if (trap[signo])
11582                         ckfree(trap[signo]);
11583                 trap[signo] = action;
11584                 if (signo != 0)
11585                         setsignal(signo);
11586                 INTON;
11587                 ap++;
11588         }
11589         return 0;
11590 }
11591
11592
11593 /*
11594  * Clear traps on a fork.
11595  */
11596
11597 void
11598 clear_traps(void)
11599 {
11600         char **tp;
11601
11602         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11603                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
11604                         INTOFF;
11605                         ckfree(*tp);
11606                         *tp = NULL;
11607                         if (tp != &trap[0])
11608                                 setsignal(tp - trap);
11609                         INTON;
11610                 }
11611         }
11612 }
11613
11614
11615 /*
11616  * Set the signal handler for the specified signal.  The routine figures
11617  * out what it should be set to.
11618  */
11619
11620 void
11621 setsignal(int signo)
11622 {
11623         int action;
11624         char *t, tsig;
11625         struct sigaction act;
11626
11627         if ((t = trap[signo]) == NULL)
11628                 action = S_DFL;
11629         else if (*t != '\0')
11630                 action = S_CATCH;
11631         else
11632                 action = S_IGN;
11633         if (rootshell && action == S_DFL) {
11634                 switch (signo) {
11635                 case SIGINT:
11636                         if (iflag || minusc || sflag == 0)
11637                                 action = S_CATCH;
11638                         break;
11639                 case SIGQUIT:
11640 #ifdef DEBUG
11641                         if (debug)
11642                                 break;
11643 #endif
11644                         /* FALLTHROUGH */
11645                 case SIGTERM:
11646                         if (iflag)
11647                                 action = S_IGN;
11648                         break;
11649 #if JOBS
11650                 case SIGTSTP:
11651                 case SIGTTOU:
11652                         if (mflag)
11653                                 action = S_IGN;
11654                         break;
11655 #endif
11656                 }
11657         }
11658
11659         t = &sigmode[signo - 1];
11660         tsig = *t;
11661         if (tsig == 0) {
11662                 /*
11663                  * current setting unknown
11664                  */
11665                 if (sigaction(signo, 0, &act) == -1) {
11666                         /*
11667                          * Pretend it worked; maybe we should give a warning
11668                          * here, but other shells don't. We don't alter
11669                          * sigmode, so that we retry every time.
11670                          */
11671                         return;
11672                 }
11673                 if (act.sa_handler == SIG_IGN) {
11674                         if (mflag && (signo == SIGTSTP ||
11675                              signo == SIGTTIN || signo == SIGTTOU)) {
11676                                 tsig = S_IGN;   /* don't hard ignore these */
11677                         } else
11678                                 tsig = S_HARD_IGN;
11679                 } else {
11680                         tsig = S_RESET; /* force to be set */
11681                 }
11682         }
11683         if (tsig == S_HARD_IGN || tsig == action)
11684                 return;
11685         switch (action) {
11686         case S_CATCH:
11687                 act.sa_handler = onsig;
11688                 break;
11689         case S_IGN:
11690                 act.sa_handler = SIG_IGN;
11691                 break;
11692         default:
11693                 act.sa_handler = SIG_DFL;
11694         }
11695         *t = action;
11696         act.sa_flags = 0;
11697         sigfillset(&act.sa_mask);
11698         sigaction(signo, &act, 0);
11699 }
11700
11701 /*
11702  * Ignore a signal.
11703  */
11704
11705 void
11706 ignoresig(int signo)
11707 {
11708         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11709                 signal(signo, SIG_IGN);
11710         }
11711         sigmode[signo - 1] = S_HARD_IGN;
11712 }
11713
11714
11715 /*
11716  * Signal handler.
11717  */
11718
11719 void
11720 onsig(int signo)
11721 {
11722         gotsig[signo - 1] = 1;
11723         pendingsigs = signo;
11724
11725         if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11726                 if (!suppressint)
11727                         onint();
11728                 intpending = 1;
11729         }
11730 }
11731
11732
11733 /*
11734  * Called to execute a trap.  Perhaps we should avoid entering new trap
11735  * handlers while we are executing a trap handler.
11736  */
11737
11738 void
11739 dotrap(void)
11740 {
11741         char *p;
11742         char *q;
11743         int savestatus;
11744
11745         savestatus = exitstatus;
11746         q = gotsig;
11747         while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11748                 *p = 0;
11749                 p = trap[p - q + 1];
11750                 if (!p)
11751                         continue;
11752                 evalstring(p);
11753                 exitstatus = savestatus;
11754         }
11755 }
11756
11757
11758 /*
11759  * Controls whether the shell is interactive or not.
11760  */
11761
11762 void
11763 setinteractive(int on)
11764 {
11765         static int is_interactive;
11766
11767         if (++on == is_interactive)
11768                 return;
11769         is_interactive = on;
11770         setsignal(SIGINT);
11771         setsignal(SIGQUIT);
11772         setsignal(SIGTERM);
11773 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11774                 if(is_interactive > 1) {
11775                         /* Looks like they want an interactive shell */
11776                         static int do_banner;
11777
11778                                 if(!do_banner) {
11779                                         out1fmt(
11780                         "\n\n" BB_BANNER " Built-in shell (ash)\n"
11781                         "Enter 'help' for a list of built-in commands.\n\n");
11782                                         do_banner++;
11783                                 }
11784                 }
11785 #endif
11786 }
11787
11788
11789 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11790 /*** List the available builtins ***/
11791
11792 static int helpcmd(int argc, char **argv)
11793 {
11794         int col, i;
11795
11796         out1fmt("\nBuilt-in commands:\n-------------------\n");
11797         for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11798                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11799                                           builtincmd[i].name + 1);
11800                 if (col > 60) {
11801                         out1fmt("\n");
11802                         col = 0;
11803                 }
11804         }
11805 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11806         {
11807                 extern const struct BB_applet applets[];
11808                 extern const size_t NUM_APPLETS;
11809
11810                 for (i = 0; i < NUM_APPLETS; i++) {
11811
11812                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11813                         if (col > 60) {
11814                                 out1fmt("\n");
11815                                 col = 0;
11816                         }
11817                 }
11818         }
11819 #endif
11820         out1fmt("\n\n");
11821         return EXIT_SUCCESS;
11822 }
11823 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11824
11825 /*
11826  * Called to exit the shell.
11827  */
11828
11829 void
11830 exitshell(void)
11831 {
11832         struct jmploc loc;
11833         char *p;
11834         int status;
11835
11836         status = exitstatus;
11837         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11838         if (setjmp(loc.loc)) {
11839                 goto out;
11840         }
11841         handler = &loc;
11842         if ((p = trap[0]) != NULL && *p != '\0') {
11843                 trap[0] = NULL;
11844                 evalstring(p);
11845         }
11846         flushall();
11847 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11848         if (iflag && rootshell) {
11849                 const char *hp = lookupvar("HISTFILE");
11850
11851                 if(hp != NULL )
11852                         save_history ( hp );
11853         }
11854 #endif
11855 out:
11856         _exit(status);
11857         /* NOTREACHED */
11858 }
11859
11860 static int decode_signal(const char *string, int minsig)
11861 {
11862         int signo;
11863         const char *name = u_signal_names(string, &signo, minsig);
11864
11865         return name ? signo : -1;
11866 }
11867
11868 /*      $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $     */
11869
11870 static struct var *vartab[VTABSIZE];
11871
11872 static int vpcmp(const void *, const void *);
11873 static struct var **findvar(struct var **, const char *);
11874
11875 /*
11876  * Initialize the varable symbol tables and import the environment
11877  */
11878
11879
11880 #ifdef CONFIG_ASH_GETOPTS
11881 /*
11882  * Safe version of setvar, returns 1 on success 0 on failure.
11883  */
11884
11885 int
11886 setvarsafe(const char *name, const char *val, int flags)
11887 {
11888         int err;
11889         volatile int saveint;
11890         struct jmploc *volatile savehandler = handler;
11891         struct jmploc jmploc;
11892
11893         SAVEINT(saveint);
11894         if (setjmp(jmploc.loc))
11895                 err = 1;
11896         else {
11897                 handler = &jmploc;
11898                 setvar(name, val, flags);
11899                 err = 0;
11900         }
11901         handler = savehandler;
11902         RESTOREINT(saveint);
11903         return err;
11904 }
11905 #endif
11906
11907 /*
11908  * Set the value of a variable.  The flags argument is ored with the
11909  * flags of the variable.  If val is NULL, the variable is unset.
11910  */
11911
11912 static void
11913 setvar(const char *name, const char *val, int flags)
11914 {
11915         char *p, *q;
11916         size_t namelen;
11917         char *nameeq;
11918         size_t vallen;
11919
11920         q = endofname(name);
11921         p = strchrnul(q, '=');
11922         namelen = p - name;
11923         if (!namelen || p != q)
11924                 error("%.*s: bad variable name", namelen, name);
11925         vallen = 0;
11926         if (val == NULL) {
11927                 flags |= VUNSET;
11928         } else {
11929                 vallen = strlen(val);
11930         }
11931         INTOFF;
11932         p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11933         *p++ = '\0';
11934         if (vallen) {
11935                 p[-1] = '=';
11936                 p = mempcpy(p, val, vallen);
11937         }
11938         *p = '\0';
11939         setvareq(nameeq, flags | VNOSAVE);
11940         INTON;
11941 }
11942
11943
11944 /*
11945  * Same as setvar except that the variable and value are passed in
11946  * the first argument as name=value.  Since the first argument will
11947  * be actually stored in the table, it should not be a string that
11948  * will go away.
11949  * Called with interrupts off.
11950  */
11951
11952 void
11953 setvareq(char *s, int flags)
11954 {
11955         struct var *vp, **vpp;
11956
11957         vpp = hashvar(s);
11958         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11959         vp = *findvar(vpp, s);
11960         if (vp) {
11961                 if (vp->flags & VREADONLY) {
11962                         if (flags & VNOSAVE)
11963                                 free(s);
11964                         error("%.*s: is read only", strchrnul(s, '=') - s, s);
11965                 }
11966
11967                 if (flags & VNOSET)
11968                         return;
11969
11970                 if (vp->func && (flags & VNOFUNC) == 0)
11971                         (*vp->func)(strchrnul(s, '=') + 1);
11972
11973                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11974                         ckfree(vp->text);
11975
11976                 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11977         } else {
11978                 if (flags & VNOSET)
11979                         return;
11980                 /* not found */
11981                 vp = ckmalloc(sizeof (*vp));
11982                 vp->next = *vpp;
11983                 vp->func = NULL;
11984                 *vpp = vp;
11985         }
11986         if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11987                 s = savestr(s);
11988         vp->text = s;
11989         vp->flags = flags;
11990 }
11991
11992
11993 /*
11994  * Process a linked list of variable assignments.
11995  */
11996
11997 static void
11998 listsetvar(struct strlist *list_set_var, int flags)
11999 {
12000         struct strlist *lp = list_set_var;
12001
12002         if (!lp)
12003                 return;
12004         INTOFF;
12005         do {
12006                 setvareq(lp->text, flags);
12007         } while ((lp = lp->next));
12008         INTON;
12009 }
12010
12011
12012 /*
12013  * Find the value of a variable.  Returns NULL if not set.
12014  */
12015
12016 static char *
12017 lookupvar(const char *name)
12018 {
12019         struct var *v;
12020
12021         if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12022                 return strchrnul(v->text, '=') + 1;
12023         }
12024         return NULL;
12025 }
12026
12027
12028 /*
12029  * Search the environment of a builtin command.
12030  */
12031
12032 static char *
12033 bltinlookup(const char *name)
12034 {
12035         struct strlist *sp;
12036
12037         for (sp = cmdenviron ; sp ; sp = sp->next) {
12038                 if (varequal(sp->text, name))
12039                         return strchrnul(sp->text, '=') + 1;
12040         }
12041         return lookupvar(name);
12042 }
12043
12044
12045 /*
12046  * Generate a list of variables satisfying the given conditions.
12047  */
12048
12049 static char **
12050 listvars(int on, int off, char ***end)
12051 {
12052         struct var **vpp;
12053         struct var *vp;
12054         char **ep;
12055         int mask;
12056
12057         STARTSTACKSTR(ep);
12058         vpp = vartab;
12059         mask = on | off;
12060         do {
12061                 for (vp = *vpp ; vp ; vp = vp->next)
12062                         if ((vp->flags & mask) == on) {
12063                                 if (ep == stackstrend())
12064                                         ep = growstackstr();
12065                                 *ep++ = (char *) vp->text;
12066                         }
12067         } while (++vpp < vartab + VTABSIZE);
12068         if (ep == stackstrend())
12069                 ep = growstackstr();
12070         if (end)
12071                 *end = ep;
12072         *ep++ = NULL;
12073         return grabstackstr(ep);
12074 }
12075
12076
12077 /*
12078  * POSIX requires that 'set' (but not export or readonly) output the
12079  * variables in lexicographic order - by the locale's collating order (sigh).
12080  * Maybe we could keep them in an ordered balanced binary tree
12081  * instead of hashed lists.
12082  * For now just roll 'em through qsort for printing...
12083  */
12084
12085 static int
12086 showvars(const char *sep_prefix, int on, int off)
12087 {
12088         const char *sep;
12089         char **ep, **epend;
12090
12091         ep = listvars(on, off, &epend);
12092         qsort(ep, epend - ep, sizeof(char *), vpcmp);
12093
12094         sep = *sep_prefix ? spcstr : sep_prefix;
12095
12096         for (; ep < epend; ep++) {
12097                 const char *p;
12098                 const char *q;
12099
12100                 p = strchrnul(*ep, '=');
12101                 q = nullstr;
12102                 if (*p)
12103                         q = single_quote(++p);
12104
12105                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12106         }
12107
12108         return 0;
12109 }
12110
12111
12112
12113 /*
12114  * The export and readonly commands.
12115  */
12116
12117 static int
12118 exportcmd(int argc, char **argv)
12119 {
12120         struct var *vp;
12121         char *name;
12122         const char *p;
12123         char **aptr;
12124         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12125         int notp;
12126
12127         notp = nextopt("p") - 'p';
12128         if (notp && ((name = *(aptr = argptr)))) {
12129                 do {
12130                         if ((p = strchr(name, '=')) != NULL) {
12131                                 p++;
12132                         } else {
12133                                 if ((vp = *findvar(hashvar(name), name))) {
12134                                         vp->flags |= flag;
12135                                         continue;
12136                                 }
12137                         }
12138                         setvar(name, p, flag);
12139                 } while ((name = *++aptr) != NULL);
12140         } else {
12141                 showvars(argv[0], flag, 0);
12142         }
12143         return 0;
12144 }
12145
12146
12147 /*
12148  * Make a variable a local variable.  When a variable is made local, it's
12149  * value and flags are saved in a localvar structure.  The saved values
12150  * will be restored when the shell function returns.  We handle the name
12151  * "-" as a special case.
12152  */
12153
12154 static inline void
12155 mklocal(char *name)
12156 {
12157         struct localvar *lvp;
12158         struct var **vpp;
12159         struct var *vp;
12160
12161         INTOFF;
12162         lvp = ckmalloc(sizeof (struct localvar));
12163         if (name[0] == '-' && name[1] == '\0') {
12164                 char *p;
12165                 p = ckmalloc(sizeof(optlist));
12166                 lvp->text = memcpy(p, optlist, sizeof(optlist));
12167                 vp = NULL;
12168         } else {
12169                 char *eq;
12170
12171                 vpp = hashvar(name);
12172                 vp = *findvar(vpp, name);
12173                 eq = strchr(name, '=');
12174                 if (vp == NULL) {
12175                         if (eq)
12176                                 setvareq(name, VSTRFIXED);
12177                         else
12178                                 setvar(name, NULL, VSTRFIXED);
12179                         vp = *vpp;      /* the new variable */
12180                         lvp->flags = VUNSET;
12181                 } else {
12182                         lvp->text = vp->text;
12183                         lvp->flags = vp->flags;
12184                         vp->flags |= VSTRFIXED|VTEXTFIXED;
12185                         if (eq)
12186                                 setvareq(name, 0);
12187                 }
12188         }
12189         lvp->vp = vp;
12190         lvp->next = localvars;
12191         localvars = lvp;
12192         INTON;
12193 }
12194
12195 /*
12196  * The "local" command.
12197  */
12198
12199 static int
12200 localcmd(int argc, char **argv)
12201 {
12202         char *name;
12203
12204         argv = argptr;
12205         while ((name = *argv++) != NULL) {
12206                 mklocal(name);
12207         }
12208         return 0;
12209 }
12210
12211
12212 /*
12213  * Called after a function returns.
12214  * Interrupts must be off.
12215  */
12216
12217 static void
12218 poplocalvars(void)
12219 {
12220         struct localvar *lvp;
12221         struct var *vp;
12222
12223         while ((lvp = localvars) != NULL) {
12224                 localvars = lvp->next;
12225                 vp = lvp->vp;
12226                 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12227                 if (vp == NULL) {       /* $- saved */
12228                         memcpy(optlist, lvp->text, sizeof(optlist));
12229                         ckfree(lvp->text);
12230                         optschanged();
12231                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12232                         unsetvar(vp->text);
12233                 } else {
12234                         if (vp->func)
12235                                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12236                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12237                                 ckfree(vp->text);
12238                         vp->flags = lvp->flags;
12239                         vp->text = lvp->text;
12240                 }
12241                 ckfree(lvp);
12242         }
12243 }
12244
12245
12246 /*
12247  * The unset builtin command.  We unset the function before we unset the
12248  * variable to allow a function to be unset when there is a readonly variable
12249  * with the same name.
12250  */
12251
12252 int
12253 unsetcmd(int argc, char **argv)
12254 {
12255         char **ap;
12256         int i;
12257         int flag = 0;
12258         int ret = 0;
12259
12260         while ((i = nextopt("vf")) != '\0') {
12261                 flag = i;
12262         }
12263
12264         for (ap = argptr; *ap ; ap++) {
12265                 if (flag != 'f') {
12266                         i = unsetvar(*ap);
12267                         ret |= i;
12268                         if (!(i & 2))
12269                                 continue;
12270                 }
12271                 if (flag != 'v')
12272                         unsetfunc(*ap);
12273         }
12274         return ret & 1;
12275 }
12276
12277
12278 /*
12279  * Unset the specified variable.
12280  */
12281
12282 int
12283 unsetvar(const char *s)
12284 {
12285         struct var **vpp;
12286         struct var *vp;
12287         int retval;
12288
12289         vpp = findvar(hashvar(s), s);
12290         vp = *vpp;
12291         retval = 2;
12292         if (vp) {
12293                 int flags = vp->flags;
12294
12295                 retval = 1;
12296                 if (flags & VREADONLY)
12297                         goto out;
12298                 if (flags & VUNSET)
12299                         goto ok;
12300                 if ((flags & VSTRFIXED) == 0) {
12301                         INTOFF;
12302                         if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12303                                 ckfree(vp->text);
12304                         *vpp = vp->next;
12305                         ckfree(vp);
12306                         INTON;
12307                 } else {
12308                         setvar(s, 0, 0);
12309                         vp->flags &= ~VEXPORT;
12310                 }
12311 ok:
12312                 retval = 0;
12313         }
12314
12315 out:
12316         return retval;
12317 }
12318
12319
12320
12321 /*
12322  * Find the appropriate entry in the hash table from the name.
12323  */
12324
12325 static struct var **
12326 hashvar(const char *p)
12327 {
12328         unsigned int hashval;
12329
12330         hashval = ((unsigned char) *p) << 4;
12331         while (*p && *p != '=')
12332                 hashval += (unsigned char) *p++;
12333         return &vartab[hashval % VTABSIZE];
12334 }
12335
12336
12337
12338 /*
12339  * Compares two strings up to the first = or '\0'.  The first
12340  * string must be terminated by '='; the second may be terminated by
12341  * either '=' or '\0'.
12342  */
12343
12344 int
12345 varcmp(const char *p, const char *q)
12346 {
12347         int c, d;
12348
12349         while ((c = *p) == (d = *q)) {
12350                 if (!c || c == '=')
12351                         goto out;
12352                 p++;
12353                 q++;
12354         }
12355         if (c == '=')
12356                 c = 0;
12357         if (d == '=')
12358                 d = 0;
12359 out:
12360         return c - d;
12361 }
12362
12363 static int
12364 vpcmp(const void *a, const void *b)
12365 {
12366         return varcmp(*(const char **)a, *(const char **)b);
12367 }
12368
12369 static struct var **
12370 findvar(struct var **vpp, const char *name)
12371 {
12372         for (; *vpp; vpp = &(*vpp)->next) {
12373                 if (varequal((*vpp)->text, name)) {
12374                         break;
12375                 }
12376         }
12377         return vpp;
12378 }
12379 /*      $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $      */
12380
12381 #include <sys/times.h>
12382
12383 static const unsigned char timescmd_str[] = {
12384         ' ',  offsetof(struct tms, tms_utime),
12385         '\n', offsetof(struct tms, tms_stime),
12386         ' ',  offsetof(struct tms, tms_cutime),
12387         '\n', offsetof(struct tms, tms_cstime),
12388         0
12389 };
12390
12391 static int timescmd(int ac, char **av)
12392 {
12393         long int clk_tck, s, t;
12394         const unsigned char *p;
12395         struct tms buf;
12396
12397         clk_tck = sysconf(_SC_CLK_TCK);
12398         times(&buf);
12399
12400         p = timescmd_str;
12401         do {
12402                 t = *(clock_t *)(((char *) &buf) + p[1]);
12403                 s = t / clk_tck;
12404                 out1fmt("%ldm%ld.%.3lds%c",
12405                         s/60, s%60,
12406                         ((t - s * clk_tck) * 1000) / clk_tck,
12407                         p[0]);
12408         } while (*(p += 2));
12409
12410         return 0;
12411 }
12412
12413 #ifdef CONFIG_ASH_MATH_SUPPORT
12414 static int
12415 dash_arith(const char *s)
12416 {
12417         long result;
12418         int errcode = 0;
12419
12420         INTOFF;
12421         result = arith(s, &errcode);
12422         if (errcode < 0) {
12423                 if (errcode == -3)
12424                         error("exponent less than 0");
12425                 else if (errcode == -2)
12426                         error("divide by zero");
12427                 else if (errcode == -5)
12428                         error("expression recursion loop detected");
12429                 else
12430                         synerror(s);
12431         }
12432         INTON;
12433
12434         return (result);
12435 }
12436
12437
12438 /*
12439  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12440  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12441  *
12442  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12443  */
12444
12445 static int
12446 letcmd(int argc, char **argv)
12447 {
12448         char **ap;
12449         long i;
12450
12451         ap = argv + 1;
12452         if(!*ap)
12453                 error("expression expected");
12454         for (ap = argv + 1; *ap; ap++) {
12455                 i = dash_arith(*ap);
12456         }
12457
12458         return (!i);
12459 }
12460 #endif /* CONFIG_ASH_MATH_SUPPORT */
12461
12462 /*      $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $  */
12463
12464 /*
12465  * Miscelaneous builtins.
12466  */
12467
12468 #undef rflag
12469
12470 #ifdef __GLIBC__
12471 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12472 typedef enum __rlimit_resource rlim_t;
12473 #endif
12474 #endif
12475
12476
12477 /*
12478  * The read builtin.  The -e option causes backslashes to escape the
12479  * following character.
12480  *
12481  * This uses unbuffered input, which may be avoidable in some cases.
12482  */
12483
12484 static int
12485 readcmd(int argc, char **argv)
12486 {
12487         char **ap;
12488         int backslash;
12489         char c;
12490         int rflag;
12491         char *prompt;
12492         const char *ifs;
12493         char *p;
12494         int startword;
12495         int status;
12496         int i;
12497
12498         rflag = 0;
12499         prompt = NULL;
12500         while ((i = nextopt("p:r")) != '\0') {
12501                 if (i == 'p')
12502                         prompt = optionarg;
12503                 else
12504                         rflag = 1;
12505         }
12506         if (prompt && isatty(0)) {
12507                 out2str(prompt);
12508         }
12509         if (*(ap = argptr) == NULL)
12510                 error("arg count");
12511         if ((ifs = bltinlookup("IFS")) == NULL)
12512                 ifs = defifs;
12513         status = 0;
12514         startword = 1;
12515         backslash = 0;
12516         STARTSTACKSTR(p);
12517         for (;;) {
12518                 if (read(0, &c, 1) != 1) {
12519                         status = 1;
12520                         break;
12521                 }
12522                 if (c == '\0')
12523                         continue;
12524                 if (backslash) {
12525                         backslash = 0;
12526                         if (c != '\n')
12527                                 goto put;
12528                         continue;
12529                 }
12530                 if (!rflag && c == '\\') {
12531                         backslash++;
12532                         continue;
12533                 }
12534                 if (c == '\n')
12535                         break;
12536                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12537                         continue;
12538                 }
12539                 startword = 0;
12540                 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12541                         STACKSTRNUL(p);
12542                         setvar(*ap, stackblock(), 0);
12543                         ap++;
12544                         startword = 1;
12545                         STARTSTACKSTR(p);
12546                 } else {
12547 put:
12548                         STPUTC(c, p);
12549                 }
12550         }
12551         STACKSTRNUL(p);
12552         /* Remove trailing blanks */
12553         while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12554                 *p = '\0';
12555         setvar(*ap, stackblock(), 0);
12556         while (*++ap != NULL)
12557                 setvar(*ap, nullstr, 0);
12558         return status;
12559 }
12560
12561
12562 static int umaskcmd(int argc, char **argv)
12563 {
12564         static const char permuser[3] = "ugo";
12565         static const char permmode[3] = "rwx";
12566         static const short int permmask[] = {
12567                 S_IRUSR, S_IWUSR, S_IXUSR,
12568                 S_IRGRP, S_IWGRP, S_IXGRP,
12569                 S_IROTH, S_IWOTH, S_IXOTH
12570         };
12571
12572         char *ap;
12573         mode_t mask;
12574         int i;
12575         int symbolic_mode = 0;
12576
12577         while (nextopt("S") != '\0') {
12578                 symbolic_mode = 1;
12579         }
12580
12581         INTOFF;
12582         mask = umask(0);
12583         umask(mask);
12584         INTON;
12585
12586         if ((ap = *argptr) == NULL) {
12587                 if (symbolic_mode) {
12588                         char buf[18];
12589                         char *p = buf;
12590
12591                         for (i = 0; i < 3; i++) {
12592                                 int j;
12593
12594                                 *p++ = permuser[i];
12595                                 *p++ = '=';
12596                                 for (j = 0; j < 3; j++) {
12597                                         if ((mask & permmask[3 * i + j]) == 0) {
12598                                                 *p++ = permmode[j];
12599                                         }
12600                                 }
12601                                 *p++ = ',';
12602                         }
12603                         *--p = 0;
12604                         puts(buf);
12605                 } else {
12606                         out1fmt("%.4o\n", mask);
12607                 }
12608         } else {
12609                 if (is_digit((unsigned char) *ap)) {
12610                         mask = 0;
12611                         do {
12612                                 if (*ap >= '8' || *ap < '0')
12613                                         error(illnum, argv[1]);
12614                                 mask = (mask << 3) + (*ap - '0');
12615                         } while (*++ap != '\0');
12616                         umask(mask);
12617                 } else {
12618                         mask = ~mask & 0777;
12619                         if (!bb_parse_mode(ap, &mask)) {
12620                                 error("Illegal mode: %s", ap);
12621                         }
12622                         umask(~mask & 0777);
12623                 }
12624         }
12625         return 0;
12626 }
12627
12628 /*
12629  * ulimit builtin
12630  *
12631  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12632  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12633  * ash by J.T. Conklin.
12634  *
12635  * Public domain.
12636  */
12637
12638 struct limits {
12639         const char *name;
12640         int     cmd;
12641         int     factor; /* multiply by to get rlim_{cur,max} values */
12642         char    option;
12643 };
12644
12645 static const struct limits limits[] = {
12646 #ifdef RLIMIT_CPU
12647         { "time(seconds)",              RLIMIT_CPU,        1, 't' },
12648 #endif
12649 #ifdef RLIMIT_FSIZE
12650         { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
12651 #endif
12652 #ifdef RLIMIT_DATA
12653         { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
12654 #endif
12655 #ifdef RLIMIT_STACK
12656         { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
12657 #endif
12658 #ifdef  RLIMIT_CORE
12659         { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
12660 #endif
12661 #ifdef RLIMIT_RSS
12662         { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
12663 #endif
12664 #ifdef RLIMIT_MEMLOCK
12665         { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
12666 #endif
12667 #ifdef RLIMIT_NPROC
12668         { "process",                    RLIMIT_NPROC,      1, 'p' },
12669 #endif
12670 #ifdef RLIMIT_NOFILE
12671         { "nofiles",                    RLIMIT_NOFILE,     1, 'n' },
12672 #endif
12673 #ifdef RLIMIT_AS
12674         { "vmemory(kbytes)",            RLIMIT_AS,      1024, 'v' },
12675 #endif
12676 #ifdef RLIMIT_LOCKS
12677         { "locks",                      RLIMIT_LOCKS,      1, 'w' },
12678 #endif
12679         { (char *) 0,                   0,                 0,  '\0' }
12680 };
12681
12682 enum limtype { SOFT = 0x1, HARD = 0x2 };
12683
12684 static void printlim(enum limtype how, const struct rlimit *limit,
12685                         const struct limits *l)
12686 {
12687         rlim_t val;
12688
12689         val = limit->rlim_max;
12690         if (how & SOFT)
12691                 val = limit->rlim_cur;
12692
12693         if (val == RLIM_INFINITY)
12694                 out1fmt("unlimited\n");
12695         else {
12696                 val /= l->factor;
12697                 out1fmt("%lld\n", (long long) val);
12698         }
12699 }
12700
12701 int
12702 ulimitcmd(int argc, char **argv)
12703 {
12704         int     c;
12705         rlim_t val = 0;
12706         enum limtype how = SOFT | HARD;
12707         const struct limits     *l;
12708         int             set, all = 0;
12709         int             optc, what;
12710         struct rlimit   limit;
12711
12712         what = 'f';
12713         while ((optc = nextopt("HSatfdsmcnplvw")) != '\0')
12714                 switch (optc) {
12715                 case 'H':
12716                         how = HARD;
12717                         break;
12718                 case 'S':
12719                         how = SOFT;
12720                         break;
12721                 case 'a':
12722                         all = 1;
12723                         break;
12724                 default:
12725                         what = optc;
12726                 }
12727
12728         for (l = limits; l->option != what; l++)
12729                 ;
12730
12731         set = *argptr ? 1 : 0;
12732         if (set) {
12733                 char *p = *argptr;
12734
12735                 if (all || argptr[1])
12736                         error("too many arguments");
12737                 if (strncmp(p, "unlimited\n", 9) == 0)
12738                         val = RLIM_INFINITY;
12739                 else {
12740                         val = (rlim_t) 0;
12741
12742                         while ((c = *p++) >= '0' && c <= '9')
12743                         {
12744                                 val = (val * 10) + (long)(c - '0');
12745                                 if (val < (rlim_t) 0)
12746                                         break;
12747                         }
12748                         if (c)
12749                                 error("bad number");
12750                         val *= l->factor;
12751                 }
12752         }
12753         if (all) {
12754                 for (l = limits; l->name; l++) {
12755                         getrlimit(l->cmd, &limit);
12756                         out1fmt("%-20s ", l->name);
12757                         printlim(how, &limit, l);
12758                 }
12759                 return 0;
12760         }
12761
12762         getrlimit(l->cmd, &limit);
12763         if (set) {
12764                 if (how & HARD)
12765                         limit.rlim_max = val;
12766                 if (how & SOFT)
12767                         limit.rlim_cur = val;
12768                 if (setrlimit(l->cmd, &limit) < 0)
12769                         error("error setting limit (%m)");
12770         } else {
12771                 printlim(how, &limit, l);
12772         }
12773         return 0;
12774 }
12775
12776
12777 #ifdef CONFIG_ASH_MATH_SUPPORT
12778
12779 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12780
12781    Permission is hereby granted, free of charge, to any person obtaining
12782    a copy of this software and associated documentation files (the
12783    "Software"), to deal in the Software without restriction, including
12784    without limitation the rights to use, copy, modify, merge, publish,
12785    distribute, sublicense, and/or sell copies of the Software, and to
12786    permit persons to whom the Software is furnished to do so, subject to
12787    the following conditions:
12788
12789    The above copyright notice and this permission notice shall be
12790    included in all copies or substantial portions of the Software.
12791
12792    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12793    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12794    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12795    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12796    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12797    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12798    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12799 */
12800
12801 /* This is my infix parser/evaluator. It is optimized for size, intended
12802  * as a replacement for yacc-based parsers. However, it may well be faster
12803  * than a comparable parser writen in yacc. The supported operators are
12804  * listed in #defines below. Parens, order of operations, and error handling
12805  * are supported. This code is threadsafe. The exact expression format should
12806  * be that which POSIX specifies for shells. */
12807
12808 /* The code uses a simple two-stack algorithm. See
12809  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12810  * for a detailed explaination of the infix-to-postfix algorithm on which
12811  * this is based (this code differs in that it applies operators immediately
12812  * to the stack instead of adding them to a queue to end up with an
12813  * expression). */
12814
12815 /* To use the routine, call it with an expression string and error return
12816  * pointer */
12817
12818 /*
12819  * Aug 24, 2001              Manuel Novoa III
12820  *
12821  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12822  *
12823  * 1) In arith_apply():
12824  *    a) Cached values of *numptr and &(numptr[-1]).
12825  *    b) Removed redundant test for zero denominator.
12826  *
12827  * 2) In arith():
12828  *    a) Eliminated redundant code for processing operator tokens by moving
12829  *       to a table-based implementation.  Also folded handling of parens
12830  *       into the table.
12831  *    b) Combined all 3 loops which called arith_apply to reduce generated
12832  *       code size at the cost of speed.
12833  *
12834  * 3) The following expressions were treated as valid by the original code:
12835  *       1()  ,    0!  ,    1 ( *3 )   .
12836  *    These bugs have been fixed by internally enclosing the expression in
12837  *    parens and then checking that all binary ops and right parens are
12838  *    preceded by a valid expression (NUM_TOKEN).
12839  *
12840  * Note: It may be desireable to replace Aaron's test for whitespace with
12841  * ctype's isspace() if it is used by another busybox applet or if additional
12842  * whitespace chars should be considered.  Look below the "#include"s for a
12843  * precompiler test.
12844  */
12845
12846 /*
12847  * Aug 26, 2001              Manuel Novoa III
12848  *
12849  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
12850  *
12851  * Merge in Aaron's comments previously posted to the busybox list,
12852  * modified slightly to take account of my changes to the code.
12853  *
12854  */
12855
12856 /*
12857  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12858  *
12859  * - allow access to variable,
12860  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12861  * - realize assign syntax (VAR=expr, +=, *= etc)
12862  * - realize exponentiation (** operator)
12863  * - realize comma separated - expr, expr
12864  * - realise ++expr --expr expr++ expr--
12865  * - realise expr ? expr : expr (but, second expr calculate always)
12866  * - allow hexdecimal and octal numbers
12867  * - was restored loses XOR operator
12868  * - remove one goto label, added three ;-)
12869  * - protect $((num num)) as true zero expr (Manuel`s error)
12870  * - always use special isspace(), see comment from bash ;-)
12871  */
12872
12873
12874 #define arith_isspace(arithval) \
12875         (arithval == ' ' || arithval == '\n' || arithval == '\t')
12876
12877
12878 typedef unsigned char operator;
12879
12880 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12881  * precedence, and 3 high bits are an ID unique accross operators of that
12882  * precedence. The ID portion is so that multiple operators can have the
12883  * same precedence, ensuring that the leftmost one is evaluated first.
12884  * Consider * and /. */
12885
12886 #define tok_decl(prec,id) (((id)<<5)|(prec))
12887 #define PREC(op) ((op) & 0x1F)
12888
12889 #define TOK_LPAREN tok_decl(0,0)
12890
12891 #define TOK_COMMA tok_decl(1,0)
12892
12893 #define TOK_ASSIGN tok_decl(2,0)
12894 #define TOK_AND_ASSIGN tok_decl(2,1)
12895 #define TOK_OR_ASSIGN tok_decl(2,2)
12896 #define TOK_XOR_ASSIGN tok_decl(2,3)
12897 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12898 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12899 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12900 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12901
12902 #define TOK_MUL_ASSIGN tok_decl(3,0)
12903 #define TOK_DIV_ASSIGN tok_decl(3,1)
12904 #define TOK_REM_ASSIGN tok_decl(3,2)
12905
12906 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12907 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12908
12909 /* conditional is right associativity too */
12910 #define TOK_CONDITIONAL tok_decl(4,0)
12911 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12912
12913 #define TOK_OR tok_decl(5,0)
12914
12915 #define TOK_AND tok_decl(6,0)
12916
12917 #define TOK_BOR tok_decl(7,0)
12918
12919 #define TOK_BXOR tok_decl(8,0)
12920
12921 #define TOK_BAND tok_decl(9,0)
12922
12923 #define TOK_EQ tok_decl(10,0)
12924 #define TOK_NE tok_decl(10,1)
12925
12926 #define TOK_LT tok_decl(11,0)
12927 #define TOK_GT tok_decl(11,1)
12928 #define TOK_GE tok_decl(11,2)
12929 #define TOK_LE tok_decl(11,3)
12930
12931 #define TOK_LSHIFT tok_decl(12,0)
12932 #define TOK_RSHIFT tok_decl(12,1)
12933
12934 #define TOK_ADD tok_decl(13,0)
12935 #define TOK_SUB tok_decl(13,1)
12936
12937 #define TOK_MUL tok_decl(14,0)
12938 #define TOK_DIV tok_decl(14,1)
12939 #define TOK_REM tok_decl(14,2)
12940
12941 /* exponent is right associativity */
12942 #define TOK_EXPONENT tok_decl(15,1)
12943
12944 /* For now unary operators. */
12945 #define UNARYPREC 16
12946 #define TOK_BNOT tok_decl(UNARYPREC,0)
12947 #define TOK_NOT tok_decl(UNARYPREC,1)
12948
12949 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12950 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12951
12952 #define PREC_PRE (UNARYPREC+2)
12953
12954 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12955 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12956
12957 #define PREC_POST (UNARYPREC+3)
12958
12959 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12960 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12961
12962 #define SPEC_PREC (UNARYPREC+4)
12963
12964 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12965 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12966
12967 #define NUMPTR (*numstackptr)
12968
12969 static inline int tok_have_assign(operator op)
12970 {
12971         operator prec = PREC(op);
12972
12973         convert_prec_is_assing(prec);
12974         return (prec == PREC(TOK_ASSIGN) ||
12975                         prec == PREC_PRE || prec == PREC_POST);
12976 }
12977
12978 static inline int is_right_associativity(operator prec)
12979 {
12980     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
12981             prec == PREC(TOK_CONDITIONAL));
12982 }
12983
12984
12985 typedef struct ARITCH_VAR_NUM {
12986         long val;
12987         long contidional_second_val;
12988         char contidional_second_val_initialized;
12989         char *var;      /* if NULL then is regular number,
12990                            else is varable name */
12991 } v_n_t;
12992
12993
12994 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12995         const char *var;
12996         struct CHK_VAR_RECURSIVE_LOOPED *next;
12997 } chk_var_recursive_looped_t;
12998
12999 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13000
13001
13002 static int arith_lookup_val(v_n_t *t)
13003 {
13004     if(t->var) {
13005         const char * p = lookupvar(t->var);
13006
13007         if(p) {
13008             int errcode;
13009
13010             /* recursive try as expression */
13011             chk_var_recursive_looped_t *cur;
13012             chk_var_recursive_looped_t cur_save;
13013
13014             for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13015                 if(strcmp(cur->var, t->var) == 0) {
13016                     /* expression recursion loop detected */
13017                     return -5;
13018                 }
13019             }
13020             /* save current lookuped var name */
13021             cur = prev_chk_var_recursive;
13022             cur_save.var = t->var;
13023             cur_save.next = cur;
13024             prev_chk_var_recursive = &cur_save;
13025
13026             t->val = arith (p, &errcode);
13027             /* restore previous ptr after recursiving */
13028             prev_chk_var_recursive = cur;
13029             return errcode;
13030         } else {
13031             /* allow undefined var as 0 */
13032             t->val = 0;
13033         }
13034     }
13035     return 0;
13036 }
13037
13038 /* "applying" a token means performing it on the top elements on the integer
13039  * stack. For a unary operator it will only change the top element, but a
13040  * binary operator will pop two arguments and push a result */
13041 static inline int
13042 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13043 {
13044         long numptr_val;
13045         v_n_t *numptr_m1;
13046         long rez;
13047         int ret_arith_lookup_val;
13048
13049         if (NUMPTR == numstack) goto err; /* There is no operator that can work
13050                                                                                  without arguments */
13051         numptr_m1 = NUMPTR - 1;
13052
13053         /* check operand is var with noninteger value */
13054         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13055         if(ret_arith_lookup_val)
13056                 return ret_arith_lookup_val;
13057
13058         rez = numptr_m1->val;
13059         if (op == TOK_UMINUS)
13060                 rez *= -1;
13061         else if (op == TOK_NOT)
13062                 rez = !rez;
13063         else if (op == TOK_BNOT)
13064                 rez = ~rez;
13065         else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13066                 rez++;
13067         else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13068                 rez--;
13069         else if (op != TOK_UPLUS) {
13070                 /* Binary operators */
13071
13072             /* check and binary operators need two arguments */
13073             if (numptr_m1 == numstack) goto err;
13074
13075             /* ... and they pop one */
13076             --NUMPTR;
13077             numptr_val = rez;
13078             if (op == TOK_CONDITIONAL) {
13079                 if(! numptr_m1->contidional_second_val_initialized) {
13080                     /* protect $((expr1 ? expr2)) without ": expr" */
13081                     goto err;
13082                 }
13083                 rez = numptr_m1->contidional_second_val;
13084             } else if(numptr_m1->contidional_second_val_initialized) {
13085                     /* protect $((expr1 : expr2)) without "expr ? " */
13086                     goto err;
13087             }
13088             numptr_m1 = NUMPTR - 1;
13089             if(op != TOK_ASSIGN) {
13090                 /* check operand is var with noninteger value for not '=' */
13091                 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13092                 if(ret_arith_lookup_val)
13093                     return ret_arith_lookup_val;
13094             }
13095             if (op == TOK_CONDITIONAL) {
13096                     numptr_m1->contidional_second_val = rez;
13097             }
13098             rez = numptr_m1->val;
13099             if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13100                         rez |= numptr_val;
13101             else if (op == TOK_OR)
13102                         rez = numptr_val || rez;
13103             else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13104                         rez &= numptr_val;
13105             else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13106                         rez ^= numptr_val;
13107             else if (op == TOK_AND)
13108                         rez = rez && numptr_val;
13109             else if (op == TOK_EQ)
13110                         rez = (rez == numptr_val);
13111             else if (op == TOK_NE)
13112                         rez = (rez != numptr_val);
13113             else if (op == TOK_GE)
13114                         rez = (rez >= numptr_val);
13115             else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13116                         rez >>= numptr_val;
13117             else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13118                         rez <<= numptr_val;
13119             else if (op == TOK_GT)
13120                         rez = (rez > numptr_val);
13121             else if (op == TOK_LT)
13122                         rez = (rez < numptr_val);
13123             else if (op == TOK_LE)
13124                         rez = (rez <= numptr_val);
13125             else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13126                         rez *= numptr_val;
13127             else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13128                         rez += numptr_val;
13129             else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13130                         rez -= numptr_val;
13131             else if (op == TOK_ASSIGN || op == TOK_COMMA)
13132                         rez = numptr_val;
13133             else if (op == TOK_CONDITIONAL_SEP) {
13134                         if (numptr_m1 == numstack) {
13135                             /* protect $((expr : expr)) without "expr ? " */
13136                             goto err;
13137                         }
13138                         numptr_m1->contidional_second_val_initialized = op;
13139                         numptr_m1->contidional_second_val = numptr_val;
13140             }
13141             else if (op == TOK_CONDITIONAL) {
13142                         rez = rez ?
13143                               numptr_val : numptr_m1->contidional_second_val;
13144             }
13145             else if(op == TOK_EXPONENT) {
13146                         if(numptr_val < 0)
13147                                 return -3;      /* exponent less than 0 */
13148                         else {
13149                                 long c = 1;
13150
13151                                 if(numptr_val)
13152                                         while(numptr_val--)
13153                                                 c *= rez;
13154                                 rez = c;
13155                         }
13156             }
13157             else if(numptr_val==0)          /* zero divisor check */
13158                         return -2;
13159             else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13160                         rez /= numptr_val;
13161             else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13162                         rez %= numptr_val;
13163         }
13164         if(tok_have_assign(op)) {
13165                 char buf[32];
13166
13167                 if(numptr_m1->var == NULL) {
13168                         /* Hmm, 1=2 ? */
13169                         goto err;
13170                 }
13171                 /* save to shell variable */
13172                 sprintf(buf, "%ld", rez);
13173                 setvar(numptr_m1->var, buf, 0);
13174                 /* after saving, make previous value for v++ or v-- */
13175                 if(op == TOK_POST_INC)
13176                         rez--;
13177                 else if(op == TOK_POST_DEC)
13178                         rez++;
13179         }
13180         numptr_m1->val = rez;
13181         /* protect geting var value, is number now */
13182         numptr_m1->var = NULL;
13183         return 0;
13184 err: return(-1);
13185 }
13186
13187 /* longest must first */
13188 static const char op_tokens[] = {
13189         '<','<','=',0, TOK_LSHIFT_ASSIGN,
13190         '>','>','=',0, TOK_RSHIFT_ASSIGN,
13191         '<','<',    0, TOK_LSHIFT,
13192         '>','>',    0, TOK_RSHIFT,
13193         '|','|',    0, TOK_OR,
13194         '&','&',    0, TOK_AND,
13195         '!','=',    0, TOK_NE,
13196         '<','=',    0, TOK_LE,
13197         '>','=',    0, TOK_GE,
13198         '=','=',    0, TOK_EQ,
13199         '|','=',    0, TOK_OR_ASSIGN,
13200         '&','=',    0, TOK_AND_ASSIGN,
13201         '*','=',    0, TOK_MUL_ASSIGN,
13202         '/','=',    0, TOK_DIV_ASSIGN,
13203         '%','=',    0, TOK_REM_ASSIGN,
13204         '+','=',    0, TOK_PLUS_ASSIGN,
13205         '-','=',    0, TOK_MINUS_ASSIGN,
13206         '-','-',    0, TOK_POST_DEC,
13207         '^','=',    0, TOK_XOR_ASSIGN,
13208         '+','+',    0, TOK_POST_INC,
13209         '*','*',    0, TOK_EXPONENT,
13210         '!',        0, TOK_NOT,
13211         '<',        0, TOK_LT,
13212         '>',        0, TOK_GT,
13213         '=',        0, TOK_ASSIGN,
13214         '|',        0, TOK_BOR,
13215         '&',        0, TOK_BAND,
13216         '*',        0, TOK_MUL,
13217         '/',        0, TOK_DIV,
13218         '%',        0, TOK_REM,
13219         '+',        0, TOK_ADD,
13220         '-',        0, TOK_SUB,
13221         '^',        0, TOK_BXOR,
13222         /* uniq */
13223         '~',        0, TOK_BNOT,
13224         ',',        0, TOK_COMMA,
13225         '?',        0, TOK_CONDITIONAL,
13226         ':',        0, TOK_CONDITIONAL_SEP,
13227         ')',        0, TOK_RPAREN,
13228         '(',        0, TOK_LPAREN,
13229         0
13230 };
13231 /* ptr to ")" */
13232 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13233
13234
13235 extern long arith (const char *expr, int *perrcode)
13236 {
13237     register char arithval; /* Current character under analysis */
13238     operator lasttok, op;
13239     operator prec;
13240
13241     const char *p = endexpression;
13242     int errcode;
13243
13244     size_t datasizes = strlen(expr) + 2;
13245
13246     /* Stack of integers */
13247     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13248      * in any given correct or incorrect expression is left as an excersize to
13249      * the reader. */
13250     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13251             *numstackptr = numstack;
13252     /* Stack of operator tokens */
13253     operator *stack = alloca((datasizes) * sizeof(operator)),
13254             *stackptr = stack;
13255
13256     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
13257     *perrcode = errcode = 0;
13258
13259     while(1) {
13260         if ((arithval = *expr) == 0) {
13261                 if (p == endexpression) {
13262                         /* Null expression. */
13263                         return 0;
13264                 }
13265
13266                 /* This is only reached after all tokens have been extracted from the
13267                  * input stream. If there are still tokens on the operator stack, they
13268                  * are to be applied in order. At the end, there should be a final
13269                  * result on the integer stack */
13270
13271                 if (expr != endexpression + 1) {
13272                         /* If we haven't done so already, */
13273                         /* append a closing right paren */
13274                         expr = endexpression;
13275                         /* and let the loop process it. */
13276                         continue;
13277                 }
13278                 /* At this point, we're done with the expression. */
13279                 if (numstackptr != numstack+1) {
13280                         /* ... but if there isn't, it's bad */
13281                   err:
13282                         return (*perrcode = -1);
13283                 }
13284                 if(numstack->var) {
13285                     /* expression is $((var)) only, lookup now */
13286                     errcode = arith_lookup_val(numstack);
13287                 }
13288         ret:
13289                 *perrcode = errcode;
13290                 return numstack->val;
13291         } else {
13292                 /* Continue processing the expression. */
13293                 if (arith_isspace(arithval)) {
13294                         /* Skip whitespace */
13295                         goto prologue;
13296                 }
13297                 if((p = endofname(expr)) != expr) {
13298                         int var_name_size = (p-expr) + 1;  /* trailing zero */
13299
13300                         numstackptr->var = alloca(var_name_size);
13301                         safe_strncpy(numstackptr->var, expr, var_name_size);
13302                         expr = p;
13303                 num:
13304                         numstackptr->contidional_second_val_initialized = 0;
13305                         numstackptr++;
13306                         lasttok = TOK_NUM;
13307                         continue;
13308                 } else if (is_digit(arithval)) {
13309                         numstackptr->var = NULL;
13310                         numstackptr->val = strtol(expr, (char **) &expr, 0);
13311                         goto num;
13312                 }
13313                 for(p = op_tokens; ; p++) {
13314                         const char *o;
13315
13316                         if(*p == 0) {
13317                                 /* strange operator not found */
13318                                 goto err;
13319                         }
13320                         for(o = expr; *p && *o == *p; p++)
13321                                 o++;
13322                         if(! *p) {
13323                                 /* found */
13324                                 expr = o - 1;
13325                                 break;
13326                         }
13327                         /* skip tail uncompared token */
13328                         while(*p)
13329                                 p++;
13330                         /* skip zero delim */
13331                         p++;
13332                 }
13333                 op = p[1];
13334
13335                 /* post grammar: a++ reduce to num */
13336                 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13337                     lasttok = TOK_NUM;
13338
13339                 /* Plus and minus are binary (not unary) _only_ if the last
13340                  * token was as number, or a right paren (which pretends to be
13341                  * a number, since it evaluates to one). Think about it.
13342                  * It makes sense. */
13343                 if (lasttok != TOK_NUM) {
13344                         switch(op) {
13345                                 case TOK_ADD:
13346                                     op = TOK_UPLUS;
13347                                     break;
13348                                 case TOK_SUB:
13349                                     op = TOK_UMINUS;
13350                                     break;
13351                                 case TOK_POST_INC:
13352                                     op = TOK_PRE_INC;
13353                                     break;
13354                                 case TOK_POST_DEC:
13355                                     op = TOK_PRE_DEC;
13356                                     break;
13357                         }
13358                 }
13359                 /* We don't want a unary operator to cause recursive descent on the
13360                  * stack, because there can be many in a row and it could cause an
13361                  * operator to be evaluated before its argument is pushed onto the
13362                  * integer stack. */
13363                 /* But for binary operators, "apply" everything on the operator
13364                  * stack until we find an operator with a lesser priority than the
13365                  * one we have just extracted. */
13366                 /* Left paren is given the lowest priority so it will never be
13367                  * "applied" in this way.
13368                  * if associativity is right and priority eq, applied also skip
13369                  */
13370                 prec = PREC(op);
13371                 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13372                         /* not left paren or unary */
13373                         if (lasttok != TOK_NUM) {
13374                                 /* binary op must be preceded by a num */
13375                                 goto err;
13376                         }
13377                         while (stackptr != stack) {
13378                             if (op == TOK_RPAREN) {
13379                                 /* The algorithm employed here is simple: while we don't
13380                                  * hit an open paren nor the bottom of the stack, pop
13381                                  * tokens and apply them */
13382                                 if (stackptr[-1] == TOK_LPAREN) {
13383                                     --stackptr;
13384                                     /* Any operator directly after a */
13385                                     lasttok = TOK_NUM;
13386                                     /* close paren should consider itself binary */
13387                                     goto prologue;
13388                                 }
13389                             } else {
13390                                 operator prev_prec = PREC(stackptr[-1]);
13391
13392                                 convert_prec_is_assing(prec);
13393                                 convert_prec_is_assing(prev_prec);
13394                                 if (prev_prec < prec)
13395                                         break;
13396                                 /* check right assoc */
13397                                 if(prev_prec == prec && is_right_associativity(prec))
13398                                         break;
13399                             }
13400                             errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13401                             if(errcode) goto ret;
13402                         }
13403                         if (op == TOK_RPAREN) {
13404                                 goto err;
13405                         }
13406                 }
13407
13408                 /* Push this operator to the stack and remember it. */
13409                 *stackptr++ = lasttok = op;
13410
13411           prologue:
13412                 ++expr;
13413         }
13414     }
13415 }
13416 #endif /* CONFIG_ASH_MATH_SUPPORT */
13417
13418
13419 #ifdef DEBUG
13420 const char *bb_applet_name = "debug stuff usage";
13421 int main(int argc, char **argv)
13422 {
13423         return ash_main(argc, argv);
13424 }
13425 #endif
13426
13427 /*-
13428  * Copyright (c) 1989, 1991, 1993, 1994
13429  *      The Regents of the University of California.  All rights reserved.
13430  *
13431  * This code is derived from software contributed to Berkeley by
13432  * Kenneth Almquist.
13433  *
13434  * Redistribution and use in source and binary forms, with or without
13435  * modification, are permitted provided that the following conditions
13436  * are met:
13437  * 1. Redistributions of source code must retain the above copyright
13438  *    notice, this list of conditions and the following disclaimer.
13439  * 2. Redistributions in binary form must reproduce the above copyright
13440  *    notice, this list of conditions and the following disclaimer in the
13441  *    documentation and/or other materials provided with the distribution.
13442  *
13443  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13444  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13445  *
13446  * 4. Neither the name of the University nor the names of its contributors
13447  *    may be used to endorse or promote products derived from this software
13448  *    without specific prior written permission.
13449  *
13450  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13451  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13452  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13453  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13454  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13455  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13456  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13457  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13458  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13459  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13460  * SUCH DAMAGE.
13461  */