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