6edc48421448b025428d3e4df7e51ad5bee4b380
[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 #define basebuf bb_common_bufsiz1       /* 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
5943 static void pushfile(void);
5944
5945 /*
5946  * Read a character from the script, returning PEOF on end of file.
5947  * Nul characters in the input are silently discarded.
5948  */
5949
5950 #define pgetc_as_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5951
5952 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5953 #define pgetc_macro() pgetc()
5954 static int
5955 pgetc(void)
5956 {
5957         return pgetc_as_macro();
5958 }
5959 #else
5960 #define pgetc_macro()   pgetc_as_macro()
5961 static int
5962 pgetc(void)
5963 {
5964         return pgetc_macro();
5965 }
5966 #endif
5967
5968
5969 /*
5970  * Same as pgetc(), but ignores PEOA.
5971  */
5972 #ifdef CONFIG_ASH_ALIAS
5973 static int pgetc2(void)
5974 {
5975         int c;
5976
5977         do {
5978                 c = pgetc_macro();
5979         } while (c == PEOA);
5980         return c;
5981 }
5982 #else
5983 static inline int pgetc2(void)
5984 {
5985         return pgetc_macro();
5986 }
5987 #endif
5988
5989 /*
5990  * Read a line from the script.
5991  */
5992
5993 static inline char *
5994 pfgets(char *line, int len)
5995 {
5996         char *p = line;
5997         int nleft = len;
5998         int c;
5999
6000         while (--nleft > 0) {
6001                 c = pgetc2();
6002                 if (c == PEOF) {
6003                         if (p == line)
6004                                 return NULL;
6005                         break;
6006                 }
6007                 *p++ = c;
6008                 if (c == '\n')
6009                         break;
6010         }
6011         *p = '\0';
6012         return line;
6013 }
6014
6015
6016
6017 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6018 #ifdef CONFIG_ASH_EXPAND_PRMT
6019 static char *cmdedit_prompt;
6020 #else
6021 static const char *cmdedit_prompt;
6022 #endif
6023 static inline void putprompt(const char *s)
6024 {
6025 #ifdef CONFIG_ASH_EXPAND_PRMT
6026         free(cmdedit_prompt);
6027         cmdedit_prompt = bb_xstrdup(s);
6028 #else
6029         cmdedit_prompt = s;
6030 #endif
6031 }
6032 #else
6033 static inline void putprompt(const char *s)
6034 {
6035         out2str(s);
6036 }
6037 #endif
6038
6039 static inline int
6040 preadfd(void)
6041 {
6042         int nr;
6043         char *buf =  parsefile->buf;
6044         parsenextc = buf;
6045
6046 retry:
6047 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6048         if (!iflag || parsefile->fd)
6049                 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6050         else {
6051 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6052                 cmdedit_path_lookup = pathval();
6053 #endif
6054                 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6055                 if(nr == 0) {
6056                         /* Ctrl+C presend */
6057                         if(trap[SIGINT]) {
6058                                 buf[0] = '\n';
6059                                 buf[1] = 0;
6060                                 raise(SIGINT);
6061                                 return 1;
6062                         }
6063                         goto retry;
6064                 }
6065                 if(nr < 0 && errno == 0) {
6066                         /* Ctrl+D presend */
6067                         nr = 0;
6068                 }
6069         }
6070 #else
6071         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6072 #endif
6073
6074         if (nr < 0) {
6075                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6076                         int flags = fcntl(0, F_GETFL, 0);
6077                         if (flags >= 0 && flags & O_NONBLOCK) {
6078                                 flags &=~ O_NONBLOCK;
6079                                 if (fcntl(0, F_SETFL, flags) >= 0) {
6080                                         out2str("sh: turning off NDELAY mode\n");
6081                                         goto retry;
6082                                 }
6083                         }
6084                 }
6085         }
6086         return nr;
6087 }
6088
6089 /*
6090  * Refill the input buffer and return the next input character:
6091  *
6092  * 1) If a string was pushed back on the input, pop it;
6093  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6094  *    from a string so we can't refill the buffer, return EOF.
6095  * 3) If the is more stuff in this buffer, use it else call read to fill it.
6096  * 4) Process input up to the next newline, deleting nul characters.
6097  */
6098
6099 int
6100 preadbuffer(void)
6101 {
6102         char *p, *q;
6103         int more;
6104         char savec;
6105
6106         while (parsefile->strpush) {
6107 #ifdef CONFIG_ASH_ALIAS
6108                 if (parsenleft == -1 && parsefile->strpush->ap &&
6109                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6110                         return PEOA;
6111                 }
6112 #endif
6113                 popstring();
6114                 if (--parsenleft >= 0)
6115                         return (*parsenextc++);
6116         }
6117         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6118                 return PEOF;
6119         flushall();
6120
6121 again:
6122         if (parselleft <= 0) {
6123                 if ((parselleft = preadfd()) <= 0) {
6124                         parselleft = parsenleft = EOF_NLEFT;
6125                         return PEOF;
6126                 }
6127         }
6128
6129         q = p = parsenextc;
6130
6131         /* delete nul characters */
6132         for (more = 1; more;) {
6133                 switch (*p) {
6134                 case '\0':
6135                         p++;    /* Skip nul */
6136                         goto check;
6137
6138                 case '\n':
6139                         parsenleft = q - parsenextc;
6140                         more = 0; /* Stop processing here */
6141                         break;
6142
6143                 }
6144
6145                 *q++ = *p++;
6146 check:
6147                 if (--parselleft <= 0 && more) {
6148                         parsenleft = q - parsenextc - 1;
6149                         if (parsenleft < 0)
6150                                 goto again;
6151                         more = 0;
6152                 }
6153         }
6154
6155         savec = *q;
6156         *q = '\0';
6157
6158         if (vflag) {
6159                 out2str(parsenextc);
6160         }
6161
6162         *q = savec;
6163
6164         return *parsenextc++;
6165 }
6166
6167 /*
6168  * Undo the last call to pgetc.  Only one character may be pushed back.
6169  * PEOF may be pushed back.
6170  */
6171
6172 void
6173 pungetc(void)
6174 {
6175         parsenleft++;
6176         parsenextc--;
6177 }
6178
6179 /*
6180  * Push a string back onto the input at this current parsefile level.
6181  * We handle aliases this way.
6182  */
6183 void
6184 pushstring(char *s, void *ap)
6185 {
6186         struct strpush *sp;
6187         size_t len;
6188
6189         len = strlen(s);
6190         INTOFF;
6191 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6192         if (parsefile->strpush) {
6193                 sp = ckmalloc(sizeof (struct strpush));
6194                 sp->prev = parsefile->strpush;
6195                 parsefile->strpush = sp;
6196         } else
6197                 sp = parsefile->strpush = &(parsefile->basestrpush);
6198         sp->prevstring = parsenextc;
6199         sp->prevnleft = parsenleft;
6200 #ifdef CONFIG_ASH_ALIAS
6201         sp->ap = (struct alias *)ap;
6202         if (ap) {
6203                 ((struct alias *)ap)->flag |= ALIASINUSE;
6204                 sp->string = s;
6205         }
6206 #endif
6207         parsenextc = s;
6208         parsenleft = len;
6209         INTON;
6210 }
6211
6212 void
6213 popstring(void)
6214 {
6215         struct strpush *sp = parsefile->strpush;
6216
6217         INTOFF;
6218 #ifdef CONFIG_ASH_ALIAS
6219         if (sp->ap) {
6220                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6221                         checkkwd |= CHKALIAS;
6222                 }
6223                 if (sp->string != sp->ap->val) {
6224                         ckfree(sp->string);
6225                 }
6226                 sp->ap->flag &= ~ALIASINUSE;
6227                 if (sp->ap->flag & ALIASDEAD) {
6228                         unalias(sp->ap->name);
6229                 }
6230         }
6231 #endif
6232         parsenextc = sp->prevstring;
6233         parsenleft = sp->prevnleft;
6234 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6235         parsefile->strpush = sp->prev;
6236         if (sp != &(parsefile->basestrpush))
6237                 ckfree(sp);
6238         INTON;
6239 }
6240
6241 /*
6242  * Set the input to take input from a file.  If push is set, push the
6243  * old input onto the stack first.
6244  */
6245
6246 void
6247 setinputfile(const char *fname, int push)
6248 {
6249         int fd;
6250         int fd2;
6251
6252         INTOFF;
6253         if ((fd = open(fname, O_RDONLY)) < 0)
6254                 error("Can't open %s", fname);
6255         if (fd < 10) {
6256                 fd2 = copyfd(fd, 10);
6257                 close(fd);
6258                 if (fd2 < 0)
6259                         error("Out of file descriptors");
6260                 fd = fd2;
6261         }
6262         setinputfd(fd, push);
6263         INTON;
6264 }
6265
6266
6267 /*
6268  * Like setinputfile, but takes an open file descriptor.  Call this with
6269  * interrupts off.
6270  */
6271
6272 static void
6273 setinputfd(int fd, int push)
6274 {
6275         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6276         if (push) {
6277                 pushfile();
6278                 parsefile->buf = 0;
6279         }
6280         parsefile->fd = fd;
6281         if (parsefile->buf == NULL)
6282                 parsefile->buf = ckmalloc(IBUFSIZ);
6283         parselleft = parsenleft = 0;
6284         plinno = 1;
6285 }
6286
6287
6288 /*
6289  * Like setinputfile, but takes input from a string.
6290  */
6291
6292 static void
6293 setinputstring(char *string)
6294 {
6295         INTOFF;
6296         pushfile();
6297         parsenextc = string;
6298         parsenleft = strlen(string);
6299         parsefile->buf = NULL;
6300         plinno = 1;
6301         INTON;
6302 }
6303
6304
6305 /*
6306  * To handle the "." command, a stack of input files is used.  Pushfile
6307  * adds a new entry to the stack and popfile restores the previous level.
6308  */
6309
6310 static void
6311 pushfile(void)
6312 {
6313         struct parsefile *pf;
6314
6315         parsefile->nleft = parsenleft;
6316         parsefile->lleft = parselleft;
6317         parsefile->nextc = parsenextc;
6318         parsefile->linno = plinno;
6319         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6320         pf->prev = parsefile;
6321         pf->fd = -1;
6322         pf->strpush = NULL;
6323         pf->basestrpush.prev = NULL;
6324         parsefile = pf;
6325 }
6326
6327
6328 static void
6329 popfile(void)
6330 {
6331         struct parsefile *pf = parsefile;
6332
6333         INTOFF;
6334         if (pf->fd >= 0)
6335                 close(pf->fd);
6336         if (pf->buf)
6337                 ckfree(pf->buf);
6338         while (pf->strpush)
6339                 popstring();
6340         parsefile = pf->prev;
6341         ckfree(pf);
6342         parsenleft = parsefile->nleft;
6343         parselleft = parsefile->lleft;
6344         parsenextc = parsefile->nextc;
6345         plinno = parsefile->linno;
6346         INTON;
6347 }
6348
6349
6350 /*
6351  * Return to top level.
6352  */
6353
6354 static void
6355 popallfiles(void)
6356 {
6357         while (parsefile != &basepf)
6358                 popfile();
6359 }
6360
6361
6362 /*
6363  * Close the file(s) that the shell is reading commands from.  Called
6364  * after a fork is done.
6365  */
6366
6367 static void
6368 closescript(void)
6369 {
6370         popallfiles();
6371         if (parsefile->fd > 0) {
6372                 close(parsefile->fd);
6373                 parsefile->fd = 0;
6374         }
6375 }
6376
6377 /*      $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $    */
6378
6379 /* mode flags for set_curjob */
6380 #define CUR_DELETE 2
6381 #define CUR_RUNNING 1
6382 #define CUR_STOPPED 0
6383
6384 /* mode flags for dowait */
6385 #define DOWAIT_NORMAL 0
6386 #define DOWAIT_BLOCK 1
6387
6388 /* array of jobs */
6389 static struct job *jobtab;
6390 /* size of array */
6391 static unsigned njobs;
6392 #if JOBS
6393 /* pgrp of shell on invocation */
6394 static int initialpgrp;
6395 static int ttyfd = -1;
6396 #endif
6397 /* current job */
6398 static struct job *curjob;
6399 /* number of presumed living untracked jobs */
6400 static int jobless;
6401
6402 static void set_curjob(struct job *, unsigned);
6403 #if JOBS
6404 static int restartjob(struct job *, int);
6405 static void xtcsetpgrp(int, pid_t);
6406 static char *commandtext(union node *);
6407 static void cmdlist(union node *, int);
6408 static void cmdtxt(union node *);
6409 static void cmdputs(const char *);
6410 static void showpipe(struct job *, FILE *);
6411 #endif
6412 static int sprint_status(char *, int, int);
6413 static void freejob(struct job *);
6414 static struct job *getjob(const char *, int);
6415 static struct job *growjobtab(void);
6416 static void forkchild(struct job *, union node *, int);
6417 static void forkparent(struct job *, union node *, int, pid_t);
6418 static int dowait(int, struct job *);
6419 static int getstatus(struct job *);
6420
6421 static void
6422 set_curjob(struct job *jp, unsigned mode)
6423 {
6424         struct job *jp1;
6425         struct job **jpp, **curp;
6426
6427         /* first remove from list */
6428         jpp = curp = &curjob;
6429         do {
6430                 jp1 = *jpp;
6431                 if (jp1 == jp)
6432                         break;
6433                 jpp = &jp1->prev_job;
6434         } while (1);
6435         *jpp = jp1->prev_job;
6436
6437         /* Then re-insert in correct position */
6438         jpp = curp;
6439         switch (mode) {
6440         default:
6441 #ifdef DEBUG
6442                 abort();
6443 #endif
6444         case CUR_DELETE:
6445                 /* job being deleted */
6446                 break;
6447         case CUR_RUNNING:
6448                 /* newly created job or backgrounded job,
6449                    put after all stopped jobs. */
6450                 do {
6451                         jp1 = *jpp;
6452 #ifdef JOBS
6453                         if (!jp1 || jp1->state != JOBSTOPPED)
6454 #endif
6455                                 break;
6456                         jpp = &jp1->prev_job;
6457                 } while (1);
6458                 /* FALLTHROUGH */
6459 #ifdef JOBS
6460         case CUR_STOPPED:
6461 #endif
6462                 /* newly stopped job - becomes curjob */
6463                 jp->prev_job = *jpp;
6464                 *jpp = jp;
6465                 break;
6466         }
6467 }
6468
6469 #if JOBS
6470 /*
6471  * Turn job control on and off.
6472  *
6473  * Note:  This code assumes that the third arg to ioctl is a character
6474  * pointer, which is true on Berkeley systems but not System V.  Since
6475  * System V doesn't have job control yet, this isn't a problem now.
6476  *
6477  * Called with interrupts off.
6478  */
6479
6480 void
6481 setjobctl(int on)
6482 {
6483         int fd;
6484         int pgrp;
6485
6486         if (on == jobctl || rootshell == 0)
6487                 return;
6488         if (on) {
6489                 int ofd;
6490                 ofd = fd = open(_PATH_TTY, O_RDWR);
6491                 if (fd < 0) {
6492                         fd += 3;
6493                         while (!isatty(fd) && --fd >= 0)
6494                                 ;
6495                 }
6496                 fd = fcntl(fd, F_DUPFD, 10);
6497                 close(ofd);
6498                 if (fd < 0)
6499                         goto out;
6500                 fcntl(fd, F_SETFD, FD_CLOEXEC);
6501                 do { /* while we are in the background */
6502                         if ((pgrp = tcgetpgrp(fd)) < 0) {
6503 out:
6504                                 sh_warnx("can't access tty; job control turned off");
6505                                 mflag = on = 0;
6506                                 goto close;
6507                         }
6508                         if (pgrp == getpgrp())
6509                                 break;
6510                         killpg(0, SIGTTIN);
6511                 } while (1);
6512                 initialpgrp = pgrp;
6513
6514                 setsignal(SIGTSTP);
6515                 setsignal(SIGTTOU);
6516                 setsignal(SIGTTIN);
6517                 pgrp = rootpid;
6518                 setpgid(0, pgrp);
6519                 xtcsetpgrp(fd, pgrp);
6520         } else {
6521                 /* turning job control off */
6522                 fd = ttyfd;
6523                 pgrp = initialpgrp;
6524                 xtcsetpgrp(fd, pgrp);
6525                 setpgid(0, pgrp);
6526                 setsignal(SIGTSTP);
6527                 setsignal(SIGTTOU);
6528                 setsignal(SIGTTIN);
6529 close:
6530                 close(fd);
6531                 fd = -1;
6532         }
6533         ttyfd = fd;
6534         jobctl = on;
6535 }
6536
6537 static int
6538 killcmd(int argc, char **argv)
6539 {
6540         int signo = -1;
6541         int list = 0;
6542         int i;
6543         pid_t pid;
6544         struct job *jp;
6545
6546         if (argc <= 1) {
6547 usage:
6548                 error(
6549 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6550 "kill -l [exitstatus]"
6551                 );
6552         }
6553
6554         if (**++argv == '-') {
6555                 signo = decode_signal(*argv + 1, 1);
6556                 if (signo < 0) {
6557                         int c;
6558
6559                         while ((c = nextopt("ls:")) != '\0')
6560                                 switch (c) {
6561                                 default:
6562 #ifdef DEBUG
6563                                         abort();
6564 #endif
6565                                 case 'l':
6566                                         list = 1;
6567                                         break;
6568                                 case 's':
6569                                         signo = decode_signal(optionarg, 1);
6570                                         if (signo < 0) {
6571                                                 error(
6572                                                         "invalid signal number or name: %s",
6573                                                         optionarg
6574                                                 );
6575                                         }
6576                                         break;
6577                                 }
6578                         argv = argptr;
6579                 } else
6580                         argv++;
6581         }
6582
6583         if (!list && signo < 0)
6584                 signo = SIGTERM;
6585
6586         if ((signo < 0 || !*argv) ^ list) {
6587                 goto usage;
6588         }
6589
6590         if (list) {
6591                 const char *name;
6592
6593                 if (!*argv) {
6594                         for (i = 1; i < NSIG; i++) {
6595                                 name = u_signal_names(0, &i, 1);
6596                                 if (name)
6597                                         out1fmt(snlfmt, name);
6598                         }
6599                         return 0;
6600                 }
6601                 name = u_signal_names(*argptr, &signo, -1);
6602                 if (name)
6603                         out1fmt(snlfmt, name);
6604                 else
6605                         error("invalid signal number or exit status: %s", *argptr);
6606                 return 0;
6607         }
6608
6609         i = 0;
6610         do {
6611                 if (**argv == '%') {
6612                         jp = getjob(*argv, 0);
6613                         pid = -jp->ps[0].pid;
6614                 } else {
6615                         pid = **argv == '-' ?
6616                                 -number(*argv + 1) : number(*argv);
6617                 }
6618                 if (kill(pid, signo) != 0) {
6619                         sh_warnx("(%d) - %m", pid);
6620                         i = 1;
6621                 }
6622         } while (*++argv);
6623
6624         return i;
6625 }
6626 #endif /* JOBS */
6627
6628 #if defined(JOBS) || defined(DEBUG)
6629 static int
6630 jobno(const struct job *jp)
6631 {
6632         return jp - jobtab + 1;
6633 }
6634 #endif
6635
6636 #ifdef JOBS
6637 static int
6638 fgcmd(int argc, char **argv)
6639 {
6640         struct job *jp;
6641         FILE *out;
6642         int mode;
6643         int retval;
6644
6645         mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6646         nextopt(nullstr);
6647         argv = argptr;
6648         out = stdout;
6649         do {
6650                 jp = getjob(*argv, 1);
6651                 if (mode == FORK_BG) {
6652                         set_curjob(jp, CUR_RUNNING);
6653                         fprintf(out, "[%d] ", jobno(jp));
6654                 }
6655                 outstr(jp->ps->cmd, out);
6656                 showpipe(jp, out);
6657                 retval = restartjob(jp, mode);
6658         } while (*argv && *++argv);
6659         return retval;
6660 }
6661
6662 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6663
6664
6665 static int
6666 restartjob(struct job *jp, int mode)
6667 {
6668         struct procstat *ps;
6669         int i;
6670         int status;
6671         pid_t pgid;
6672
6673         INTOFF;
6674         if (jp->state == JOBDONE)
6675                 goto out;
6676         jp->state = JOBRUNNING;
6677         pgid = jp->ps->pid;
6678         if (mode == FORK_FG)
6679                 xtcsetpgrp(ttyfd, pgid);
6680         killpg(pgid, SIGCONT);
6681         ps = jp->ps;
6682         i = jp->nprocs;
6683         do {
6684                 if (WIFSTOPPED(ps->status)) {
6685                         ps->status = -1;
6686                 }
6687         } while (ps++, --i);
6688 out:
6689         status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6690         INTON;
6691         return status;
6692 }
6693 #endif
6694
6695 static int
6696 sprint_status(char *s, int status, int sigonly)
6697 {
6698         int col;
6699         int st;
6700
6701         col = 0;
6702         if (!WIFEXITED(status)) {
6703 #if JOBS
6704                 if (WIFSTOPPED(status))
6705                         st = WSTOPSIG(status);
6706                 else
6707 #endif
6708                         st = WTERMSIG(status);
6709                 if (sigonly) {
6710                         if (st == SIGINT || st == SIGPIPE)
6711                                 goto out;
6712 #if JOBS
6713                         if (WIFSTOPPED(status))
6714                                 goto out;
6715 #endif
6716                 }
6717                 st &= 0x7f;
6718                 col = fmtstr(s, 32, strsignal(st));
6719                 if (WCOREDUMP(status)) {
6720                         col += fmtstr(s + col, 16, " (core dumped)");
6721                 }
6722         } else if (!sigonly) {
6723                 st = WEXITSTATUS(status);
6724                 if (st)
6725                         col = fmtstr(s, 16, "Done(%d)", st);
6726                 else
6727                         col = fmtstr(s, 16, "Done");
6728         }
6729
6730 out:
6731         return col;
6732 }
6733
6734 #if JOBS
6735 static void
6736 showjob(FILE *out, struct job *jp, int mode)
6737 {
6738         struct procstat *ps;
6739         struct procstat *psend;
6740         int col;
6741         int indent;
6742         char s[80];
6743
6744         ps = jp->ps;
6745
6746         if (mode & SHOW_PGID) {
6747                 /* just output process (group) id of pipeline */
6748                 fprintf(out, "%d\n", ps->pid);
6749                 return;
6750         }
6751
6752         col = fmtstr(s, 16, "[%d]   ", jobno(jp));
6753         indent = col;
6754
6755         if (jp == curjob)
6756                 s[col - 2] = '+';
6757         else if (curjob && jp == curjob->prev_job)
6758                 s[col - 2] = '-';
6759
6760         if (mode & SHOW_PID)
6761                 col += fmtstr(s + col, 16, "%d ", ps->pid);
6762
6763         psend = ps + jp->nprocs;
6764
6765         if (jp->state == JOBRUNNING) {
6766                 scopy("Running", s + col);
6767                 col += strlen("Running");
6768         } else {
6769                 int status = psend[-1].status;
6770 #if JOBS
6771                 if (jp->state == JOBSTOPPED)
6772                         status = jp->stopstatus;
6773 #endif
6774                 col += sprint_status(s + col, status, 0);
6775         }
6776
6777         goto start;
6778
6779         do {
6780                 /* for each process */
6781                 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6782
6783 start:
6784                 fprintf(out, "%s%*c%s",
6785                         s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6786                 );
6787                 if (!(mode & SHOW_PID)) {
6788                         showpipe(jp, out);
6789                         break;
6790                 }
6791                 if (++ps == psend) {
6792                         outcslow('\n', out);
6793                         break;
6794                 }
6795         } while (1);
6796
6797         jp->changed = 0;
6798
6799         if (jp->state == JOBDONE) {
6800                 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6801                 freejob(jp);
6802         }
6803 }
6804
6805
6806 static int
6807 jobscmd(int argc, char **argv)
6808 {
6809         int mode, m;
6810         FILE *out;
6811
6812         mode = 0;
6813         while ((m = nextopt("lp")))
6814                 if (m == 'l')
6815                         mode = SHOW_PID;
6816                 else
6817                         mode = SHOW_PGID;
6818
6819         out = stdout;
6820         argv = argptr;
6821         if (*argv)
6822                 do
6823                         showjob(out, getjob(*argv,0), mode);
6824                 while (*++argv);
6825         else
6826                 showjobs(out, mode);
6827
6828         return 0;
6829 }
6830
6831
6832 /*
6833  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
6834  * statuses have changed since the last call to showjobs.
6835  */
6836
6837 static void
6838 showjobs(FILE *out, int mode)
6839 {
6840         struct job *jp;
6841
6842         TRACE(("showjobs(%x) called\n", mode));
6843
6844         /* If not even one one job changed, there is nothing to do */
6845         while (dowait(DOWAIT_NORMAL, NULL) > 0)
6846                 continue;
6847
6848         for (jp = curjob; jp; jp = jp->prev_job) {
6849                 if (!(mode & SHOW_CHANGED) || jp->changed)
6850                         showjob(out, jp, mode);
6851         }
6852 }
6853 #endif /* JOBS */
6854
6855 /*
6856  * Mark a job structure as unused.
6857  */
6858
6859 static void
6860 freejob(struct job *jp)
6861 {
6862         struct procstat *ps;
6863         int i;
6864
6865         INTOFF;
6866         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6867                 if (ps->cmd != nullstr)
6868                         ckfree(ps->cmd);
6869         }
6870         if (jp->ps != &jp->ps0)
6871                 ckfree(jp->ps);
6872         jp->used = 0;
6873         set_curjob(jp, CUR_DELETE);
6874         INTON;
6875 }
6876
6877
6878 static int
6879 waitcmd(int argc, char **argv)
6880 {
6881         struct job *job;
6882         int retval;
6883         struct job *jp;
6884
6885         EXSIGON();
6886
6887         nextopt(nullstr);
6888         retval = 0;
6889
6890         argv = argptr;
6891         if (!*argv) {
6892                 /* wait for all jobs */
6893                 for (;;) {
6894                         jp = curjob;
6895                         while (1) {
6896                                 if (!jp) {
6897                                         /* no running procs */
6898                                         goto out;
6899                                 }
6900                                 if (jp->state == JOBRUNNING)
6901                                         break;
6902                                 jp->waited = 1;
6903                                 jp = jp->prev_job;
6904                         }
6905                         dowait(DOWAIT_BLOCK, 0);
6906                 }
6907         }
6908
6909         retval = 127;
6910         do {
6911                 if (**argv != '%') {
6912                         pid_t pid = number(*argv);
6913                         job = curjob;
6914                         goto start;
6915                         do {
6916                                 if (job->ps[job->nprocs - 1].pid == pid)
6917                                         break;
6918                                 job = job->prev_job;
6919 start:
6920                                 if (!job)
6921                                         goto repeat;
6922                         } while (1);
6923                 } else
6924                         job = getjob(*argv, 0);
6925                 /* loop until process terminated or stopped */
6926                 while (job->state == JOBRUNNING)
6927                         dowait(DOWAIT_BLOCK, 0);
6928                 job->waited = 1;
6929                 retval = getstatus(job);
6930 repeat:
6931                 ;
6932         } while (*++argv);
6933
6934 out:
6935         return retval;
6936 }
6937
6938
6939 /*
6940  * Convert a job name to a job structure.
6941  */
6942
6943 static struct job *
6944 getjob(const char *name, int getctl)
6945 {
6946         struct job *jp;
6947         struct job *found;
6948         const char *err_msg = "No such job: %s";
6949         unsigned num;
6950         int c;
6951         const char *p;
6952         char *(*match)(const char *, const char *);
6953
6954         jp = curjob;
6955         p = name;
6956         if (!p)
6957                 goto currentjob;
6958
6959         if (*p != '%')
6960                 goto err;
6961
6962         c = *++p;
6963         if (!c)
6964                 goto currentjob;
6965
6966         if (!p[1]) {
6967                 if (c == '+' || c == '%') {
6968 currentjob:
6969                         err_msg = "No current job";
6970                         goto check;
6971                 } else if (c == '-') {
6972                         if (jp)
6973                                 jp = jp->prev_job;
6974                         err_msg = "No previous job";
6975 check:
6976                         if (!jp)
6977                                 goto err;
6978                         goto gotit;
6979                 }
6980         }
6981
6982         if (is_number(p)) {
6983                 num = atoi(p);
6984                 if (num < njobs) {
6985                         jp = jobtab + num - 1;
6986                         if (jp->used)
6987                                 goto gotit;
6988                         goto err;
6989                 }
6990         }
6991
6992         match = prefix;
6993         if (*p == '?') {
6994                 match = strstr;
6995                 p++;
6996         }
6997
6998         found = 0;
6999         while (1) {
7000                 if (!jp)
7001                         goto err;
7002                 if (match(jp->ps[0].cmd, p)) {
7003                         if (found)
7004                                 goto err;
7005                         found = jp;
7006                         err_msg = "%s: ambiguous";
7007                 }
7008                 jp = jp->prev_job;
7009         }
7010
7011 gotit:
7012 #if JOBS
7013         err_msg = "job %s not created under job control";
7014         if (getctl && jp->jobctl == 0)
7015                 goto err;
7016 #endif
7017         return jp;
7018 err:
7019         error(err_msg, name);
7020 }
7021
7022
7023 /*
7024  * Return a new job structure.
7025  * Called with interrupts off.
7026  */
7027
7028 static struct job *
7029 makejob(union node *node, int nprocs)
7030 {
7031         int i;
7032         struct job *jp;
7033
7034         for (i = njobs, jp = jobtab ; ; jp++) {
7035                 if (--i < 0) {
7036                         jp = growjobtab();
7037                         break;
7038                 }
7039                 if (jp->used == 0)
7040                         break;
7041                 if (jp->state != JOBDONE || !jp->waited)
7042                         continue;
7043 #if JOBS
7044                 if (jobctl)
7045                         continue;
7046 #endif
7047                 freejob(jp);
7048                 break;
7049         }
7050         memset(jp, 0, sizeof(*jp));
7051 #if JOBS
7052         if (jobctl)
7053                 jp->jobctl = 1;
7054 #endif
7055         jp->prev_job = curjob;
7056         curjob = jp;
7057         jp->used = 1;
7058         jp->ps = &jp->ps0;
7059         if (nprocs > 1) {
7060                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7061         }
7062         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7063             jobno(jp)));
7064         return jp;
7065 }
7066
7067 static struct job *
7068 growjobtab(void)
7069 {
7070         size_t len;
7071         ptrdiff_t offset;
7072         struct job *jp, *jq;
7073
7074         len = njobs * sizeof(*jp);
7075         jq = jobtab;
7076         jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7077
7078         offset = (char *)jp - (char *)jq;
7079         if (offset) {
7080                 /* Relocate pointers */
7081                 size_t l = len;
7082
7083                 jq = (struct job *)((char *)jq + l);
7084                 while (l) {
7085                         l -= sizeof(*jp);
7086                         jq--;
7087 #define joff(p) ((struct job *)((char *)(p) + l))
7088 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7089                         if (xlikely(joff(jp)->ps == &jq->ps0))
7090                                 jmove(joff(jp)->ps);
7091                         if (joff(jp)->prev_job)
7092                                 jmove(joff(jp)->prev_job);
7093                 }
7094                 if (curjob)
7095                         jmove(curjob);
7096 #undef joff
7097 #undef jmove
7098         }
7099
7100         njobs += 4;
7101         jobtab = jp;
7102         jp = (struct job *)((char *)jp + len);
7103         jq = jp + 3;
7104         do {
7105                 jq->used = 0;
7106         } while (--jq >= jp);
7107         return jp;
7108 }
7109
7110
7111 /*
7112  * Fork off a subshell.  If we are doing job control, give the subshell its
7113  * own process group.  Jp is a job structure that the job is to be added to.
7114  * N is the command that will be evaluated by the child.  Both jp and n may
7115  * be NULL.  The mode parameter can be one of the following:
7116  *      FORK_FG - Fork off a foreground process.
7117  *      FORK_BG - Fork off a background process.
7118  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
7119  *                   process group even if job control is on.
7120  *
7121  * When job control is turned off, background processes have their standard
7122  * input redirected to /dev/null (except for the second and later processes
7123  * in a pipeline).
7124  *
7125  * Called with interrupts off.
7126  */
7127
7128 static inline void
7129 forkchild(struct job *jp, union node *n, int mode)
7130 {
7131         int wasroot;
7132
7133         TRACE(("Child shell %d\n", getpid()));
7134         wasroot = rootshell;
7135         rootshell = 0;
7136
7137         closescript();
7138         clear_traps();
7139 #if JOBS
7140         /* do job control only in root shell */
7141         jobctl = 0;
7142         if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7143                 pid_t pgrp;
7144
7145                 if (jp->nprocs == 0)
7146                         pgrp = getpid();
7147                 else
7148                         pgrp = jp->ps[0].pid;
7149                 /* This can fail because we are doing it in the parent also */
7150                 (void)setpgid(0, pgrp);
7151                 if (mode == FORK_FG)
7152                         xtcsetpgrp(ttyfd, pgrp);
7153                 setsignal(SIGTSTP);
7154                 setsignal(SIGTTOU);
7155         } else
7156 #endif
7157         if (mode == FORK_BG) {
7158                 ignoresig(SIGINT);
7159                 ignoresig(SIGQUIT);
7160                 if (jp->nprocs == 0) {
7161                         close(0);
7162                         if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7163                                 error("Can't open %s", _PATH_DEVNULL);
7164                 }
7165         }
7166         if (wasroot && iflag) {
7167                 setsignal(SIGINT);
7168                 setsignal(SIGQUIT);
7169                 setsignal(SIGTERM);
7170         }
7171         for (jp = curjob; jp; jp = jp->prev_job)
7172                 freejob(jp);
7173         jobless = 0;
7174 }
7175
7176 static inline void
7177 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7178 {
7179         TRACE(("In parent shell:  child = %d\n", pid));
7180         if (!jp) {
7181                 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7182                 jobless++;
7183                 return;
7184         }
7185 #if JOBS
7186         if (mode != FORK_NOJOB && jp->jobctl) {
7187                 int pgrp;
7188
7189                 if (jp->nprocs == 0)
7190                         pgrp = pid;
7191                 else
7192                         pgrp = jp->ps[0].pid;
7193                 /* This can fail because we are doing it in the child also */
7194                 (void)setpgid(pid, pgrp);
7195         }
7196 #endif
7197         if (mode == FORK_BG) {
7198                 backgndpid = pid;               /* set $! */
7199                 set_curjob(jp, CUR_RUNNING);
7200         }
7201         if (jp) {
7202                 struct procstat *ps = &jp->ps[jp->nprocs++];
7203                 ps->pid = pid;
7204                 ps->status = -1;
7205                 ps->cmd = nullstr;
7206 #if JOBS
7207                 if (jobctl && n)
7208                         ps->cmd = commandtext(n);
7209 #endif
7210         }
7211 }
7212
7213 static int
7214 forkshell(struct job *jp, union node *n, int mode)
7215 {
7216         int pid;
7217
7218         TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7219         pid = fork();
7220         if (pid < 0) {
7221                 TRACE(("Fork failed, errno=%d", errno));
7222                 if (jp)
7223                         freejob(jp);
7224                 error("Cannot fork");
7225         }
7226         if (pid == 0)
7227                 forkchild(jp, n, mode);
7228         else
7229                 forkparent(jp, n, mode, pid);
7230         return pid;
7231 }
7232
7233 /*
7234  * Wait for job to finish.
7235  *
7236  * Under job control we have the problem that while a child process is
7237  * running interrupts generated by the user are sent to the child but not
7238  * to the shell.  This means that an infinite loop started by an inter-
7239  * active user may be hard to kill.  With job control turned off, an
7240  * interactive user may place an interactive program inside a loop.  If
7241  * the interactive program catches interrupts, the user doesn't want
7242  * these interrupts to also abort the loop.  The approach we take here
7243  * is to have the shell ignore interrupt signals while waiting for a
7244  * foreground process to terminate, and then send itself an interrupt
7245  * signal if the child process was terminated by an interrupt signal.
7246  * Unfortunately, some programs want to do a bit of cleanup and then
7247  * exit on interrupt; unless these processes terminate themselves by
7248  * sending a signal to themselves (instead of calling exit) they will
7249  * confuse this approach.
7250  *
7251  * Called with interrupts off.
7252  */
7253
7254 int
7255 waitforjob(struct job *jp)
7256 {
7257         int st;
7258
7259         TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7260         while (jp->state == JOBRUNNING) {
7261                 dowait(DOWAIT_BLOCK, jp);
7262         }
7263         st = getstatus(jp);
7264 #if JOBS
7265         if (jp->jobctl) {
7266                 xtcsetpgrp(ttyfd, rootpid);
7267                 /*
7268                  * This is truly gross.
7269                  * If we're doing job control, then we did a TIOCSPGRP which
7270                  * caused us (the shell) to no longer be in the controlling
7271                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
7272                  * intuit from the subprocess exit status whether a SIGINT
7273                  * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
7274                  */
7275                 if (jp->sigint)
7276                         raise(SIGINT);
7277         }
7278         if (jp->state == JOBDONE)
7279 #endif
7280                 freejob(jp);
7281         return st;
7282 }
7283
7284
7285 /*
7286  * Do a wait system call.  If job control is compiled in, we accept
7287  * stopped processes.  If block is zero, we return a value of zero
7288  * rather than blocking.
7289  *
7290  * System V doesn't have a non-blocking wait system call.  It does
7291  * have a SIGCLD signal that is sent to a process when one of it's
7292  * children dies.  The obvious way to use SIGCLD would be to install
7293  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7294  * was received, and have waitproc bump another counter when it got
7295  * the status of a process.  Waitproc would then know that a wait
7296  * system call would not block if the two counters were different.
7297  * This approach doesn't work because if a process has children that
7298  * have not been waited for, System V will send it a SIGCLD when it
7299  * installs a signal handler for SIGCLD.  What this means is that when
7300  * a child exits, the shell will be sent SIGCLD signals continuously
7301  * until is runs out of stack space, unless it does a wait call before
7302  * restoring the signal handler.  The code below takes advantage of
7303  * this (mis)feature by installing a signal handler for SIGCLD and
7304  * then checking to see whether it was called.  If there are any
7305  * children to be waited for, it will be.
7306  *
7307  * If neither SYSV nor BSD is defined, we don't implement nonblocking
7308  * waits at all.  In this case, the user will not be informed when
7309  * a background process until the next time she runs a real program
7310  * (as opposed to running a builtin command or just typing return),
7311  * and the jobs command may give out of date information.
7312  */
7313
7314 static inline int
7315 waitproc(int block, int *status)
7316 {
7317         int flags = 0;
7318
7319 #if JOBS
7320         if (jobctl)
7321                 flags |= WUNTRACED;
7322 #endif
7323         if (block == 0)
7324                 flags |= WNOHANG;
7325         return wait3(status, flags, (struct rusage *)NULL);
7326 }
7327
7328 /*
7329  * Wait for a process to terminate.
7330  */
7331
7332 static int
7333 dowait(int block, struct job *job)
7334 {
7335         int pid;
7336         int status;
7337         struct job *jp;
7338         struct job *thisjob;
7339         int state;
7340
7341         TRACE(("dowait(%d) called\n", block));
7342         pid = waitproc(block, &status);
7343         TRACE(("wait returns pid %d, status=%d\n", pid, status));
7344         if (pid <= 0)
7345                 return pid;
7346         INTOFF;
7347         thisjob = NULL;
7348         for (jp = curjob; jp; jp = jp->prev_job) {
7349                 struct procstat *sp;
7350                 struct procstat *spend;
7351                 if (jp->state == JOBDONE)
7352                         continue;
7353                 state = JOBDONE;
7354                 spend = jp->ps + jp->nprocs;
7355                 sp = jp->ps;
7356                 do {
7357                         if (sp->pid == pid) {
7358                                 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7359                                 sp->status = status;
7360                                 thisjob = jp;
7361                         }
7362                         if (sp->status == -1)
7363                                 state = JOBRUNNING;
7364 #ifdef JOBS
7365                         if (state == JOBRUNNING)
7366                                 continue;
7367                         if (WIFSTOPPED(sp->status)) {
7368                                 jp->stopstatus = sp->status;
7369                                 state = JOBSTOPPED;
7370                         }
7371 #endif
7372                 } while (++sp < spend);
7373                 if (thisjob)
7374                         goto gotjob;
7375         }
7376 #ifdef JOBS
7377         if (!WIFSTOPPED(status))
7378 #endif
7379
7380                 jobless--;
7381         goto out;
7382
7383 gotjob:
7384         if (state != JOBRUNNING) {
7385                 thisjob->changed = 1;
7386
7387                 if (thisjob->state != state) {
7388                         TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7389                         thisjob->state = state;
7390 #ifdef JOBS
7391                         if (state == JOBSTOPPED) {
7392                                 set_curjob(thisjob, CUR_STOPPED);
7393                         }
7394 #endif
7395                 }
7396         }
7397
7398 out:
7399         INTON;
7400
7401         if (thisjob && thisjob == job) {
7402                 char s[48 + 1];
7403                 int len;
7404
7405                 len = sprint_status(s, status, 1);
7406                 if (len) {
7407                         s[len] = '\n';
7408                         s[len + 1] = 0;
7409                         out2str(s);
7410                 }
7411         }
7412         return pid;
7413 }
7414
7415
7416 /*
7417  * return 1 if there are stopped jobs, otherwise 0
7418  */
7419
7420 int
7421 stoppedjobs(void)
7422 {
7423         struct job *jp;
7424         int retval;
7425
7426         retval = 0;
7427         if (job_warning)
7428                 goto out;
7429         jp = curjob;
7430         if (jp && jp->state == JOBSTOPPED) {
7431                 out2str("You have stopped jobs.\n");
7432                 job_warning = 2;
7433                 retval++;
7434         }
7435
7436 out:
7437         return retval;
7438 }
7439
7440 /*
7441  * Return a string identifying a command (to be printed by the
7442  * jobs command).
7443  */
7444
7445 #if JOBS
7446 static char *cmdnextc;
7447
7448 static char *
7449 commandtext(union node *n)
7450 {
7451         char *name;
7452
7453         STARTSTACKSTR(cmdnextc);
7454         cmdtxt(n);
7455         name = stackblock();
7456         TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7457                 name, cmdnextc, cmdnextc));
7458         return savestr(name);
7459 }
7460
7461 static void
7462 cmdtxt(union node *n)
7463 {
7464         union node *np;
7465         struct nodelist *lp;
7466         const char *p;
7467         char s[2];
7468
7469         if (!n)
7470                 return;
7471         switch (n->type) {
7472         default:
7473 #if DEBUG
7474                 abort();
7475 #endif
7476         case NPIPE:
7477                 lp = n->npipe.cmdlist;
7478                 for (;;) {
7479                         cmdtxt(lp->n);
7480                         lp = lp->next;
7481                         if (!lp)
7482                                 break;
7483                         cmdputs(" | ");
7484                 }
7485                 break;
7486         case NSEMI:
7487                 p = "; ";
7488                 goto binop;
7489         case NAND:
7490                 p = " && ";
7491                 goto binop;
7492         case NOR:
7493                 p = " || ";
7494 binop:
7495                 cmdtxt(n->nbinary.ch1);
7496                 cmdputs(p);
7497                 n = n->nbinary.ch2;
7498                 goto donode;
7499         case NREDIR:
7500         case NBACKGND:
7501                 n = n->nredir.n;
7502                 goto donode;
7503         case NNOT:
7504                 cmdputs("!");
7505                 n = n->nnot.com;
7506 donode:
7507                 cmdtxt(n);
7508                 break;
7509         case NIF:
7510                 cmdputs("if ");
7511                 cmdtxt(n->nif.test);
7512                 cmdputs("; then ");
7513                 n = n->nif.ifpart;
7514                 if (n->nif.elsepart) {
7515                         cmdtxt(n);
7516                         cmdputs("; else ");
7517                         n = n->nif.elsepart;
7518                 }
7519                 p = "; fi";
7520                 goto dotail;
7521         case NSUBSHELL:
7522                 cmdputs("(");
7523                 n = n->nredir.n;
7524                 p = ")";
7525                 goto dotail;
7526         case NWHILE:
7527                 p = "while ";
7528                 goto until;
7529         case NUNTIL:
7530                 p = "until ";
7531 until:
7532                 cmdputs(p);
7533                 cmdtxt(n->nbinary.ch1);
7534                 n = n->nbinary.ch2;
7535                 p = "; done";
7536 dodo:
7537                 cmdputs("; do ");
7538 dotail:
7539                 cmdtxt(n);
7540                 goto dotail2;
7541         case NFOR:
7542                 cmdputs("for ");
7543                 cmdputs(n->nfor.var);
7544                 cmdputs(" in ");
7545                 cmdlist(n->nfor.args, 1);
7546                 n = n->nfor.body;
7547                 p = "; done";
7548                 goto dodo;
7549         case NDEFUN:
7550                 cmdputs(n->narg.text);
7551                 p = "() { ... }";
7552                 goto dotail2;
7553         case NCMD:
7554                 cmdlist(n->ncmd.args, 1);
7555                 cmdlist(n->ncmd.redirect, 0);
7556                 break;
7557         case NARG:
7558                 p = n->narg.text;
7559 dotail2:
7560                 cmdputs(p);
7561                 break;
7562         case NHERE:
7563         case NXHERE:
7564                 p = "<<...";
7565                 goto dotail2;
7566         case NCASE:
7567                 cmdputs("case ");
7568                 cmdputs(n->ncase.expr->narg.text);
7569                 cmdputs(" in ");
7570                 for (np = n->ncase.cases; np; np = np->nclist.next) {
7571                         cmdtxt(np->nclist.pattern);
7572                         cmdputs(") ");
7573                         cmdtxt(np->nclist.body);
7574                         cmdputs(";; ");
7575                 }
7576                 p = "esac";
7577                 goto dotail2;
7578         case NTO:
7579                 p = ">";
7580                 goto redir;
7581         case NCLOBBER:
7582                 p = ">|";
7583                 goto redir;
7584         case NAPPEND:
7585                 p = ">>";
7586                 goto redir;
7587         case NTOFD:
7588                 p = ">&";
7589                 goto redir;
7590         case NFROM:
7591                 p = "<";
7592                 goto redir;
7593         case NFROMFD:
7594                 p = "<&";
7595                 goto redir;
7596         case NFROMTO:
7597                 p = "<>";
7598 redir:
7599                 s[0] = n->nfile.fd + '0';
7600                 s[1] = '\0';
7601                 cmdputs(s);
7602                 cmdputs(p);
7603                 if (n->type == NTOFD || n->type == NFROMFD) {
7604                         s[0] = n->ndup.dupfd + '0';
7605                         p = s;
7606                         goto dotail2;
7607                 } else {
7608                         n = n->nfile.fname;
7609                         goto donode;
7610                 }
7611         }
7612 }
7613
7614 static void
7615 cmdlist(union node *np, int sep)
7616 {
7617         for (; np; np = np->narg.next) {
7618                 if (!sep)
7619                         cmdputs(spcstr);
7620                 cmdtxt(np);
7621                 if (sep && np->narg.next)
7622                         cmdputs(spcstr);
7623         }
7624 }
7625
7626 static void
7627 cmdputs(const char *s)
7628 {
7629         const char *p, *str;
7630         char c, cc[2] = " ";
7631         char *nextc;
7632         int subtype = 0;
7633         int quoted = 0;
7634         static const char vstype[VSTYPE + 1][4] = {
7635                 "", "}", "-", "+", "?", "=",
7636                 "%", "%%", "#", "##"
7637         };
7638         nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7639         p = s;
7640         while ((c = *p++) != 0) {
7641                 str = 0;
7642                 switch (c) {
7643                 case CTLESC:
7644                         c = *p++;
7645                         break;
7646                 case CTLVAR:
7647                         subtype = *p++;
7648                         if ((subtype & VSTYPE) == VSLENGTH)
7649                                 str = "${#";
7650                         else
7651                                 str = "${";
7652                         if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7653                                 quoted ^= 1;
7654                                 c = '"';
7655                         } else
7656                                 goto dostr;
7657                         break;
7658                 case CTLENDVAR:
7659                         str = "\"}" + !(quoted & 1);
7660                         quoted >>= 1;
7661                         subtype = 0;
7662                         goto dostr;
7663                 case CTLBACKQ:
7664                         str = "$(...)";
7665                         goto dostr;
7666                 case CTLBACKQ+CTLQUOTE:
7667                         str = "\"$(...)\"";
7668                         goto dostr;
7669 #ifdef CONFIG_ASH_MATH_SUPPORT
7670                 case CTLARI:
7671                         str = "$((";
7672                         goto dostr;
7673                 case CTLENDARI:
7674                         str = "))";
7675                         goto dostr;
7676 #endif
7677                 case CTLQUOTEMARK:
7678                         quoted ^= 1;
7679                         c = '"';
7680                         break;
7681                 case '=':
7682                         if (subtype == 0)
7683                                 break;
7684                         if ((subtype & VSTYPE) != VSNORMAL)
7685                                 quoted <<= 1;
7686                         str = vstype[subtype & VSTYPE];
7687                         if (subtype & VSNUL)
7688                                 c = ':';
7689                         else
7690                                 goto checkstr;
7691                         break;
7692                 case '\'':
7693                 case '\\':
7694                 case '"':
7695                 case '$':
7696                         /* These can only happen inside quotes */
7697                         cc[0] = c;
7698                         str = cc;
7699                         c = '\\';
7700                         break;
7701                 default:
7702                         break;
7703                 }
7704                 USTPUTC(c, nextc);
7705 checkstr:
7706                 if (!str)
7707                         continue;
7708 dostr:
7709                 while ((c = *str++)) {
7710                         USTPUTC(c, nextc);
7711                 }
7712         }
7713         if (quoted & 1) {
7714                 USTPUTC('"', nextc);
7715         }
7716         *nextc = 0;
7717         cmdnextc = nextc;
7718 }
7719
7720
7721 static void
7722 showpipe(struct job *jp, FILE *out)
7723 {
7724         struct procstat *sp;
7725         struct procstat *spend;
7726
7727         spend = jp->ps + jp->nprocs;
7728         for (sp = jp->ps + 1; sp < spend; sp++)
7729                 fprintf(out, " | %s", sp->cmd);
7730         outcslow('\n', out);
7731         flushall();
7732 }
7733
7734 static void
7735 xtcsetpgrp(int fd, pid_t pgrp)
7736 {
7737         if (tcsetpgrp(fd, pgrp))
7738                 error("Cannot set tty process group (%m)");
7739 }
7740 #endif /* JOBS */
7741
7742 static int
7743 getstatus(struct job *job) {
7744         int status;
7745         int retval;
7746
7747         status = job->ps[job->nprocs - 1].status;
7748         retval = WEXITSTATUS(status);
7749         if (!WIFEXITED(status)) {
7750 #if JOBS
7751                 retval = WSTOPSIG(status);
7752                 if (!WIFSTOPPED(status))
7753 #endif
7754                 {
7755                         /* XXX: limits number of signals */
7756                         retval = WTERMSIG(status);
7757 #if JOBS
7758                         if (retval == SIGINT)
7759                                 job->sigint = 1;
7760 #endif
7761                 }
7762                 retval += 128;
7763         }
7764         TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7765                 jobno(job), job->nprocs, status, retval));
7766         return retval;
7767 }
7768
7769 #ifdef CONFIG_ASH_MAIL
7770 /*      $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $       */
7771
7772 /*
7773  * Routines to check for mail.  (Perhaps make part of main.c?)
7774  */
7775
7776 #define MAXMBOXES 10
7777
7778 /* times of mailboxes */
7779 static time_t mailtime[MAXMBOXES];
7780 /* Set if MAIL or MAILPATH is changed. */
7781 static int mail_var_path_changed;
7782
7783
7784
7785 /*
7786  * Print appropriate message(s) if mail has arrived.
7787  * If mail_var_path_changed is set,
7788  * then the value of MAIL has mail_var_path_changed,
7789  * so we just update the values.
7790  */
7791
7792 static void
7793 chkmail(void)
7794 {
7795         const char *mpath;
7796         char *p;
7797         char *q;
7798         time_t *mtp;
7799         struct stackmark smark;
7800         struct stat statb;
7801
7802         setstackmark(&smark);
7803         mpath = mpathset() ? mpathval() : mailval();
7804         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7805                 p = padvance(&mpath, nullstr);
7806                 if (p == NULL)
7807                         break;
7808                 if (*p == '\0')
7809                         continue;
7810                 for (q = p ; *q ; q++);
7811 #ifdef DEBUG
7812                 if (q[-1] != '/')
7813                         abort();
7814 #endif
7815                 q[-1] = '\0';                   /* delete trailing '/' */
7816                 if (stat(p, &statb) < 0) {
7817                         *mtp = 0;
7818                         continue;
7819                 }
7820                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7821                         fprintf(
7822                                 stderr, snlfmt,
7823                                 pathopt ? pathopt : "you have mail"
7824                         );
7825                 }
7826                 *mtp = statb.st_mtime;
7827         }
7828         mail_var_path_changed = 0;
7829         popstackmark(&smark);
7830 }
7831
7832
7833 static void
7834 changemail(const char *val)
7835 {
7836         mail_var_path_changed++;
7837 }
7838
7839 #endif /* CONFIG_ASH_MAIL */
7840
7841 /*      $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $       */
7842
7843
7844 #if PROFILE
7845 static short profile_buf[16384];
7846 extern int etext();
7847 #endif
7848
7849 static int isloginsh;
7850
7851 static void read_profile(const char *);
7852
7853 /*
7854  * Main routine.  We initialize things, parse the arguments, execute
7855  * profiles if we're a login shell, and then call cmdloop to execute
7856  * commands.  The setjmp call sets up the location to jump to when an
7857  * exception occurs.  When an exception occurs the variable "state"
7858  * is used to figure out how far we had gotten.
7859  */
7860
7861 int
7862 ash_main(int argc, char **argv)
7863 {
7864         char *shinit;
7865         volatile int state;
7866         struct jmploc jmploc;
7867         struct stackmark smark;
7868
7869 #ifdef __GLIBC__
7870         dash_errno = __errno_location();
7871 #endif
7872
7873 #if PROFILE
7874         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7875 #endif
7876         state = 0;
7877         if (setjmp(jmploc.loc)) {
7878                 int status;
7879                 int e;
7880
7881                 reset();
7882
7883                 e = exception;
7884                 switch (exception) {
7885                 case EXEXEC:
7886                         status = exerrno;
7887                         break;
7888
7889                 case EXERROR:
7890                         status = 2;
7891                         break;
7892
7893                 default:
7894                         status = exitstatus;
7895                         break;
7896                 }
7897                 exitstatus = status;
7898
7899                 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7900                         exitshell();
7901
7902                 if (e == EXINT) {
7903                         outcslow('\n', stderr);
7904                 }
7905                 popstackmark(&smark);
7906                 FORCEINTON;                             /* enable interrupts */
7907                 if (state == 1)
7908                         goto state1;
7909                 else if (state == 2)
7910                         goto state2;
7911                 else if (state == 3)
7912                         goto state3;
7913                 else
7914                         goto state4;
7915         }
7916         handler = &jmploc;
7917 #ifdef DEBUG
7918         opentrace();
7919         trputs("Shell args:  ");  trargs(argv);
7920 #endif
7921         rootpid = getpid();
7922
7923 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7924         rseed = rootpid + ((time_t)time((time_t *)0));
7925 #endif
7926         rootshell = 1;
7927         init();
7928         setstackmark(&smark);
7929         procargs(argc, argv);
7930 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7931         if ( iflag ) {
7932                 const char *hp = lookupvar("HISTFILE");
7933
7934                 if(hp == NULL ) {
7935                         hp = lookupvar("HOME");
7936                         if(hp != NULL) {
7937                                 char *defhp = concat_path_file(hp, ".ash_history");
7938                                 setvar("HISTFILE", defhp, 0);
7939                                 free(defhp);
7940                         }
7941                 }
7942         }
7943 #endif
7944         if (argv[0] && argv[0][0] == '-')
7945                 isloginsh = 1;
7946         if (isloginsh) {
7947                 state = 1;
7948                 read_profile("/etc/profile");
7949 state1:
7950                 state = 2;
7951                 read_profile(".profile");
7952         }
7953 state2:
7954         state = 3;
7955         if (
7956 #ifndef linux
7957                 getuid() == geteuid() && getgid() == getegid() &&
7958 #endif
7959                 iflag
7960         ) {
7961                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7962                         read_profile(shinit);
7963                 }
7964         }
7965 state3:
7966         state = 4;
7967         if (minusc)
7968                 evalstring(minusc);
7969
7970         if (sflag || minusc == NULL) {
7971 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7972             if ( iflag ) {
7973                 const char *hp = lookupvar("HISTFILE");
7974
7975                 if(hp != NULL )
7976                         load_history ( hp );
7977             }
7978 #endif
7979 state4: /* XXX ??? - why isn't this before the "if" statement */
7980                 cmdloop(1);
7981         }
7982 #if PROFILE
7983         monitor(0);
7984 #endif
7985 #if GPROF
7986         {
7987                 extern void _mcleanup(void);
7988                 _mcleanup();
7989         }
7990 #endif
7991         exitshell();
7992         /* NOTREACHED */
7993 }
7994
7995
7996 /*
7997  * Read and execute commands.  "Top" is nonzero for the top level command
7998  * loop; it turns on prompting if the shell is interactive.
7999  */
8000
8001 static void
8002 cmdloop(int top)
8003 {
8004         union node *n;
8005         struct stackmark smark;
8006         int inter;
8007         int numeof = 0;
8008
8009         TRACE(("cmdloop(%d) called\n", top));
8010         for (;;) {
8011                 setstackmark(&smark);
8012                 if (pendingsigs)
8013                         dotrap();
8014 #if JOBS
8015                 if (jobctl)
8016                         showjobs(stderr, SHOW_CHANGED);
8017 #endif
8018                 inter = 0;
8019                 if (iflag && top) {
8020                         inter++;
8021 #ifdef CONFIG_ASH_MAIL
8022                         chkmail();
8023 #endif
8024                 }
8025                 n = parsecmd(inter);
8026                 /* showtree(n); DEBUG */
8027                 if (n == NEOF) {
8028                         if (!top || numeof >= 50)
8029                                 break;
8030                         if (!stoppedjobs()) {
8031                                 if (!Iflag)
8032                                         break;
8033                                 out2str("\nUse \"exit\" to leave shell.\n");
8034                         }
8035                         numeof++;
8036                 } else if (n != NULL && nflag == 0) {
8037                         job_warning = (job_warning == 2) ? 1 : 0;
8038                         numeof = 0;
8039                         evaltree(n, 0);
8040                 }
8041                 popstackmark(&smark);
8042                 if (evalskip) {
8043                         evalskip = 0;
8044                         break;
8045                 }
8046         }
8047 }
8048
8049
8050 /*
8051  * Read /etc/profile or .profile.  Return on error.
8052  */
8053
8054 static void
8055 read_profile(const char *name)
8056 {
8057         int fd;
8058         int xflag_set = 0;
8059         int vflag_set = 0;
8060
8061         INTOFF;
8062         if ((fd = open(name, O_RDONLY)) >= 0)
8063                 setinputfd(fd, 1);
8064         INTON;
8065         if (fd < 0)
8066                 return;
8067         /* -q turns off -x and -v just when executing init files */
8068         if (qflag)  {
8069             if (xflag)
8070                     xflag = 0, xflag_set = 1;
8071             if (vflag)
8072                     vflag = 0, vflag_set = 1;
8073         }
8074         cmdloop(0);
8075         if (qflag)  {
8076             if (xflag_set)
8077                     xflag = 1;
8078             if (vflag_set)
8079                     vflag = 1;
8080         }
8081         popfile();
8082 }
8083
8084
8085 /*
8086  * Read a file containing shell functions.
8087  */
8088
8089 static void
8090 readcmdfile(char *name)
8091 {
8092         int fd;
8093
8094         INTOFF;
8095         if ((fd = open(name, O_RDONLY)) >= 0)
8096                 setinputfd(fd, 1);
8097         else
8098                 error("Can't open %s", name);
8099         INTON;
8100         cmdloop(0);
8101         popfile();
8102 }
8103
8104
8105 /*
8106  * Take commands from a file.  To be compatible we should do a path
8107  * search for the file, which is necessary to find sub-commands.
8108  */
8109
8110 static inline char *
8111 find_dot_file(char *name)
8112 {
8113         char *fullname;
8114         const char *path = pathval();
8115         struct stat statb;
8116
8117         /* don't try this for absolute or relative paths */
8118         if (strchr(name, '/'))
8119                 return name;
8120
8121         while ((fullname = padvance(&path, name)) != NULL) {
8122                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8123                         /*
8124                          * Don't bother freeing here, since it will
8125                          * be freed by the caller.
8126                          */
8127                         return fullname;
8128                 }
8129                 stunalloc(fullname);
8130         }
8131
8132         /* not found in the PATH */
8133         error(not_found_msg, name);
8134         /* NOTREACHED */
8135 }
8136
8137 static int dotcmd(int argc, char **argv)
8138 {
8139         struct strlist *sp;
8140         volatile struct shparam saveparam;
8141
8142         exitstatus = 0;
8143
8144         for (sp = cmdenviron; sp; sp = sp->next)
8145                 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8146
8147         if (argc >= 2) {        /* That's what SVR2 does */
8148                 char *fullname;
8149                 struct stackmark smark;
8150
8151                 setstackmark(&smark);
8152                 fullname = find_dot_file(argv[1]);
8153
8154                 if (argc > 2) {
8155                         saveparam = shellparam;
8156                         shellparam.malloc = 0;
8157                         shellparam.nparam = argc - 2;
8158                         shellparam.p = argv + 2;
8159                 };
8160
8161                 setinputfile(fullname, 1);
8162                 commandname = fullname;
8163                 cmdloop(0);
8164                 popfile();
8165
8166                 if (argc > 2) {
8167                         freeparam(&shellparam);
8168                         shellparam = saveparam;
8169                 };
8170
8171                 popstackmark(&smark);
8172         }
8173         return exitstatus;
8174 }
8175
8176
8177 static int
8178 exitcmd(int argc, char **argv)
8179 {
8180         if (stoppedjobs())
8181                 return 0;
8182         if (argc > 1)
8183                 exitstatus = number(argv[1]);
8184         exraise(EXEXIT);
8185         /* NOTREACHED */
8186 }
8187
8188 #ifdef CONFIG_ASH_BUILTIN_ECHO
8189 static int
8190 echocmd(int argc, char **argv)
8191 {
8192         return bb_echo(argc, argv);
8193 }
8194 #endif
8195 /*      $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $        */
8196
8197 /*
8198  * Same for malloc, realloc, but returns an error when out of space.
8199  */
8200
8201 static pointer
8202 ckrealloc(pointer p, size_t nbytes)
8203 {
8204         p = realloc(p, nbytes);
8205         if (p == NULL)
8206                 error(bb_msg_memory_exhausted);
8207         return p;
8208 }
8209
8210 static pointer
8211 ckmalloc(size_t nbytes)
8212 {
8213         return ckrealloc(NULL, nbytes);
8214 }
8215
8216 /*
8217  * Make a copy of a string in safe storage.
8218  */
8219
8220 static char *
8221 savestr(const char *s)
8222 {
8223         char *p = strdup(s);
8224         if (!p)
8225                 error(bb_msg_memory_exhausted);
8226         return p;
8227 }
8228
8229
8230 /*
8231  * Parse trees for commands are allocated in lifo order, so we use a stack
8232  * to make this more efficient, and also to avoid all sorts of exception
8233  * handling code to handle interrupts in the middle of a parse.
8234  *
8235  * The size 504 was chosen because the Ultrix malloc handles that size
8236  * well.
8237  */
8238
8239
8240 static pointer
8241 stalloc(size_t nbytes)
8242 {
8243         char *p;
8244         size_t aligned;
8245
8246         aligned = SHELL_ALIGN(nbytes);
8247         if (aligned > stacknleft) {
8248                 size_t len;
8249                 size_t blocksize;
8250                 struct stack_block *sp;
8251
8252                 blocksize = aligned;
8253                 if (blocksize < MINSIZE)
8254                         blocksize = MINSIZE;
8255                 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8256                 if (len < blocksize)
8257                         error(bb_msg_memory_exhausted);
8258                 INTOFF;
8259                 sp = ckmalloc(len);
8260                 sp->prev = stackp;
8261                 stacknxt = sp->space;
8262                 stacknleft = blocksize;
8263                 sstrend = stacknxt + blocksize;
8264                 stackp = sp;
8265                 INTON;
8266         }
8267         p = stacknxt;
8268         stacknxt += aligned;
8269         stacknleft -= aligned;
8270         return p;
8271 }
8272
8273
8274 void
8275 stunalloc(pointer p)
8276 {
8277 #ifdef DEBUG
8278         if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8279                 write(2, "stunalloc\n", 10);
8280                 abort();
8281         }
8282 #endif
8283         stacknleft += stacknxt - (char *)p;
8284         stacknxt = p;
8285 }
8286
8287
8288 void
8289 setstackmark(struct stackmark *mark)
8290 {
8291         mark->stackp = stackp;
8292         mark->stacknxt = stacknxt;
8293         mark->stacknleft = stacknleft;
8294         mark->marknext = markp;
8295         markp = mark;
8296 }
8297
8298
8299 void
8300 popstackmark(struct stackmark *mark)
8301 {
8302         struct stack_block *sp;
8303
8304         INTOFF;
8305         markp = mark->marknext;
8306         while (stackp != mark->stackp) {
8307                 sp = stackp;
8308                 stackp = sp->prev;
8309                 ckfree(sp);
8310         }
8311         stacknxt = mark->stacknxt;
8312         stacknleft = mark->stacknleft;
8313         sstrend = mark->stacknxt + mark->stacknleft;
8314         INTON;
8315 }
8316
8317
8318 /*
8319  * When the parser reads in a string, it wants to stick the string on the
8320  * stack and only adjust the stack pointer when it knows how big the
8321  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
8322  * of space on top of the stack and stackblocklen returns the length of
8323  * this block.  Growstackblock will grow this space by at least one byte,
8324  * possibly moving it (like realloc).  Grabstackblock actually allocates the
8325  * part of the block that has been used.
8326  */
8327
8328 void
8329 growstackblock(void)
8330 {
8331         size_t newlen;
8332
8333         newlen = stacknleft * 2;
8334         if (newlen < stacknleft)
8335                 error(bb_msg_memory_exhausted);
8336         if (newlen < 128)
8337                 newlen += 128;
8338
8339         if (stacknxt == stackp->space && stackp != &stackbase) {
8340                 struct stack_block *oldstackp;
8341                 struct stackmark *xmark;
8342                 struct stack_block *sp;
8343                 struct stack_block *prevstackp;
8344                 size_t grosslen;
8345
8346                 INTOFF;
8347                 oldstackp = stackp;
8348                 sp = stackp;
8349                 prevstackp = sp->prev;
8350                 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8351                 sp = ckrealloc((pointer)sp, grosslen);
8352                 sp->prev = prevstackp;
8353                 stackp = sp;
8354                 stacknxt = sp->space;
8355                 stacknleft = newlen;
8356                 sstrend = sp->space + newlen;
8357
8358                 /*
8359                  * Stack marks pointing to the start of the old block
8360                  * must be relocated to point to the new block
8361                  */
8362                 xmark = markp;
8363                 while (xmark != NULL && xmark->stackp == oldstackp) {
8364                         xmark->stackp = stackp;
8365                         xmark->stacknxt = stacknxt;
8366                         xmark->stacknleft = stacknleft;
8367                         xmark = xmark->marknext;
8368                 }
8369                 INTON;
8370         } else {
8371                 char *oldspace = stacknxt;
8372                 int oldlen = stacknleft;
8373                 char *p = stalloc(newlen);
8374
8375                 /* free the space we just allocated */
8376                 stacknxt = memcpy(p, oldspace, oldlen);
8377                 stacknleft += newlen;
8378         }
8379 }
8380
8381 static inline void
8382 grabstackblock(size_t len)
8383 {
8384         len = SHELL_ALIGN(len);
8385         stacknxt += len;
8386         stacknleft -= len;
8387 }
8388
8389 /*
8390  * The following routines are somewhat easier to use than the above.
8391  * The user declares a variable of type STACKSTR, which may be declared
8392  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
8393  * the user uses the macro STPUTC to add characters to the string.  In
8394  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8395  * grown as necessary.  When the user is done, she can just leave the
8396  * string there and refer to it using stackblock().  Or she can allocate
8397  * the space for it using grabstackstr().  If it is necessary to allow
8398  * someone else to use the stack temporarily and then continue to grow
8399  * the string, the user should use grabstack to allocate the space, and
8400  * then call ungrabstr(p) to return to the previous mode of operation.
8401  *
8402  * USTPUTC is like STPUTC except that it doesn't check for overflow.
8403  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8404  * is space for at least one character.
8405  */
8406
8407 void *
8408 growstackstr(void)
8409 {
8410         size_t len = stackblocksize();
8411         if (herefd >= 0 && len >= 1024) {
8412                 bb_full_write(herefd, stackblock(), len);
8413                 return stackblock();
8414         }
8415         growstackblock();
8416         return stackblock() + len;
8417 }
8418
8419 /*
8420  * Called from CHECKSTRSPACE.
8421  */
8422
8423 char *
8424 makestrspace(size_t newlen, char *p)
8425 {
8426         size_t len = p - stacknxt;
8427         size_t size = stackblocksize();
8428
8429         for (;;) {
8430                 size_t nleft;
8431
8432                 size = stackblocksize();
8433                 nleft = size - len;
8434                 if (nleft >= newlen)
8435                         break;
8436                 growstackblock();
8437         }
8438         return stackblock() + len;
8439 }
8440
8441 char *
8442 stnputs(const char *s, size_t n, char *p)
8443 {
8444         p = makestrspace(n, p);
8445         p = mempcpy(p, s, n);
8446         return p;
8447 }
8448
8449 char *
8450 stputs(const char *s, char *p)
8451 {
8452         return stnputs(s, strlen(s), p);
8453 }
8454
8455 /*      $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $   */
8456
8457 /*
8458  * String functions.
8459  *
8460  *      number(s)               Convert a string of digits to an integer.
8461  *      is_number(s)            Return true if s is a string of digits.
8462  */
8463
8464 /*
8465  * prefix -- see if pfx is a prefix of string.
8466  */
8467
8468 char *
8469 prefix(const char *string, const char *pfx)
8470 {
8471         while (*pfx) {
8472                 if (*pfx++ != *string++)
8473                         return 0;
8474         }
8475         return (char *) string;
8476 }
8477
8478
8479 /*
8480  * Convert a string of digits to an integer, printing an error message on
8481  * failure.
8482  */
8483
8484 int
8485 number(const char *s)
8486 {
8487
8488         if (! is_number(s))
8489                 error(illnum, s);
8490         return atoi(s);
8491 }
8492
8493
8494 /*
8495  * Check for a valid number.  This should be elsewhere.
8496  */
8497
8498 int
8499 is_number(const char *p)
8500 {
8501         do {
8502                 if (! is_digit(*p))
8503                         return 0;
8504         } while (*++p != '\0');
8505         return 1;
8506 }
8507
8508
8509 /*
8510  * Produce a possibly single quoted string suitable as input to the shell.
8511  * The return string is allocated on the stack.
8512  */
8513
8514 char *
8515 single_quote(const char *s) {
8516         char *p;
8517
8518         STARTSTACKSTR(p);
8519
8520         do {
8521                 char *q;
8522                 size_t len;
8523
8524                 len = strchrnul(s, '\'') - s;
8525
8526                 q = p = makestrspace(len + 3, p);
8527
8528                 *q++ = '\'';
8529                 q = mempcpy(q, s, len);
8530                 *q++ = '\'';
8531                 s += len;
8532
8533                 STADJUST(q - p, p);
8534
8535                 len = strspn(s, "'");
8536                 if (!len)
8537                         break;
8538
8539                 q = p = makestrspace(len + 3, p);
8540
8541                 *q++ = '"';
8542                 q = mempcpy(q, s, len);
8543                 *q++ = '"';
8544                 s += len;
8545
8546                 STADJUST(q - p, p);
8547         } while (*s);
8548
8549         USTPUTC(0, p);
8550
8551         return stackblock();
8552 }
8553
8554 /*
8555  * Like strdup but works with the ash stack.
8556  */
8557
8558 char *
8559 sstrdup(const char *p)
8560 {
8561         size_t len = strlen(p) + 1;
8562         return memcpy(stalloc(len), p, len);
8563 }
8564
8565
8566 static void
8567 calcsize(union node *n)
8568 {
8569       if (n == NULL)
8570             return;
8571       funcblocksize += nodesize[n->type];
8572       switch (n->type) {
8573       case NCMD:
8574             calcsize(n->ncmd.redirect);
8575             calcsize(n->ncmd.args);
8576             calcsize(n->ncmd.assign);
8577             break;
8578       case NPIPE:
8579             sizenodelist(n->npipe.cmdlist);
8580             break;
8581       case NREDIR:
8582       case NBACKGND:
8583       case NSUBSHELL:
8584             calcsize(n->nredir.redirect);
8585             calcsize(n->nredir.n);
8586             break;
8587       case NAND:
8588       case NOR:
8589       case NSEMI:
8590       case NWHILE:
8591       case NUNTIL:
8592             calcsize(n->nbinary.ch2);
8593             calcsize(n->nbinary.ch1);
8594             break;
8595       case NIF:
8596             calcsize(n->nif.elsepart);
8597             calcsize(n->nif.ifpart);
8598             calcsize(n->nif.test);
8599             break;
8600       case NFOR:
8601             funcstringsize += strlen(n->nfor.var) + 1;
8602             calcsize(n->nfor.body);
8603             calcsize(n->nfor.args);
8604             break;
8605       case NCASE:
8606             calcsize(n->ncase.cases);
8607             calcsize(n->ncase.expr);
8608             break;
8609       case NCLIST:
8610             calcsize(n->nclist.body);
8611             calcsize(n->nclist.pattern);
8612             calcsize(n->nclist.next);
8613             break;
8614       case NDEFUN:
8615       case NARG:
8616             sizenodelist(n->narg.backquote);
8617             funcstringsize += strlen(n->narg.text) + 1;
8618             calcsize(n->narg.next);
8619             break;
8620       case NTO:
8621       case NCLOBBER:
8622       case NFROM:
8623       case NFROMTO:
8624       case NAPPEND:
8625             calcsize(n->nfile.fname);
8626             calcsize(n->nfile.next);
8627             break;
8628       case NTOFD:
8629       case NFROMFD:
8630             calcsize(n->ndup.vname);
8631             calcsize(n->ndup.next);
8632             break;
8633       case NHERE:
8634       case NXHERE:
8635             calcsize(n->nhere.doc);
8636             calcsize(n->nhere.next);
8637             break;
8638       case NNOT:
8639             calcsize(n->nnot.com);
8640             break;
8641       };
8642 }
8643
8644
8645 static void
8646 sizenodelist(struct nodelist *lp)
8647 {
8648         while (lp) {
8649                 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8650                 calcsize(lp->n);
8651                 lp = lp->next;
8652         }
8653 }
8654
8655
8656 static union node *
8657 copynode(union node *n)
8658 {
8659       union node *new;
8660
8661       if (n == NULL)
8662             return NULL;
8663       new = funcblock;
8664       funcblock = (char *) funcblock + nodesize[n->type];
8665       switch (n->type) {
8666       case NCMD:
8667             new->ncmd.redirect = copynode(n->ncmd.redirect);
8668             new->ncmd.args = copynode(n->ncmd.args);
8669             new->ncmd.assign = copynode(n->ncmd.assign);
8670             break;
8671       case NPIPE:
8672             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8673             new->npipe.backgnd = n->npipe.backgnd;
8674             break;
8675       case NREDIR:
8676       case NBACKGND:
8677       case NSUBSHELL:
8678             new->nredir.redirect = copynode(n->nredir.redirect);
8679             new->nredir.n = copynode(n->nredir.n);
8680             break;
8681       case NAND:
8682       case NOR:
8683       case NSEMI:
8684       case NWHILE:
8685       case NUNTIL:
8686             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8687             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8688             break;
8689       case NIF:
8690             new->nif.elsepart = copynode(n->nif.elsepart);
8691             new->nif.ifpart = copynode(n->nif.ifpart);
8692             new->nif.test = copynode(n->nif.test);
8693             break;
8694       case NFOR:
8695             new->nfor.var = nodesavestr(n->nfor.var);
8696             new->nfor.body = copynode(n->nfor.body);
8697             new->nfor.args = copynode(n->nfor.args);
8698             break;
8699       case NCASE:
8700             new->ncase.cases = copynode(n->ncase.cases);
8701             new->ncase.expr = copynode(n->ncase.expr);
8702             break;
8703       case NCLIST:
8704             new->nclist.body = copynode(n->nclist.body);
8705             new->nclist.pattern = copynode(n->nclist.pattern);
8706             new->nclist.next = copynode(n->nclist.next);
8707             break;
8708       case NDEFUN:
8709       case NARG:
8710             new->narg.backquote = copynodelist(n->narg.backquote);
8711             new->narg.text = nodesavestr(n->narg.text);
8712             new->narg.next = copynode(n->narg.next);
8713             break;
8714       case NTO:
8715       case NCLOBBER:
8716       case NFROM:
8717       case NFROMTO:
8718       case NAPPEND:
8719             new->nfile.fname = copynode(n->nfile.fname);
8720             new->nfile.fd = n->nfile.fd;
8721             new->nfile.next = copynode(n->nfile.next);
8722             break;
8723       case NTOFD:
8724       case NFROMFD:
8725             new->ndup.vname = copynode(n->ndup.vname);
8726             new->ndup.dupfd = n->ndup.dupfd;
8727             new->ndup.fd = n->ndup.fd;
8728             new->ndup.next = copynode(n->ndup.next);
8729             break;
8730       case NHERE:
8731       case NXHERE:
8732             new->nhere.doc = copynode(n->nhere.doc);
8733             new->nhere.fd = n->nhere.fd;
8734             new->nhere.next = copynode(n->nhere.next);
8735             break;
8736       case NNOT:
8737             new->nnot.com = copynode(n->nnot.com);
8738             break;
8739       };
8740       new->type = n->type;
8741         return new;
8742 }
8743
8744
8745 static struct nodelist *
8746 copynodelist(struct nodelist *lp)
8747 {
8748         struct nodelist *start;
8749         struct nodelist **lpp;
8750
8751         lpp = &start;
8752         while (lp) {
8753                 *lpp = funcblock;
8754                 funcblock = (char *) funcblock +
8755                     SHELL_ALIGN(sizeof(struct nodelist));
8756                 (*lpp)->n = copynode(lp->n);
8757                 lp = lp->next;
8758                 lpp = &(*lpp)->next;
8759         }
8760         *lpp = NULL;
8761         return start;
8762 }
8763
8764
8765 static char *
8766 nodesavestr(char   *s)
8767 {
8768         char   *rtn = funcstring;
8769
8770         funcstring = stpcpy(funcstring, s) + 1;
8771         return rtn;
8772 }
8773
8774
8775 /*
8776  * Free a parse tree.
8777  */
8778
8779 static void
8780 freefunc(struct funcnode *f)
8781 {
8782         if (f && --f->count < 0)
8783                 ckfree(f);
8784 }
8785
8786
8787 static void options(int);
8788 static void setoption(int, int);
8789
8790
8791 /*
8792  * Process the shell command line arguments.
8793  */
8794
8795 void
8796 procargs(int argc, char **argv)
8797 {
8798         int i;
8799         const char *xminusc;
8800         char **xargv;
8801
8802         xargv = argv;
8803         arg0 = xargv[0];
8804         if (argc > 0)
8805                 xargv++;
8806         for (i = 0; i < NOPTS; i++)
8807                 optlist[i] = 2;
8808         argptr = xargv;
8809         options(1);
8810         xargv = argptr;
8811         xminusc = minusc;
8812         if (*xargv == NULL) {
8813                 if (xminusc)
8814                         error("-c requires an argument");
8815                 sflag = 1;
8816         }
8817         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8818                 iflag = 1;
8819         if (mflag == 2)
8820                 mflag = iflag;
8821         for (i = 0; i < NOPTS; i++)
8822                 if (optlist[i] == 2)
8823                         optlist[i] = 0;
8824 #if DEBUG == 2
8825         debug = 1;
8826 #endif
8827         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8828         if (xminusc) {
8829                 minusc = *xargv++;
8830                 if (*xargv)
8831                         goto setarg0;
8832         } else if (!sflag) {
8833                 setinputfile(*xargv, 0);
8834 setarg0:
8835                 arg0 = *xargv++;
8836                 commandname = arg0;
8837         }
8838
8839         shellparam.p = xargv;
8840 #ifdef CONFIG_ASH_GETOPTS
8841         shellparam.optind = 1;
8842         shellparam.optoff = -1;
8843 #endif
8844         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8845         while (*xargv) {
8846                 shellparam.nparam++;
8847                 xargv++;
8848         }
8849         optschanged();
8850 }
8851
8852
8853 void
8854 optschanged(void)
8855 {
8856 #ifdef DEBUG
8857         opentrace();
8858 #endif
8859         setinteractive(iflag);
8860         setjobctl(mflag);
8861         setvimode(viflag);
8862 }
8863
8864 static inline void
8865 minus_o(char *name, int val)
8866 {
8867         int i;
8868
8869         if (name == NULL) {
8870                 out1str("Current option settings\n");
8871                 for (i = 0; i < NOPTS; i++)
8872                         out1fmt("%-16s%s\n", optnames(i),
8873                                 optlist[i] ? "on" : "off");
8874         } else {
8875                 for (i = 0; i < NOPTS; i++)
8876                         if (equal(name, optnames(i))) {
8877                                 optlist[i] = val;
8878                                 return;
8879                         }
8880                 error("Illegal option -o %s", name);
8881         }
8882 }
8883
8884 /*
8885  * Process shell options.  The global variable argptr contains a pointer
8886  * to the argument list; we advance it past the options.
8887  */
8888
8889 static void
8890 options(int cmdline)
8891 {
8892         char *p;
8893         int val;
8894         int c;
8895
8896         if (cmdline)
8897                 minusc = NULL;
8898         while ((p = *argptr) != NULL) {
8899                 argptr++;
8900                 if ((c = *p++) == '-') {
8901                         val = 1;
8902                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8903                                 if (!cmdline) {
8904                                         /* "-" means turn off -x and -v */
8905                                         if (p[0] == '\0')
8906                                                 xflag = vflag = 0;
8907                                         /* "--" means reset params */
8908                                         else if (*argptr == NULL)
8909                                                 setparam(argptr);
8910                                 }
8911                                 break;    /* "-" or  "--" terminates options */
8912                         }
8913                 } else if (c == '+') {
8914                         val = 0;
8915                 } else {
8916                         argptr--;
8917                         break;
8918                 }
8919                 while ((c = *p++) != '\0') {
8920                         if (c == 'c' && cmdline) {
8921                                 minusc = p;     /* command is after shell args*/
8922                         } else if (c == 'o') {
8923                                 minus_o(*argptr, val);
8924                                 if (*argptr)
8925                                         argptr++;
8926                         } else if (cmdline && (c == '-')) {     // long options
8927                                 if (strcmp(p, "login") == 0)
8928                                         isloginsh = 1;
8929                                 break;
8930                         } else {
8931                                 setoption(c, val);
8932                         }
8933                 }
8934         }
8935 }
8936
8937
8938 static void
8939 setoption(int flag, int val)
8940 {
8941         int i;
8942
8943         for (i = 0; i < NOPTS; i++)
8944                 if (optletters(i) == flag) {
8945                         optlist[i] = val;
8946                         return;
8947                 }
8948         error("Illegal option -%c", flag);
8949         /* NOTREACHED */
8950 }
8951
8952
8953
8954 /*
8955  * Set the shell parameters.
8956  */
8957
8958 void
8959 setparam(char **argv)
8960 {
8961         char **newparam;
8962         char **ap;
8963         int nparam;
8964
8965         for (nparam = 0 ; argv[nparam] ; nparam++);
8966         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8967         while (*argv) {
8968                 *ap++ = savestr(*argv++);
8969         }
8970         *ap = NULL;
8971         freeparam(&shellparam);
8972         shellparam.malloc = 1;
8973         shellparam.nparam = nparam;
8974         shellparam.p = newparam;
8975 #ifdef CONFIG_ASH_GETOPTS
8976         shellparam.optind = 1;
8977         shellparam.optoff = -1;
8978 #endif
8979 }
8980
8981
8982 /*
8983  * Free the list of positional parameters.
8984  */
8985
8986 void
8987 freeparam(volatile struct shparam *param)
8988 {
8989         char **ap;
8990
8991         if (param->malloc) {
8992                 for (ap = param->p ; *ap ; ap++)
8993                         ckfree(*ap);
8994                 ckfree(param->p);
8995         }
8996 }
8997
8998
8999
9000 /*
9001  * The shift builtin command.
9002  */
9003
9004 int
9005 shiftcmd(int argc, char **argv)
9006 {
9007         int n;
9008         char **ap1, **ap2;
9009
9010         n = 1;
9011         if (argc > 1)
9012                 n = number(argv[1]);
9013         if (n > shellparam.nparam)
9014                 error("can't shift that many");
9015         INTOFF;
9016         shellparam.nparam -= n;
9017         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9018                 if (shellparam.malloc)
9019                         ckfree(*ap1);
9020         }
9021         ap2 = shellparam.p;
9022         while ((*ap2++ = *ap1++) != NULL);
9023 #ifdef CONFIG_ASH_GETOPTS
9024         shellparam.optind = 1;
9025         shellparam.optoff = -1;
9026 #endif
9027         INTON;
9028         return 0;
9029 }
9030
9031
9032
9033 /*
9034  * The set command builtin.
9035  */
9036
9037 int
9038 setcmd(int argc, char **argv)
9039 {
9040         if (argc == 1)
9041                 return showvars(nullstr, 0, VUNSET);
9042         INTOFF;
9043         options(0);
9044         optschanged();
9045         if (*argptr != NULL) {
9046                 setparam(argptr);
9047         }
9048         INTON;
9049         return 0;
9050 }
9051
9052
9053 #ifdef CONFIG_ASH_GETOPTS
9054 static void
9055 getoptsreset(value)
9056         const char *value;
9057 {
9058         shellparam.optind = number(value);
9059         shellparam.optoff = -1;
9060 }
9061 #endif
9062
9063 #ifdef CONFIG_LOCALE_SUPPORT
9064 static void change_lc_all(const char *value)
9065 {
9066         if (value != 0 && *value != 0)
9067                 setlocale(LC_ALL, value);
9068 }
9069
9070 static void change_lc_ctype(const char *value)
9071 {
9072         if (value != 0 && *value != 0)
9073                 setlocale(LC_CTYPE, value);
9074 }
9075
9076 #endif
9077
9078 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9079 /* Roughly copied from bash.. */
9080 static void change_random(const char *value)
9081 {
9082         if(value == NULL) {
9083                 /* "get", generate */
9084                 char buf[16];
9085
9086                 rseed = rseed * 1103515245 + 12345;
9087                 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9088                 /* set without recursion */
9089                 setvar(vrandom.text, buf, VNOFUNC);
9090                 vrandom.flags &= ~VNOFUNC;
9091         } else {
9092                 /* set/reset */
9093                 rseed = strtoul(value, (char **)NULL, 10);
9094         }
9095 }
9096 #endif
9097
9098
9099 #ifdef CONFIG_ASH_GETOPTS
9100 static int
9101 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9102 {
9103         char *p, *q;
9104         char c = '?';
9105         int done = 0;
9106         int err = 0;
9107         char s[12];
9108         char **optnext;
9109
9110         if(*param_optind < 1)
9111                 return 1;
9112         optnext = optfirst + *param_optind - 1;
9113
9114         if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9115                 p = NULL;
9116         else
9117                 p = optnext[-1] + *optoff;
9118         if (p == NULL || *p == '\0') {
9119                 /* Current word is done, advance */
9120                 p = *optnext;
9121                 if (p == NULL || *p != '-' || *++p == '\0') {
9122 atend:
9123                         p = NULL;
9124                         done = 1;
9125                         goto out;
9126                 }
9127                 optnext++;
9128                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9129                         goto atend;
9130         }
9131
9132         c = *p++;
9133         for (q = optstr; *q != c; ) {
9134                 if (*q == '\0') {
9135                         if (optstr[0] == ':') {
9136                                 s[0] = c;
9137                                 s[1] = '\0';
9138                                 err |= setvarsafe("OPTARG", s, 0);
9139                         } else {
9140                                 fprintf(stderr, "Illegal option -%c\n", c);
9141                                 (void) unsetvar("OPTARG");
9142                         }
9143                         c = '?';
9144                         goto out;
9145                 }
9146                 if (*++q == ':')
9147                         q++;
9148         }
9149
9150         if (*++q == ':') {
9151                 if (*p == '\0' && (p = *optnext) == NULL) {
9152                         if (optstr[0] == ':') {
9153                                 s[0] = c;
9154                                 s[1] = '\0';
9155                                 err |= setvarsafe("OPTARG", s, 0);
9156                                 c = ':';
9157                         } else {
9158                                 fprintf(stderr, "No arg for -%c option\n", c);
9159                                 (void) unsetvar("OPTARG");
9160                                 c = '?';
9161                         }
9162                         goto out;
9163                 }
9164
9165                 if (p == *optnext)
9166                         optnext++;
9167                 err |= setvarsafe("OPTARG", p, 0);
9168                 p = NULL;
9169         } else
9170                 err |= setvarsafe("OPTARG", nullstr, 0);
9171
9172 out:
9173         *optoff = p ? p - *(optnext - 1) : -1;
9174         *param_optind = optnext - optfirst + 1;
9175         fmtstr(s, sizeof(s), "%d", *param_optind);
9176         err |= setvarsafe("OPTIND", s, VNOFUNC);
9177         s[0] = c;
9178         s[1] = '\0';
9179         err |= setvarsafe(optvar, s, 0);
9180         if (err) {
9181                 *param_optind = 1;
9182                 *optoff = -1;
9183                 flushall();
9184                 exraise(EXERROR);
9185         }
9186         return done;
9187 }
9188
9189 /*
9190  * The getopts builtin.  Shellparam.optnext points to the next argument
9191  * to be processed.  Shellparam.optptr points to the next character to
9192  * be processed in the current argument.  If shellparam.optnext is NULL,
9193  * then it's the first time getopts has been called.
9194  */
9195
9196 int
9197 getoptscmd(int argc, char **argv)
9198 {
9199         char **optbase;
9200
9201         if (argc < 3)
9202                 error("Usage: getopts optstring var [arg]");
9203         else if (argc == 3) {
9204                 optbase = shellparam.p;
9205                 if (shellparam.optind > shellparam.nparam + 1) {
9206                         shellparam.optind = 1;
9207                         shellparam.optoff = -1;
9208                 }
9209         }
9210         else {
9211                 optbase = &argv[3];
9212                 if (shellparam.optind > argc - 2) {
9213                         shellparam.optind = 1;
9214                         shellparam.optoff = -1;
9215                 }
9216         }
9217
9218         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9219                        &shellparam.optoff);
9220 }
9221 #endif /* CONFIG_ASH_GETOPTS */
9222
9223 /*
9224  * XXX - should get rid of.  have all builtins use getopt(3).  the
9225  * library getopt must have the BSD extension static variable "optreset"
9226  * otherwise it can't be used within the shell safely.
9227  *
9228  * Standard option processing (a la getopt) for builtin routines.  The
9229  * only argument that is passed to nextopt is the option string; the
9230  * other arguments are unnecessary.  It return the character, or '\0' on
9231  * end of input.
9232  */
9233
9234 static int
9235 nextopt(const char *optstring)
9236 {
9237         char *p;
9238         const char *q;
9239         char c;
9240
9241         if ((p = optptr) == NULL || *p == '\0') {
9242                 p = *argptr;
9243                 if (p == NULL || *p != '-' || *++p == '\0')
9244                         return '\0';
9245                 argptr++;
9246                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9247                         return '\0';
9248         }
9249         c = *p++;
9250         for (q = optstring ; *q != c ; ) {
9251                 if (*q == '\0')
9252                         error("Illegal option -%c", c);
9253                 if (*++q == ':')
9254                         q++;
9255         }
9256         if (*++q == ':') {
9257                 if (*p == '\0' && (p = *argptr++) == NULL)
9258                         error("No arg for -%c option", c);
9259                 optionarg = p;
9260                 p = NULL;
9261         }
9262         optptr = p;
9263         return c;
9264 }
9265
9266
9267 /*      $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $     */
9268
9269 void
9270 outstr(const char *p, FILE *file)
9271 {
9272         INTOFF;
9273         fputs(p, file);
9274         INTON;
9275 }
9276
9277 void
9278 flushall(void)
9279 {
9280         INTOFF;
9281         fflush(stdout);
9282         fflush(stderr);
9283         INTON;
9284 }
9285
9286 void
9287 flusherr(void)
9288 {
9289         INTOFF;
9290         fflush(stderr);
9291         INTON;
9292 }
9293
9294 static void
9295 outcslow(int c, FILE *dest)
9296 {
9297         INTOFF;
9298         putc(c, dest);
9299         fflush(dest);
9300         INTON;
9301 }
9302
9303
9304 static int
9305 out1fmt(const char *fmt, ...)
9306 {
9307         va_list ap;
9308         int r;
9309
9310         INTOFF;
9311         va_start(ap, fmt);
9312         r = vprintf(fmt, ap);
9313         va_end(ap);
9314         INTON;
9315         return r;
9316 }
9317
9318
9319 int
9320 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9321 {
9322         va_list ap;
9323         int ret;
9324
9325         va_start(ap, fmt);
9326         INTOFF;
9327         ret = vsnprintf(outbuf, length, fmt, ap);
9328         va_end(ap);
9329         INTON;
9330         return ret;
9331 }
9332
9333
9334
9335 /*      $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $     */
9336
9337
9338 /*
9339  * Shell command parser.
9340  */
9341
9342 #define EOFMARKLEN 79
9343
9344
9345 struct heredoc {
9346         struct heredoc *next;   /* next here document in list */
9347         union node *here;               /* redirection node */
9348         char *eofmark;          /* string indicating end of input */
9349         int striptabs;          /* if set, strip leading tabs */
9350 };
9351
9352
9353
9354 static struct heredoc *heredoclist;    /* list of here documents to read */
9355
9356
9357 static union node *list(int);
9358 static union node *andor(void);
9359 static union node *pipeline(void);
9360 static union node *command(void);
9361 static union node *simplecmd(void);
9362 static union node *makename(void);
9363 static void parsefname(void);
9364 static void parseheredoc(void);
9365 static char peektoken(void);
9366 static int readtoken(void);
9367 static int xxreadtoken(void);
9368 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9369 static int noexpand(char *);
9370 static void synexpect(int) __attribute__((__noreturn__));
9371 static void synerror(const char *) __attribute__((__noreturn__));
9372 static void setprompt(int);
9373
9374
9375
9376
9377 /*
9378  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9379  * valid parse tree indicating a blank line.)
9380  */
9381
9382 union node *
9383 parsecmd(int interact)
9384 {
9385         int t;
9386
9387         tokpushback = 0;
9388         doprompt = interact;
9389         if (doprompt)
9390                 setprompt(doprompt);
9391         needprompt = 0;
9392         t = readtoken();
9393         if (t == TEOF)
9394                 return NEOF;
9395         if (t == TNL)
9396                 return NULL;
9397         tokpushback++;
9398         return list(1);
9399 }
9400
9401
9402 static union node *
9403 list(int nlflag)
9404 {
9405         union node *n1, *n2, *n3;
9406         int tok;
9407
9408         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9409         if (nlflag == 2 && peektoken())
9410                 return NULL;
9411         n1 = NULL;
9412         for (;;) {
9413                 n2 = andor();
9414                 tok = readtoken();
9415                 if (tok == TBACKGND) {
9416                         if (n2->type == NPIPE) {
9417                                 n2->npipe.backgnd = 1;
9418                         } else {
9419                                 if (n2->type != NREDIR) {
9420                                         n3 = stalloc(sizeof(struct nredir));
9421                                         n3->nredir.n = n2;
9422                                         n3->nredir.redirect = NULL;
9423                                         n2 = n3;
9424                                 }
9425                                 n2->type = NBACKGND;
9426                         }
9427                 }
9428                 if (n1 == NULL) {
9429                         n1 = n2;
9430                 }
9431                 else {
9432                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9433                         n3->type = NSEMI;
9434                         n3->nbinary.ch1 = n1;
9435                         n3->nbinary.ch2 = n2;
9436                         n1 = n3;
9437                 }
9438                 switch (tok) {
9439                 case TBACKGND:
9440                 case TSEMI:
9441                         tok = readtoken();
9442                         /* fall through */
9443                 case TNL:
9444                         if (tok == TNL) {
9445                                 parseheredoc();
9446                                 if (nlflag == 1)
9447                                         return n1;
9448                         } else {
9449                                 tokpushback++;
9450                         }
9451                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9452                         if (peektoken())
9453                                 return n1;
9454                         break;
9455                 case TEOF:
9456                         if (heredoclist)
9457                                 parseheredoc();
9458                         else
9459                                 pungetc();              /* push back EOF on input */
9460                         return n1;
9461                 default:
9462                         if (nlflag == 1)
9463                                 synexpect(-1);
9464                         tokpushback++;
9465                         return n1;
9466                 }
9467         }
9468 }
9469
9470
9471
9472 static union node *
9473 andor(void)
9474 {
9475         union node *n1, *n2, *n3;
9476         int t;
9477
9478         n1 = pipeline();
9479         for (;;) {
9480                 if ((t = readtoken()) == TAND) {
9481                         t = NAND;
9482                 } else if (t == TOR) {
9483                         t = NOR;
9484                 } else {
9485                         tokpushback++;
9486                         return n1;
9487                 }
9488                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9489                 n2 = pipeline();
9490                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9491                 n3->type = t;
9492                 n3->nbinary.ch1 = n1;
9493                 n3->nbinary.ch2 = n2;
9494                 n1 = n3;
9495         }
9496 }
9497
9498
9499
9500 static union node *
9501 pipeline(void)
9502 {
9503         union node *n1, *n2, *pipenode;
9504         struct nodelist *lp, *prev;
9505         int negate;
9506
9507         negate = 0;
9508         TRACE(("pipeline: entered\n"));
9509         if (readtoken() == TNOT) {
9510                 negate = !negate;
9511                 checkkwd = CHKKWD | CHKALIAS;
9512         } else
9513                 tokpushback++;
9514         n1 = command();
9515         if (readtoken() == TPIPE) {
9516                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9517                 pipenode->type = NPIPE;
9518                 pipenode->npipe.backgnd = 0;
9519                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9520                 pipenode->npipe.cmdlist = lp;
9521                 lp->n = n1;
9522                 do {
9523                         prev = lp;
9524                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9525                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9526                         lp->n = command();
9527                         prev->next = lp;
9528                 } while (readtoken() == TPIPE);
9529                 lp->next = NULL;
9530                 n1 = pipenode;
9531         }
9532         tokpushback++;
9533         if (negate) {
9534                 n2 = (union node *)stalloc(sizeof (struct nnot));
9535                 n2->type = NNOT;
9536                 n2->nnot.com = n1;
9537                 return n2;
9538         } else
9539                 return n1;
9540 }
9541
9542
9543
9544 static union node *
9545 command(void)
9546 {
9547         union node *n1, *n2;
9548         union node *ap, **app;
9549         union node *cp, **cpp;
9550         union node *redir, **rpp;
9551         union node **rpp2;
9552         int t;
9553
9554         redir = NULL;
9555         rpp2 = &redir;
9556
9557         switch (readtoken()) {
9558         default:
9559                 synexpect(-1);
9560                 /* NOTREACHED */
9561         case TIF:
9562                 n1 = (union node *)stalloc(sizeof (struct nif));
9563                 n1->type = NIF;
9564                 n1->nif.test = list(0);
9565                 if (readtoken() != TTHEN)
9566                         synexpect(TTHEN);
9567                 n1->nif.ifpart = list(0);
9568                 n2 = n1;
9569                 while (readtoken() == TELIF) {
9570                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9571                         n2 = n2->nif.elsepart;
9572                         n2->type = NIF;
9573                         n2->nif.test = list(0);
9574                         if (readtoken() != TTHEN)
9575                                 synexpect(TTHEN);
9576                         n2->nif.ifpart = list(0);
9577                 }
9578                 if (lasttoken == TELSE)
9579                         n2->nif.elsepart = list(0);
9580                 else {
9581                         n2->nif.elsepart = NULL;
9582                         tokpushback++;
9583                 }
9584                 t = TFI;
9585                 break;
9586         case TWHILE:
9587         case TUNTIL: {
9588                 int got;
9589                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9590                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9591                 n1->nbinary.ch1 = list(0);
9592                 if ((got=readtoken()) != TDO) {
9593 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9594                         synexpect(TDO);
9595                 }
9596                 n1->nbinary.ch2 = list(0);
9597                 t = TDONE;
9598                 break;
9599         }
9600         case TFOR:
9601                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9602                         synerror("Bad for loop variable");
9603                 n1 = (union node *)stalloc(sizeof (struct nfor));
9604                 n1->type = NFOR;
9605                 n1->nfor.var = wordtext;
9606                 checkkwd = CHKKWD | CHKALIAS;
9607                 if (readtoken() == TIN) {
9608                         app = &ap;
9609                         while (readtoken() == TWORD) {
9610                                 n2 = (union node *)stalloc(sizeof (struct narg));
9611                                 n2->type = NARG;
9612                                 n2->narg.text = wordtext;
9613                                 n2->narg.backquote = backquotelist;
9614                                 *app = n2;
9615                                 app = &n2->narg.next;
9616                         }
9617                         *app = NULL;
9618                         n1->nfor.args = ap;
9619                         if (lasttoken != TNL && lasttoken != TSEMI)
9620                                 synexpect(-1);
9621                 } else {
9622                         n2 = (union node *)stalloc(sizeof (struct narg));
9623                         n2->type = NARG;
9624                         n2->narg.text = (char *)dolatstr;
9625                         n2->narg.backquote = NULL;
9626                         n2->narg.next = NULL;
9627                         n1->nfor.args = n2;
9628                         /*
9629                          * Newline or semicolon here is optional (but note
9630                          * that the original Bourne shell only allowed NL).
9631                          */
9632                         if (lasttoken != TNL && lasttoken != TSEMI)
9633                                 tokpushback++;
9634                 }
9635                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9636                 if (readtoken() != TDO)
9637                         synexpect(TDO);
9638                 n1->nfor.body = list(0);
9639                 t = TDONE;
9640                 break;
9641         case TCASE:
9642                 n1 = (union node *)stalloc(sizeof (struct ncase));
9643                 n1->type = NCASE;
9644                 if (readtoken() != TWORD)
9645                         synexpect(TWORD);
9646                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9647                 n2->type = NARG;
9648                 n2->narg.text = wordtext;
9649                 n2->narg.backquote = backquotelist;
9650                 n2->narg.next = NULL;
9651                 do {
9652                         checkkwd = CHKKWD | CHKALIAS;
9653                 } while (readtoken() == TNL);
9654                 if (lasttoken != TIN)
9655                         synexpect(TIN);
9656                 cpp = &n1->ncase.cases;
9657 next_case:
9658                 checkkwd = CHKNL | CHKKWD;
9659                 t = readtoken();
9660                 while(t != TESAC) {
9661                         if (lasttoken == TLP)
9662                                 readtoken();
9663                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9664                         cp->type = NCLIST;
9665                         app = &cp->nclist.pattern;
9666                         for (;;) {
9667                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9668                                 ap->type = NARG;
9669                                 ap->narg.text = wordtext;
9670                                 ap->narg.backquote = backquotelist;
9671                                 if (readtoken() != TPIPE)
9672                                         break;
9673                                 app = &ap->narg.next;
9674                                 readtoken();
9675                         }
9676                         ap->narg.next = NULL;
9677                         if (lasttoken != TRP)
9678                                 synexpect(TRP);
9679                         cp->nclist.body = list(2);
9680
9681                         cpp = &cp->nclist.next;
9682
9683                         checkkwd = CHKNL | CHKKWD;
9684                         if ((t = readtoken()) != TESAC) {
9685                                 if (t != TENDCASE)
9686                                         synexpect(TENDCASE);
9687                                 else
9688                                         goto next_case;
9689                         }
9690                 }
9691                 *cpp = NULL;
9692                 goto redir;
9693         case TLP:
9694                 n1 = (union node *)stalloc(sizeof (struct nredir));
9695                 n1->type = NSUBSHELL;
9696                 n1->nredir.n = list(0);
9697                 n1->nredir.redirect = NULL;
9698                 t = TRP;
9699                 break;
9700         case TBEGIN:
9701                 n1 = list(0);
9702                 t = TEND;
9703                 break;
9704         case TWORD:
9705         case TREDIR:
9706                 tokpushback++;
9707                 return simplecmd();
9708         }
9709
9710         if (readtoken() != t)
9711                 synexpect(t);
9712
9713 redir:
9714         /* Now check for redirection which may follow command */
9715         checkkwd = CHKKWD | CHKALIAS;
9716         rpp = rpp2;
9717         while (readtoken() == TREDIR) {
9718                 *rpp = n2 = redirnode;
9719                 rpp = &n2->nfile.next;
9720                 parsefname();
9721         }
9722         tokpushback++;
9723         *rpp = NULL;
9724         if (redir) {
9725                 if (n1->type != NSUBSHELL) {
9726                         n2 = (union node *)stalloc(sizeof (struct nredir));
9727                         n2->type = NREDIR;
9728                         n2->nredir.n = n1;
9729                         n1 = n2;
9730                 }
9731                 n1->nredir.redirect = redir;
9732         }
9733
9734         return n1;
9735 }
9736
9737
9738 static union node *
9739 simplecmd(void) {
9740         union node *args, **app;
9741         union node *n = NULL;
9742         union node *vars, **vpp;
9743         union node **rpp, *redir;
9744         int savecheckkwd;
9745
9746         args = NULL;
9747         app = &args;
9748         vars = NULL;
9749         vpp = &vars;
9750         redir = NULL;
9751         rpp = &redir;
9752
9753         savecheckkwd = CHKALIAS;
9754         for (;;) {
9755                 checkkwd = savecheckkwd;
9756                 switch (readtoken()) {
9757                 case TWORD:
9758                         n = (union node *)stalloc(sizeof (struct narg));
9759                         n->type = NARG;
9760                         n->narg.text = wordtext;
9761                         n->narg.backquote = backquotelist;
9762                         if (savecheckkwd && isassignment(wordtext)) {
9763                                 *vpp = n;
9764                                 vpp = &n->narg.next;
9765                         } else {
9766                                 *app = n;
9767                                 app = &n->narg.next;
9768                                 savecheckkwd = 0;
9769                         }
9770                         break;
9771                 case TREDIR:
9772                         *rpp = n = redirnode;
9773                         rpp = &n->nfile.next;
9774                         parsefname();   /* read name of redirection file */
9775                         break;
9776                 case TLP:
9777                         if (
9778                                 args && app == &args->narg.next &&
9779                                 !vars && !redir
9780                         ) {
9781                                 struct builtincmd *bcmd;
9782                                 const char *name;
9783
9784                                 /* We have a function */
9785                                 if (readtoken() != TRP)
9786                                         synexpect(TRP);
9787                                 name = n->narg.text;
9788                                 if (
9789                                         !goodname(name) || (
9790                                                 (bcmd = find_builtin(name)) &&
9791                                                 IS_BUILTIN_SPECIAL(bcmd)
9792                                         )
9793                                 )
9794                                         synerror("Bad function name");
9795                                 n->type = NDEFUN;
9796                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9797                                 n->narg.next = command();
9798                                 return n;
9799                         }
9800                         /* fall through */
9801                 default:
9802                         tokpushback++;
9803                         goto out;
9804                 }
9805         }
9806 out:
9807         *app = NULL;
9808         *vpp = NULL;
9809         *rpp = NULL;
9810         n = (union node *)stalloc(sizeof (struct ncmd));
9811         n->type = NCMD;
9812         n->ncmd.args = args;
9813         n->ncmd.assign = vars;
9814         n->ncmd.redirect = redir;
9815         return n;
9816 }
9817
9818 static union node *
9819 makename(void)
9820 {
9821         union node *n;
9822
9823         n = (union node *)stalloc(sizeof (struct narg));
9824         n->type = NARG;
9825         n->narg.next = NULL;
9826         n->narg.text = wordtext;
9827         n->narg.backquote = backquotelist;
9828         return n;
9829 }
9830
9831 void fixredir(union node *n, const char *text, int err)
9832 {
9833         TRACE(("Fix redir %s %d\n", text, err));
9834         if (!err)
9835                 n->ndup.vname = NULL;
9836
9837         if (is_digit(text[0]) && text[1] == '\0')
9838                 n->ndup.dupfd = digit_val(text[0]);
9839         else if (text[0] == '-' && text[1] == '\0')
9840                 n->ndup.dupfd = -1;
9841         else {
9842
9843                 if (err)
9844                         synerror("Bad fd number");
9845                 else
9846                         n->ndup.vname = makename();
9847         }
9848 }
9849
9850
9851 static void
9852 parsefname(void)
9853 {
9854         union node *n = redirnode;
9855
9856         if (readtoken() != TWORD)
9857                 synexpect(-1);
9858         if (n->type == NHERE) {
9859                 struct heredoc *here = heredoc;
9860                 struct heredoc *p;
9861                 int i;
9862
9863                 if (quoteflag == 0)
9864                         n->type = NXHERE;
9865                 TRACE(("Here document %d\n", n->type));
9866                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9867                         synerror("Illegal eof marker for << redirection");
9868                 rmescapes(wordtext);
9869                 here->eofmark = wordtext;
9870                 here->next = NULL;
9871                 if (heredoclist == NULL)
9872                         heredoclist = here;
9873                 else {
9874                         for (p = heredoclist ; p->next ; p = p->next);
9875                         p->next = here;
9876                 }
9877         } else if (n->type == NTOFD || n->type == NFROMFD) {
9878                 fixredir(n, wordtext, 0);
9879         } else {
9880                 n->nfile.fname = makename();
9881         }
9882 }
9883
9884
9885 /*
9886  * Input any here documents.
9887  */
9888
9889 static void
9890 parseheredoc(void)
9891 {
9892         struct heredoc *here;
9893         union node *n;
9894
9895         here = heredoclist;
9896         heredoclist = 0;
9897
9898         while (here) {
9899                 if (needprompt) {
9900                         setprompt(2);
9901                 }
9902                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9903                                 here->eofmark, here->striptabs);
9904                 n = (union node *)stalloc(sizeof (struct narg));
9905                 n->narg.type = NARG;
9906                 n->narg.next = NULL;
9907                 n->narg.text = wordtext;
9908                 n->narg.backquote = backquotelist;
9909                 here->here->nhere.doc = n;
9910                 here = here->next;
9911         }
9912 }
9913
9914 static char peektoken(void)
9915 {
9916         int t;
9917
9918         t = readtoken();
9919         tokpushback++;
9920         return tokname_array[t][0];
9921 }
9922
9923 static int
9924 readtoken(void)
9925 {
9926         int t;
9927 #ifdef DEBUG
9928         int alreadyseen = tokpushback;
9929 #endif
9930
9931 #ifdef CONFIG_ASH_ALIAS
9932 top:
9933 #endif
9934
9935         t = xxreadtoken();
9936
9937         /*
9938          * eat newlines
9939          */
9940         if (checkkwd & CHKNL) {
9941                 while (t == TNL) {
9942                         parseheredoc();
9943                         t = xxreadtoken();
9944                 }
9945         }
9946
9947         if (t != TWORD || quoteflag) {
9948                 goto out;
9949         }
9950
9951         /*
9952          * check for keywords
9953          */
9954         if (checkkwd & CHKKWD) {
9955                 const char *const *pp;
9956
9957                 if ((pp = findkwd(wordtext))) {
9958                         lasttoken = t = pp - tokname_array;
9959                         TRACE(("keyword %s recognized\n", tokname(t)));
9960                         goto out;
9961                 }
9962         }
9963
9964         if (checkkwd & CHKALIAS) {
9965 #ifdef CONFIG_ASH_ALIAS
9966                 struct alias *ap;
9967                 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9968                         if (*ap->val) {
9969                                 pushstring(ap->val, ap);
9970                         }
9971                         goto top;
9972                 }
9973 #endif
9974         }
9975 out:
9976         checkkwd = 0;
9977 #ifdef DEBUG
9978         if (!alreadyseen)
9979             TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9980         else
9981             TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9982 #endif
9983         return (t);
9984 }
9985
9986
9987 /*
9988  * Read the next input token.
9989  * If the token is a word, we set backquotelist to the list of cmds in
9990  *      backquotes.  We set quoteflag to true if any part of the word was
9991  *      quoted.
9992  * If the token is TREDIR, then we set redirnode to a structure containing
9993  *      the redirection.
9994  * In all cases, the variable startlinno is set to the number of the line
9995  *      on which the token starts.
9996  *
9997  * [Change comment:  here documents and internal procedures]
9998  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
9999  *  word parsing code into a separate routine.  In this case, readtoken
10000  *  doesn't need to have any internal procedures, but parseword does.
10001  *  We could also make parseoperator in essence the main routine, and
10002  *  have parseword (readtoken1?) handle both words and redirection.]
10003  */
10004
10005 #define NEW_xxreadtoken
10006 #ifdef NEW_xxreadtoken
10007
10008 /* singles must be first! */
10009 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10010
10011 static const char xxreadtoken_tokens[] = {
10012         TNL, TLP, TRP,          /* only single occurrence allowed */
10013         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10014         TEOF,                   /* corresponds to trailing nul */
10015         TAND, TOR, TENDCASE,    /* if double occurrence */
10016 };
10017
10018 #define xxreadtoken_doubles \
10019         (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10020 #define xxreadtoken_singles \
10021         (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10022
10023 static int xxreadtoken()
10024 {
10025         int c;
10026
10027         if (tokpushback) {
10028                 tokpushback = 0;
10029                 return lasttoken;
10030         }
10031         if (needprompt) {
10032                 setprompt(2);
10033         }
10034         startlinno = plinno;
10035         for (;;) {                      /* until token or start of word found */
10036                 c = pgetc_macro();
10037
10038                 if ((c != ' ') && (c != '\t')
10039 #ifdef CONFIG_ASH_ALIAS
10040                         && (c != PEOA)
10041 #endif
10042                         ) {
10043                         if (c == '#') {
10044                                 while ((c = pgetc()) != '\n' && c != PEOF);
10045                                 pungetc();
10046                         } else if (c == '\\') {
10047                                 if (pgetc() != '\n') {
10048                                         pungetc();
10049                                         goto READTOKEN1;
10050                                 }
10051                                 startlinno = ++plinno;
10052                                 if (doprompt)
10053                                         setprompt(2);
10054                         } else {
10055                                 const char *p
10056                                         = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10057
10058                                 if (c != PEOF) {
10059                                         if (c == '\n') {
10060                                                 plinno++;
10061                                                 needprompt = doprompt;
10062                                         }
10063
10064                                         p = strchr(xxreadtoken_chars, c);
10065                                         if (p == NULL) {
10066                                           READTOKEN1:
10067                                                 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10068                                         }
10069
10070                                         if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10071                                                 if (pgetc() == *p) {    /* double occurrence? */
10072                                                         p += xxreadtoken_doubles + 1;
10073                                                 } else {
10074                                                         pungetc();
10075                                                 }
10076                                         }
10077                                 }
10078
10079                                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10080                         }
10081                 }
10082         }
10083 }
10084
10085
10086 #else
10087 #define RETURN(token)   return lasttoken = token
10088
10089 static int
10090 xxreadtoken(void)
10091 {
10092         int c;
10093
10094         if (tokpushback) {
10095                 tokpushback = 0;
10096                 return lasttoken;
10097         }
10098         if (needprompt) {
10099                 setprompt(2);
10100         }
10101         startlinno = plinno;
10102         for (;;) {      /* until token or start of word found */
10103                 c = pgetc_macro();
10104                 switch (c) {
10105                 case ' ': case '\t':
10106 #ifdef CONFIG_ASH_ALIAS
10107                 case PEOA:
10108 #endif
10109                         continue;
10110                 case '#':
10111                         while ((c = pgetc()) != '\n' && c != PEOF);
10112                         pungetc();
10113                         continue;
10114                 case '\\':
10115                         if (pgetc() == '\n') {
10116                                 startlinno = ++plinno;
10117                                 if (doprompt)
10118                                         setprompt(2);
10119                                 continue;
10120                         }
10121                         pungetc();
10122                         goto breakloop;
10123                 case '\n':
10124                         plinno++;
10125                         needprompt = doprompt;
10126                         RETURN(TNL);
10127                 case PEOF:
10128                         RETURN(TEOF);
10129                 case '&':
10130                         if (pgetc() == '&')
10131                                 RETURN(TAND);
10132                         pungetc();
10133                         RETURN(TBACKGND);
10134                 case '|':
10135                         if (pgetc() == '|')
10136                                 RETURN(TOR);
10137                         pungetc();
10138                         RETURN(TPIPE);
10139                 case ';':
10140                         if (pgetc() == ';')
10141                                 RETURN(TENDCASE);
10142                         pungetc();
10143                         RETURN(TSEMI);
10144                 case '(':
10145                         RETURN(TLP);
10146                 case ')':
10147                         RETURN(TRP);
10148                 default:
10149                         goto breakloop;
10150                 }
10151         }
10152 breakloop:
10153         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10154 #undef RETURN
10155 }
10156 #endif /* NEW_xxreadtoken */
10157
10158
10159 /*
10160  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10161  * is not NULL, read a here document.  In the latter case, eofmark is the
10162  * word which marks the end of the document and striptabs is true if
10163  * leading tabs should be stripped from the document.  The argument firstc
10164  * is the first character of the input token or document.
10165  *
10166  * Because C does not have internal subroutines, I have simulated them
10167  * using goto's to implement the subroutine linkage.  The following macros
10168  * will run code that appears at the end of readtoken1.
10169  */
10170
10171 #define CHECKEND()      {goto checkend; checkend_return:;}
10172 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10173 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10174 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10175 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10176 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10177
10178 static int
10179 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10180 {
10181         int c = firstc;
10182         char *out;
10183         int len;
10184         char line[EOFMARKLEN + 1];
10185         struct nodelist *bqlist;
10186         int quotef;
10187         int dblquote;
10188         int varnest;    /* levels of variables expansion */
10189         int arinest;    /* levels of arithmetic expansion */
10190         int parenlevel; /* levels of parens in arithmetic */
10191         int dqvarnest;  /* levels of variables expansion within double quotes */
10192         int oldstyle;
10193         int prevsyntax; /* syntax before arithmetic */
10194 #if __GNUC__
10195         /* Avoid longjmp clobbering */
10196         (void) &out;
10197         (void) &quotef;
10198         (void) &dblquote;
10199         (void) &varnest;
10200         (void) &arinest;
10201         (void) &parenlevel;
10202         (void) &dqvarnest;
10203         (void) &oldstyle;
10204         (void) &prevsyntax;
10205         (void) &syntax;
10206 #endif
10207
10208         startlinno = plinno;
10209         dblquote = 0;
10210         if (syntax == DQSYNTAX)
10211                 dblquote = 1;
10212         quotef = 0;
10213         bqlist = NULL;
10214         varnest = 0;
10215         arinest = 0;
10216         parenlevel = 0;
10217         dqvarnest = 0;
10218
10219         STARTSTACKSTR(out);
10220         loop: { /* for each line, until end of word */
10221                 CHECKEND();     /* set c to PEOF if at end of here document */
10222                 for (;;) {      /* until end of line or end of word */
10223                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10224                         switch(SIT(c, syntax)) {
10225                         case CNL:       /* '\n' */
10226                                 if (syntax == BASESYNTAX)
10227                                         goto endword;   /* exit outer loop */
10228                                 USTPUTC(c, out);
10229                                 plinno++;
10230                                 if (doprompt)
10231                                         setprompt(2);
10232                                 c = pgetc();
10233                                 goto loop;              /* continue outer loop */
10234                         case CWORD:
10235                                 USTPUTC(c, out);
10236                                 break;
10237                         case CCTL:
10238                                 if (eofmark == NULL || dblquote)
10239                                         USTPUTC(CTLESC, out);
10240                                 USTPUTC(c, out);
10241                                 break;
10242                         case CBACK:     /* backslash */
10243                                 c = pgetc2();
10244                                 if (c == PEOF) {
10245                                         USTPUTC(CTLESC, out);
10246                                         USTPUTC('\\', out);
10247                                         pungetc();
10248                                 } else if (c == '\n') {
10249                                         if (doprompt)
10250                                                 setprompt(2);
10251                                 } else {
10252                                         if (
10253                                                 dblquote &&
10254                                                 c != '\\' && c != '`' &&
10255                                                 c != '$' && (
10256                                                         c != '"' ||
10257                                                         eofmark != NULL
10258                                                 )
10259                                         ) {
10260                                                 USTPUTC(CTLESC, out);
10261                                                 USTPUTC('\\', out);
10262                                         }
10263                                         if (SIT(c, SQSYNTAX) == CCTL)
10264                                                 USTPUTC(CTLESC, out);
10265                                         USTPUTC(c, out);
10266                                         quotef++;
10267                                 }
10268                                 break;
10269                         case CSQUOTE:
10270                                 syntax = SQSYNTAX;
10271 quotemark:
10272                                 if (eofmark == NULL) {
10273                                         USTPUTC(CTLQUOTEMARK, out);
10274                                 }
10275                                 break;
10276                         case CDQUOTE:
10277                                 syntax = DQSYNTAX;
10278                                 dblquote = 1;
10279                                 goto quotemark;
10280                         case CENDQUOTE:
10281                                 if (eofmark != NULL && arinest == 0 &&
10282                                     varnest == 0) {
10283                                         USTPUTC(c, out);
10284                                 } else {
10285                                         if (dqvarnest == 0) {
10286                                                 syntax = BASESYNTAX;
10287                                                 dblquote = 0;
10288                                         }
10289                                         quotef++;
10290                                         goto quotemark;
10291                                 }
10292                                 break;
10293                         case CVAR:      /* '$' */
10294                                 PARSESUB();             /* parse substitution */
10295                                 break;
10296                         case CENDVAR:   /* '}' */
10297                                 if (varnest > 0) {
10298                                         varnest--;
10299                                         if (dqvarnest > 0) {
10300                                                 dqvarnest--;
10301                                         }
10302                                         USTPUTC(CTLENDVAR, out);
10303                                 } else {
10304                                         USTPUTC(c, out);
10305                                 }
10306                                 break;
10307 #ifdef CONFIG_ASH_MATH_SUPPORT
10308                         case CLP:       /* '(' in arithmetic */
10309                                 parenlevel++;
10310                                 USTPUTC(c, out);
10311                                 break;
10312                         case CRP:       /* ')' in arithmetic */
10313                                 if (parenlevel > 0) {
10314                                         USTPUTC(c, out);
10315                                         --parenlevel;
10316                                 } else {
10317                                         if (pgetc() == ')') {
10318                                                 if (--arinest == 0) {
10319                                                         USTPUTC(CTLENDARI, out);
10320                                                         syntax = prevsyntax;
10321                                                         if (syntax == DQSYNTAX)
10322                                                                 dblquote = 1;
10323                                                         else
10324                                                                 dblquote = 0;
10325                                                 } else
10326                                                         USTPUTC(')', out);
10327                                         } else {
10328                                                 /*
10329                                                  * unbalanced parens
10330                                                  *  (don't 2nd guess - no error)
10331                                                  */
10332                                                 pungetc();
10333                                                 USTPUTC(')', out);
10334                                         }
10335                                 }
10336                                 break;
10337 #endif
10338                         case CBQUOTE:   /* '`' */
10339                                 PARSEBACKQOLD();
10340                                 break;
10341                         case CENDFILE:
10342                                 goto endword;           /* exit outer loop */
10343                         case CIGN:
10344                                 break;
10345                         default:
10346                                 if (varnest == 0)
10347                                         goto endword;   /* exit outer loop */
10348 #ifdef CONFIG_ASH_ALIAS
10349                                 if (c != PEOA)
10350 #endif
10351                                         USTPUTC(c, out);
10352
10353                         }
10354                         c = pgetc_macro();
10355                 }
10356         }
10357 endword:
10358 #ifdef CONFIG_ASH_MATH_SUPPORT
10359         if (syntax == ARISYNTAX)
10360                 synerror("Missing '))'");
10361 #endif
10362         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10363                 synerror("Unterminated quoted string");
10364         if (varnest != 0) {
10365                 startlinno = plinno;
10366                 /* { */
10367                 synerror("Missing '}'");
10368         }
10369         USTPUTC('\0', out);
10370         len = out - (char *)stackblock();
10371         out = stackblock();
10372         if (eofmark == NULL) {
10373                 if ((c == '>' || c == '<')
10374                  && quotef == 0
10375                  && len <= 2
10376                  && (*out == '\0' || is_digit(*out))) {
10377                         PARSEREDIR();
10378                         return lasttoken = TREDIR;
10379                 } else {
10380                         pungetc();
10381                 }
10382         }
10383         quoteflag = quotef;
10384         backquotelist = bqlist;
10385         grabstackblock(len);
10386         wordtext = out;
10387         return lasttoken = TWORD;
10388 /* end of readtoken routine */
10389
10390
10391
10392 /*
10393  * Check to see whether we are at the end of the here document.  When this
10394  * is called, c is set to the first character of the next input line.  If
10395  * we are at the end of the here document, this routine sets the c to PEOF.
10396  */
10397
10398 checkend: {
10399         if (eofmark) {
10400 #ifdef CONFIG_ASH_ALIAS
10401                 if (c == PEOA) {
10402                         c = pgetc2();
10403                 }
10404 #endif
10405                 if (striptabs) {
10406                         while (c == '\t') {
10407                                 c = pgetc2();
10408                         }
10409                 }
10410                 if (c == *eofmark) {
10411                         if (pfgets(line, sizeof line) != NULL) {
10412                                 char *p, *q;
10413
10414                                 p = line;
10415                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10416                                 if (*p == '\n' && *q == '\0') {
10417                                         c = PEOF;
10418                                         plinno++;
10419                                         needprompt = doprompt;
10420                                 } else {
10421                                         pushstring(line, NULL);
10422                                 }
10423                         }
10424                 }
10425         }
10426         goto checkend_return;
10427 }
10428
10429
10430 /*
10431  * Parse a redirection operator.  The variable "out" points to a string
10432  * specifying the fd to be redirected.  The variable "c" contains the
10433  * first character of the redirection operator.
10434  */
10435
10436 parseredir: {
10437         char fd = *out;
10438         union node *np;
10439
10440         np = (union node *)stalloc(sizeof (struct nfile));
10441         if (c == '>') {
10442                 np->nfile.fd = 1;
10443                 c = pgetc();
10444                 if (c == '>')
10445                         np->type = NAPPEND;
10446                 else if (c == '|')
10447                         np->type = NCLOBBER;
10448                 else if (c == '&')
10449                         np->type = NTOFD;
10450                 else {
10451                         np->type = NTO;
10452                         pungetc();
10453                 }
10454         } else {        /* c == '<' */
10455                 np->nfile.fd = 0;
10456                 switch (c = pgetc()) {
10457                 case '<':
10458                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10459                                 np = (union node *)stalloc(sizeof (struct nhere));
10460                                 np->nfile.fd = 0;
10461                         }
10462                         np->type = NHERE;
10463                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10464                         heredoc->here = np;
10465                         if ((c = pgetc()) == '-') {
10466                                 heredoc->striptabs = 1;
10467                         } else {
10468                                 heredoc->striptabs = 0;
10469                                 pungetc();
10470                         }
10471                         break;
10472
10473                 case '&':
10474                         np->type = NFROMFD;
10475                         break;
10476
10477                 case '>':
10478                         np->type = NFROMTO;
10479                         break;
10480
10481                 default:
10482                         np->type = NFROM;
10483                         pungetc();
10484                         break;
10485                 }
10486         }
10487         if (fd != '\0')
10488                 np->nfile.fd = digit_val(fd);
10489         redirnode = np;
10490         goto parseredir_return;
10491 }
10492
10493
10494 /*
10495  * Parse a substitution.  At this point, we have read the dollar sign
10496  * and nothing else.
10497  */
10498
10499 parsesub: {
10500         int subtype;
10501         int typeloc;
10502         int flags;
10503         char *p;
10504         static const char types[] = "}-+?=";
10505
10506         c = pgetc();
10507         if (
10508                 c <= PEOA_OR_PEOF  ||
10509                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10510         ) {
10511                 USTPUTC('$', out);
10512                 pungetc();
10513         } else if (c == '(') {  /* $(command) or $((arith)) */
10514                 if (pgetc() == '(') {
10515 #ifdef CONFIG_ASH_MATH_SUPPORT
10516                         PARSEARITH();
10517 #else
10518                         synerror("We unsupport $((arith))");
10519 #endif
10520                 } else {
10521                         pungetc();
10522                         PARSEBACKQNEW();
10523                 }
10524         } else {
10525                 USTPUTC(CTLVAR, out);
10526                 typeloc = out - (char *)stackblock();
10527                 USTPUTC(VSNORMAL, out);
10528                 subtype = VSNORMAL;
10529                 if (c == '{') {
10530                         c = pgetc();
10531                         if (c == '#') {
10532                                 if ((c = pgetc()) == '}')
10533                                         c = '#';
10534                                 else
10535                                         subtype = VSLENGTH;
10536                         }
10537                         else
10538                                 subtype = 0;
10539                 }
10540                 if (c > PEOA_OR_PEOF && is_name(c)) {
10541                         do {
10542                                 STPUTC(c, out);
10543                                 c = pgetc();
10544                         } while (c > PEOA_OR_PEOF && is_in_name(c));
10545                 } else if (is_digit(c)) {
10546                         do {
10547                                 STPUTC(c, out);
10548                                 c = pgetc();
10549                         } while (is_digit(c));
10550                 }
10551                 else if (is_special(c)) {
10552                         USTPUTC(c, out);
10553                         c = pgetc();
10554                 }
10555                 else
10556 badsub:                 synerror("Bad substitution");
10557
10558                 STPUTC('=', out);
10559                 flags = 0;
10560                 if (subtype == 0) {
10561                         switch (c) {
10562                         case ':':
10563                                 flags = VSNUL;
10564                                 c = pgetc();
10565                                 /*FALLTHROUGH*/
10566                         default:
10567                                 p = strchr(types, c);
10568                                 if (p == NULL)
10569                                         goto badsub;
10570                                 subtype = p - types + VSNORMAL;
10571                                 break;
10572                         case '%':
10573                         case '#':
10574                                 {
10575                                         int cc = c;
10576                                         subtype = c == '#' ? VSTRIMLEFT :
10577                                                              VSTRIMRIGHT;
10578                                         c = pgetc();
10579                                         if (c == cc)
10580                                                 subtype++;
10581                                         else
10582                                                 pungetc();
10583                                         break;
10584                                 }
10585                         }
10586                 } else {
10587                         pungetc();
10588                 }
10589                 if (dblquote || arinest)
10590                         flags |= VSQUOTE;
10591                 *((char *)stackblock() + typeloc) = subtype | flags;
10592                 if (subtype != VSNORMAL) {
10593                         varnest++;
10594                         if (dblquote || arinest) {
10595                                 dqvarnest++;
10596                         }
10597                 }
10598         }
10599         goto parsesub_return;
10600 }
10601
10602
10603 /*
10604  * Called to parse command substitutions.  Newstyle is set if the command
10605  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10606  * list of commands (passed by reference), and savelen is the number of
10607  * characters on the top of the stack which must be preserved.
10608  */
10609
10610 parsebackq: {
10611         struct nodelist **nlpp;
10612         int savepbq;
10613         union node *n;
10614         char *volatile str;
10615         struct jmploc jmploc;
10616         struct jmploc *volatile savehandler;
10617         size_t savelen;
10618         int saveprompt;
10619 #ifdef __GNUC__
10620         (void) &saveprompt;
10621 #endif
10622
10623         savepbq = parsebackquote;
10624         if (setjmp(jmploc.loc)) {
10625                 if (str)
10626                         ckfree(str);
10627                 parsebackquote = 0;
10628                 handler = savehandler;
10629                 longjmp(handler->loc, 1);
10630         }
10631         INTOFF;
10632         str = NULL;
10633         savelen = out - (char *)stackblock();
10634         if (savelen > 0) {
10635                 str = ckmalloc(savelen);
10636                 memcpy(str, stackblock(), savelen);
10637         }
10638         savehandler = handler;
10639         handler = &jmploc;
10640         INTON;
10641         if (oldstyle) {
10642                 /* We must read until the closing backquote, giving special
10643                    treatment to some slashes, and then push the string and
10644                    reread it as input, interpreting it normally.  */
10645                 char *pout;
10646                 int pc;
10647                 size_t psavelen;
10648                 char *pstr;
10649
10650
10651                 STARTSTACKSTR(pout);
10652                 for (;;) {
10653                         if (needprompt) {
10654                                 setprompt(2);
10655                         }
10656                         switch (pc = pgetc()) {
10657                         case '`':
10658                                 goto done;
10659
10660                         case '\\':
10661                                 if ((pc = pgetc()) == '\n') {
10662                                         plinno++;
10663                                         if (doprompt)
10664                                                 setprompt(2);
10665                                         /*
10666                                          * If eating a newline, avoid putting
10667                                          * the newline into the new character
10668                                          * stream (via the STPUTC after the
10669                                          * switch).
10670                                          */
10671                                         continue;
10672                                 }
10673                                 if (pc != '\\' && pc != '`' && pc != '$'
10674                                     && (!dblquote || pc != '"'))
10675                                         STPUTC('\\', pout);
10676                                 if (pc > PEOA_OR_PEOF) {
10677                                         break;
10678                                 }
10679                                 /* fall through */
10680
10681                         case PEOF:
10682 #ifdef CONFIG_ASH_ALIAS
10683                         case PEOA:
10684 #endif
10685                                 startlinno = plinno;
10686                                 synerror("EOF in backquote substitution");
10687
10688                         case '\n':
10689                                 plinno++;
10690                                 needprompt = doprompt;
10691                                 break;
10692
10693                         default:
10694                                 break;
10695                         }
10696                         STPUTC(pc, pout);
10697                 }
10698 done:
10699                 STPUTC('\0', pout);
10700                 psavelen = pout - (char *)stackblock();
10701                 if (psavelen > 0) {
10702                         pstr = grabstackstr(pout);
10703                         setinputstring(pstr);
10704                 }
10705         }
10706         nlpp = &bqlist;
10707         while (*nlpp)
10708                 nlpp = &(*nlpp)->next;
10709         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10710         (*nlpp)->next = NULL;
10711         parsebackquote = oldstyle;
10712
10713         if (oldstyle) {
10714                 saveprompt = doprompt;
10715                 doprompt = 0;
10716         }
10717
10718         n = list(2);
10719
10720         if (oldstyle)
10721                 doprompt = saveprompt;
10722         else {
10723                 if (readtoken() != TRP)
10724                         synexpect(TRP);
10725         }
10726
10727         (*nlpp)->n = n;
10728         if (oldstyle) {
10729                 /*
10730                  * Start reading from old file again, ignoring any pushed back
10731                  * tokens left from the backquote parsing
10732                  */
10733                 popfile();
10734                 tokpushback = 0;
10735         }
10736         while (stackblocksize() <= savelen)
10737                 growstackblock();
10738         STARTSTACKSTR(out);
10739         if (str) {
10740                 memcpy(out, str, savelen);
10741                 STADJUST(savelen, out);
10742                 INTOFF;
10743                 ckfree(str);
10744                 str = NULL;
10745                 INTON;
10746         }
10747         parsebackquote = savepbq;
10748         handler = savehandler;
10749         if (arinest || dblquote)
10750                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10751         else
10752                 USTPUTC(CTLBACKQ, out);
10753         if (oldstyle)
10754                 goto parsebackq_oldreturn;
10755         else
10756                 goto parsebackq_newreturn;
10757 }
10758
10759 #ifdef CONFIG_ASH_MATH_SUPPORT
10760 /*
10761  * Parse an arithmetic expansion (indicate start of one and set state)
10762  */
10763 parsearith: {
10764
10765         if (++arinest == 1) {
10766                 prevsyntax = syntax;
10767                 syntax = ARISYNTAX;
10768                 USTPUTC(CTLARI, out);
10769                 if (dblquote)
10770                         USTPUTC('"',out);
10771                 else
10772                         USTPUTC(' ',out);
10773         } else {
10774                 /*
10775                  * we collapse embedded arithmetic expansion to
10776                  * parenthesis, which should be equivalent
10777                  */
10778                 USTPUTC('(', out);
10779         }
10780         goto parsearith_return;
10781 }
10782 #endif
10783
10784 } /* end of readtoken */
10785
10786
10787
10788 /*
10789  * Returns true if the text contains nothing to expand (no dollar signs
10790  * or backquotes).
10791  */
10792
10793 static int
10794 noexpand(char *text)
10795 {
10796         char *p;
10797         char c;
10798
10799         p = text;
10800         while ((c = *p++) != '\0') {
10801                 if (c == CTLQUOTEMARK)
10802                         continue;
10803                 if (c == CTLESC)
10804                         p++;
10805                 else if (SIT(c, BASESYNTAX) == CCTL)
10806                         return 0;
10807         }
10808         return 1;
10809 }
10810
10811
10812 /*
10813  * Return of a legal variable name (a letter or underscore followed by zero or
10814  * more letters, underscores, and digits).
10815  */
10816
10817 static char *
10818 endofname(const char *name)
10819 {
10820         char *p;
10821
10822         p = (char *) name;
10823         if (! is_name(*p))
10824                 return p;
10825         while (*++p) {
10826                 if (! is_in_name(*p))
10827                         break;
10828         }
10829         return p;
10830 }
10831
10832
10833 /*
10834  * Called when an unexpected token is read during the parse.  The argument
10835  * is the token that is expected, or -1 if more than one type of token can
10836  * occur at this point.
10837  */
10838
10839 static void synexpect(int token)
10840 {
10841         char msg[64];
10842         int l;
10843
10844         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10845         if (token >= 0)
10846                 sprintf(msg + l, " (expecting %s)", tokname(token));
10847         synerror(msg);
10848         /* NOTREACHED */
10849 }
10850
10851 static void
10852 synerror(const char *msg)
10853 {
10854         error("Syntax error: %s", msg);
10855         /* NOTREACHED */
10856 }
10857
10858
10859 /*
10860  * called by editline -- any expansions to the prompt
10861  *    should be added here.
10862  */
10863
10864 #ifdef CONFIG_ASH_EXPAND_PRMT
10865 static const char *
10866 expandstr(const char *ps)
10867 {
10868         union node n;
10869
10870         /* XXX Fix (char *) cast. */
10871         setinputstring((char *)ps);
10872         readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10873         popfile();
10874
10875         n.narg.type = NARG;
10876         n.narg.next = NULL;
10877         n.narg.text = wordtext;
10878         n.narg.backquote = backquotelist;
10879
10880         expandarg(&n, NULL, 0);
10881         return stackblock();
10882 }
10883 #endif
10884
10885 static void setprompt(int whichprompt)
10886 {
10887         const char *prompt;
10888 #ifdef CONFIG_ASH_EXPAND_PRMT
10889         struct stackmark smark;
10890 #endif
10891
10892         needprompt = 0;
10893
10894         switch (whichprompt) {
10895         case 1:
10896                 prompt = ps1val();
10897                 break;
10898         case 2:
10899                 prompt = ps2val();
10900                 break;
10901         default:                        /* 0 */
10902                 prompt = nullstr;
10903         }
10904 #ifdef CONFIG_ASH_EXPAND_PRMT
10905         setstackmark(&smark);
10906         stalloc(stackblocksize());
10907 #endif
10908         putprompt(expandstr(prompt));
10909 #ifdef CONFIG_ASH_EXPAND_PRMT
10910         popstackmark(&smark);
10911 #endif
10912 }
10913
10914
10915 static const char *const *findkwd(const char *s)
10916 {
10917         return bsearch(s, tokname_array + KWDOFFSET,
10918                        (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10919                                    sizeof(const char *), pstrcmp);
10920 }
10921
10922 /*      $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $      */
10923
10924 /*
10925  * Code for dealing with input/output redirection.
10926  */
10927
10928 #define EMPTY -2                /* marks an unused slot in redirtab */
10929 #ifndef PIPE_BUF
10930 # define PIPESIZE 4096          /* amount of buffering in a pipe */
10931 #else
10932 # define PIPESIZE PIPE_BUF
10933 #endif
10934
10935 /*
10936  * Open a file in noclobber mode.
10937  * The code was copied from bash.
10938  */
10939 static inline int
10940 noclobberopen(const char *fname)
10941 {
10942         int r, fd;
10943         struct stat finfo, finfo2;
10944
10945         /*
10946          * If the file exists and is a regular file, return an error
10947          * immediately.
10948          */
10949         r = stat(fname, &finfo);
10950         if (r == 0 && S_ISREG(finfo.st_mode)) {
10951                 errno = EEXIST;
10952                 return -1;
10953         }
10954
10955         /*
10956          * If the file was not present (r != 0), make sure we open it
10957          * exclusively so that if it is created before we open it, our open
10958          * will fail.  Make sure that we do not truncate an existing file.
10959          * Note that we don't turn on O_EXCL unless the stat failed -- if the
10960          * file was not a regular file, we leave O_EXCL off.
10961          */
10962         if (r != 0)
10963                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10964         fd = open(fname, O_WRONLY|O_CREAT, 0666);
10965
10966         /* If the open failed, return the file descriptor right away. */
10967         if (fd < 0)
10968                 return fd;
10969
10970         /*
10971          * OK, the open succeeded, but the file may have been changed from a
10972          * non-regular file to a regular file between the stat and the open.
10973          * We are assuming that the O_EXCL open handles the case where FILENAME
10974          * did not exist and is symlinked to an existing file between the stat
10975          * and open.
10976          */
10977
10978         /*
10979          * If we can open it and fstat the file descriptor, and neither check
10980          * revealed that it was a regular file, and the file has not been
10981          * replaced, return the file descriptor.
10982          */
10983          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10984              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10985                 return fd;
10986
10987         /* The file has been replaced.  badness. */
10988         close(fd);
10989         errno = EEXIST;
10990         return -1;
10991 }
10992
10993 /*
10994  * Handle here documents.  Normally we fork off a process to write the
10995  * data to a pipe.  If the document is short, we can stuff the data in
10996  * the pipe without forking.
10997  */
10998
10999 static inline int
11000 openhere(union node *redir)
11001 {
11002         int pip[2];
11003         size_t len = 0;
11004
11005         if (pipe(pip) < 0)
11006                 error("Pipe call failed");
11007         if (redir->type == NHERE) {
11008                 len = strlen(redir->nhere.doc->narg.text);
11009                 if (len <= PIPESIZE) {
11010                         bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11011                         goto out;
11012                 }
11013         }
11014         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11015                 close(pip[0]);
11016                 signal(SIGINT, SIG_IGN);
11017                 signal(SIGQUIT, SIG_IGN);
11018                 signal(SIGHUP, SIG_IGN);
11019 #ifdef SIGTSTP
11020                 signal(SIGTSTP, SIG_IGN);
11021 #endif
11022                 signal(SIGPIPE, SIG_DFL);
11023                 if (redir->type == NHERE)
11024                         bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11025                 else
11026                         expandhere(redir->nhere.doc, pip[1]);
11027                 _exit(0);
11028         }
11029 out:
11030         close(pip[1]);
11031         return pip[0];
11032 }
11033
11034 static int
11035 openredirect(union node *redir)
11036 {
11037         char *fname;
11038         int f;
11039
11040         switch (redir->nfile.type) {
11041         case NFROM:
11042                 fname = redir->nfile.expfname;
11043                 if ((f = open(fname, O_RDONLY)) < 0)
11044                         goto eopen;
11045                 break;
11046         case NFROMTO:
11047                 fname = redir->nfile.expfname;
11048                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11049                         goto ecreate;
11050                 break;
11051         case NTO:
11052                 /* Take care of noclobber mode. */
11053                 if (Cflag) {
11054                         fname = redir->nfile.expfname;
11055                         if ((f = noclobberopen(fname)) < 0)
11056                                 goto ecreate;
11057                         break;
11058                 }
11059                 /* FALLTHROUGH */
11060         case NCLOBBER:
11061                 fname = redir->nfile.expfname;
11062                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11063                         goto ecreate;
11064                 break;
11065         case NAPPEND:
11066                 fname = redir->nfile.expfname;
11067                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11068                         goto ecreate;
11069                 break;
11070         default:
11071 #ifdef DEBUG
11072                 abort();
11073 #endif
11074                 /* Fall through to eliminate warning. */
11075         case NTOFD:
11076         case NFROMFD:
11077                 f = -1;
11078                 break;
11079         case NHERE:
11080         case NXHERE:
11081                 f = openhere(redir);
11082                 break;
11083         }
11084
11085         return f;
11086 ecreate:
11087         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11088 eopen:
11089         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11090 }
11091
11092 static inline void
11093 dupredirect(union node *redir, int f)
11094 {
11095         int fd = redir->nfile.fd;
11096
11097         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11098                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11099                                 copyfd(redir->ndup.dupfd, fd);
11100                 }
11101                 return;
11102         }
11103
11104         if (f != fd) {
11105                 copyfd(f, fd);
11106                 close(f);
11107         }
11108         return;
11109 }
11110
11111 /*
11112  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
11113  * old file descriptors are stashed away so that the redirection can be
11114  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
11115  * standard output, and the standard error if it becomes a duplicate of
11116  * stdout, is saved in memory.
11117  */
11118
11119 static void
11120 redirect(union node *redir, int flags)
11121 {
11122         union node *n;
11123         struct redirtab *sv;
11124         int i;
11125         int fd;
11126         int newfd;
11127         int *p;
11128         nullredirs++;
11129         if (!redir) {
11130                 return;
11131         }
11132         sv = NULL;
11133         INTOFF;
11134         if (flags & REDIR_PUSH) {
11135                 struct redirtab *q;
11136                 q = ckmalloc(sizeof (struct redirtab));
11137                 q->next = redirlist;
11138                 redirlist = q;
11139                 q->nullredirs = nullredirs - 1;
11140                 for (i = 0 ; i < 10 ; i++)
11141                         q->renamed[i] = EMPTY;
11142                 nullredirs = 0;
11143                 sv = q;
11144         }
11145         n = redir;
11146         do {
11147                 fd = n->nfile.fd;
11148                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11149                     n->ndup.dupfd == fd)
11150                         continue; /* redirect from/to same file descriptor */
11151
11152                 newfd = openredirect(n);
11153                 if (fd == newfd)
11154                         continue;
11155                 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11156                         i = fcntl(fd, F_DUPFD, 10);
11157
11158                         if (i == -1) {
11159                                 i = errno;
11160                                 if (i != EBADF) {
11161                                         close(newfd);
11162                                         errno = i;
11163                                         error("%d: %m", fd);
11164                                         /* NOTREACHED */
11165                                 }
11166                         } else {
11167                                 *p = i;
11168                                 close(fd);
11169                         }
11170                 } else {
11171                         close(fd);
11172                 }
11173                 dupredirect(n, newfd);
11174         } while ((n = n->nfile.next));
11175         INTON;
11176         if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11177                 preverrout_fd = sv->renamed[2];
11178 }
11179
11180
11181 /*
11182  * Undo the effects of the last redirection.
11183  */
11184
11185 void
11186 popredir(int drop)
11187 {
11188         struct redirtab *rp;
11189         int i;
11190
11191         if (--nullredirs >= 0)
11192                 return;
11193         INTOFF;
11194         rp = redirlist;
11195         for (i = 0 ; i < 10 ; i++) {
11196                 if (rp->renamed[i] != EMPTY) {
11197                         if (!drop) {
11198                                 close(i);
11199                                 copyfd(rp->renamed[i], i);
11200                         }
11201                         close(rp->renamed[i]);
11202                 }
11203         }
11204         redirlist = rp->next;
11205         nullredirs = rp->nullredirs;
11206         ckfree(rp);
11207         INTON;
11208 }
11209
11210 /*
11211  * Undo all redirections.  Called on error or interrupt.
11212  */
11213
11214 /*
11215  * Discard all saved file descriptors.
11216  */
11217
11218 void
11219 clearredir(int drop)
11220 {
11221         for (;;) {
11222                 nullredirs = 0;
11223                 if (!redirlist)
11224                         break;
11225                 popredir(drop);
11226         }
11227 }
11228
11229
11230 /*
11231  * Copy a file descriptor to be >= to.  Returns -1
11232  * if the source file descriptor is closed, EMPTY if there are no unused
11233  * file descriptors left.
11234  */
11235
11236 int
11237 copyfd(int from, int to)
11238 {
11239         int newfd;
11240
11241         newfd = fcntl(from, F_DUPFD, to);
11242         if (newfd < 0) {
11243                 if (errno == EMFILE)
11244                         return EMPTY;
11245                 else
11246                         error("%d: %m", from);
11247         }
11248         return newfd;
11249 }
11250
11251
11252 int
11253 redirectsafe(union node *redir, int flags)
11254 {
11255         int err;
11256         volatile int saveint;
11257         struct jmploc *volatile savehandler = handler;
11258         struct jmploc jmploc;
11259
11260         SAVEINT(saveint);
11261         if (!(err = setjmp(jmploc.loc) * 2)) {
11262                 handler = &jmploc;
11263                 redirect(redir, flags);
11264         }
11265         handler = savehandler;
11266         if (err && exception != EXERROR)
11267                 longjmp(handler->loc, 1);
11268         RESTOREINT(saveint);
11269         return err;
11270 }
11271
11272 /*      $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $    */
11273
11274 #ifdef DEBUG
11275 static void shtree(union node *, int, char *, FILE*);
11276 static void shcmd(union node *, FILE *);
11277 static void sharg(union node *, FILE *);
11278 static void indent(int, char *, FILE *);
11279 static void trstring(char *);
11280
11281
11282 void
11283 showtree(union node *n)
11284 {
11285         trputs("showtree called\n");
11286         shtree(n, 1, NULL, stdout);
11287 }
11288
11289
11290 static void
11291 shtree(union node *n, int ind, char *pfx, FILE *fp)
11292 {
11293         struct nodelist *lp;
11294         const char *s;
11295
11296         if (n == NULL)
11297                 return;
11298
11299         indent(ind, pfx, fp);
11300         switch(n->type) {
11301         case NSEMI:
11302                 s = "; ";
11303                 goto binop;
11304         case NAND:
11305                 s = " && ";
11306                 goto binop;
11307         case NOR:
11308                 s = " || ";
11309 binop:
11310                 shtree(n->nbinary.ch1, ind, NULL, fp);
11311            /*    if (ind < 0) */
11312                         fputs(s, fp);
11313                 shtree(n->nbinary.ch2, ind, NULL, fp);
11314                 break;
11315         case NCMD:
11316                 shcmd(n, fp);
11317                 if (ind >= 0)
11318                         putc('\n', fp);
11319                 break;
11320         case NPIPE:
11321                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11322                         shcmd(lp->n, fp);
11323                         if (lp->next)
11324                                 fputs(" | ", fp);
11325                 }
11326                 if (n->npipe.backgnd)
11327                         fputs(" &", fp);
11328                 if (ind >= 0)
11329                         putc('\n', fp);
11330                 break;
11331         default:
11332                 fprintf(fp, "<node type %d>", n->type);
11333                 if (ind >= 0)
11334                         putc('\n', fp);
11335                 break;
11336         }
11337 }
11338
11339
11340 static void
11341 shcmd(union node *cmd, FILE *fp)
11342 {
11343         union node *np;
11344         int first;
11345         const char *s;
11346         int dftfd;
11347
11348         first = 1;
11349         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11350                 if (! first)
11351                         putchar(' ');
11352                 sharg(np, fp);
11353                 first = 0;
11354         }
11355         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11356                 if (! first)
11357                         putchar(' ');
11358                 switch (np->nfile.type) {
11359                         case NTO:       s = ">";  dftfd = 1; break;
11360                         case NCLOBBER:  s = ">|"; dftfd = 1; break;
11361                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11362                         case NTOFD:     s = ">&"; dftfd = 1; break;
11363                         case NFROM:     s = "<";  dftfd = 0; break;
11364                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11365                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11366                         default:        s = "*error*"; dftfd = 0; break;
11367                 }
11368                 if (np->nfile.fd != dftfd)
11369                         fprintf(fp, "%d", np->nfile.fd);
11370                 fputs(s, fp);
11371                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11372                         fprintf(fp, "%d", np->ndup.dupfd);
11373                 } else {
11374                         sharg(np->nfile.fname, fp);
11375                 }
11376                 first = 0;
11377         }
11378 }
11379
11380
11381
11382 static void
11383 sharg(union node *arg, FILE *fp)
11384 {
11385         char *p;
11386         struct nodelist *bqlist;
11387         int subtype;
11388
11389         if (arg->type != NARG) {
11390                 out1fmt("<node type %d>\n", arg->type);
11391                 abort();
11392         }
11393         bqlist = arg->narg.backquote;
11394         for (p = arg->narg.text ; *p ; p++) {
11395                 switch (*p) {
11396                 case CTLESC:
11397                         putc(*++p, fp);
11398                         break;
11399                 case CTLVAR:
11400                         putc('$', fp);
11401                         putc('{', fp);
11402                         subtype = *++p;
11403                         if (subtype == VSLENGTH)
11404                                 putc('#', fp);
11405
11406                         while (*p != '=')
11407                                 putc(*p++, fp);
11408
11409                         if (subtype & VSNUL)
11410                                 putc(':', fp);
11411
11412                         switch (subtype & VSTYPE) {
11413                         case VSNORMAL:
11414                                 putc('}', fp);
11415                                 break;
11416                         case VSMINUS:
11417                                 putc('-', fp);
11418                                 break;
11419                         case VSPLUS:
11420                                 putc('+', fp);
11421                                 break;
11422                         case VSQUESTION:
11423                                 putc('?', fp);
11424                                 break;
11425                         case VSASSIGN:
11426                                 putc('=', fp);
11427                                 break;
11428                         case VSTRIMLEFT:
11429                                 putc('#', fp);
11430                                 break;
11431                         case VSTRIMLEFTMAX:
11432                                 putc('#', fp);
11433                                 putc('#', fp);
11434                                 break;
11435                         case VSTRIMRIGHT:
11436                                 putc('%', fp);
11437                                 break;
11438                         case VSTRIMRIGHTMAX:
11439                                 putc('%', fp);
11440                                 putc('%', fp);
11441                                 break;
11442                         case VSLENGTH:
11443                                 break;
11444                         default:
11445                                 out1fmt("<subtype %d>", subtype);
11446                         }
11447                         break;
11448                 case CTLENDVAR:
11449                      putc('}', fp);
11450                      break;
11451                 case CTLBACKQ:
11452                 case CTLBACKQ|CTLQUOTE:
11453                         putc('$', fp);
11454                         putc('(', fp);
11455                         shtree(bqlist->n, -1, NULL, fp);
11456                         putc(')', fp);
11457                         break;
11458                 default:
11459                         putc(*p, fp);
11460                         break;
11461                 }
11462         }
11463 }
11464
11465
11466 static void
11467 indent(int amount, char *pfx, FILE *fp)
11468 {
11469         int i;
11470
11471         for (i = 0 ; i < amount ; i++) {
11472                 if (pfx && i == amount - 1)
11473                         fputs(pfx, fp);
11474                 putc('\t', fp);
11475         }
11476 }
11477
11478
11479
11480 /*
11481  * Debugging stuff.
11482  */
11483
11484
11485 FILE *tracefile;
11486
11487
11488 void
11489 trputc(int c)
11490 {
11491         if (debug != 1)
11492                 return;
11493         putc(c, tracefile);
11494 }
11495
11496 void
11497 trace(const char *fmt, ...)
11498 {
11499         va_list va;
11500
11501         if (debug != 1)
11502                 return;
11503         va_start(va, fmt);
11504         (void) vfprintf(tracefile, fmt, va);
11505         va_end(va);
11506 }
11507
11508 void
11509 tracev(const char *fmt, va_list va)
11510 {
11511         if (debug != 1)
11512                 return;
11513         (void) vfprintf(tracefile, fmt, va);
11514 }
11515
11516
11517 void
11518 trputs(const char *s)
11519 {
11520         if (debug != 1)
11521                 return;
11522         fputs(s, tracefile);
11523 }
11524
11525
11526 static void
11527 trstring(char *s)
11528 {
11529         char *p;
11530         char c;
11531
11532         if (debug != 1)
11533                 return;
11534         putc('"', tracefile);
11535         for (p = s ; *p ; p++) {
11536                 switch (*p) {
11537                 case '\n':  c = 'n';  goto backslash;
11538                 case '\t':  c = 't';  goto backslash;
11539                 case '\r':  c = 'r';  goto backslash;
11540                 case '"':  c = '"';  goto backslash;
11541                 case '\\':  c = '\\';  goto backslash;
11542                 case CTLESC:  c = 'e';  goto backslash;
11543                 case CTLVAR:  c = 'v';  goto backslash;
11544                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11545                 case CTLBACKQ:  c = 'q';  goto backslash;
11546                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11547 backslash:        putc('\\', tracefile);
11548                         putc(c, tracefile);
11549                         break;
11550                 default:
11551                         if (*p >= ' ' && *p <= '~')
11552                                 putc(*p, tracefile);
11553                         else {
11554                                 putc('\\', tracefile);
11555                                 putc(*p >> 6 & 03, tracefile);
11556                                 putc(*p >> 3 & 07, tracefile);
11557                                 putc(*p & 07, tracefile);
11558                         }
11559                         break;
11560                 }
11561         }
11562         putc('"', tracefile);
11563 }
11564
11565
11566 void
11567 trargs(char **ap)
11568 {
11569         if (debug != 1)
11570                 return;
11571         while (*ap) {
11572                 trstring(*ap++);
11573                 if (*ap)
11574                         putc(' ', tracefile);
11575                 else
11576                         putc('\n', tracefile);
11577         }
11578 }
11579
11580
11581 void
11582 opentrace(void)
11583 {
11584         char s[100];
11585 #ifdef O_APPEND
11586         int flags;
11587 #endif
11588
11589         if (debug != 1) {
11590                 if (tracefile)
11591                         fflush(tracefile);
11592                 /* leave open because libedit might be using it */
11593                 return;
11594         }
11595         scopy("./trace", s);
11596         if (tracefile) {
11597                 if (!freopen(s, "a", tracefile)) {
11598                         fprintf(stderr, "Can't re-open %s\n", s);
11599                         debug = 0;
11600                         return;
11601                 }
11602         } else {
11603                 if ((tracefile = fopen(s, "a")) == NULL) {
11604                         fprintf(stderr, "Can't open %s\n", s);
11605                         debug = 0;
11606                         return;
11607                 }
11608         }
11609 #ifdef O_APPEND
11610         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11611                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11612 #endif
11613         setlinebuf(tracefile);
11614         fputs("\nTracing started.\n", tracefile);
11615 }
11616 #endif /* DEBUG */
11617
11618
11619 /*      $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $       */
11620
11621 /*
11622  * Sigmode records the current value of the signal handlers for the various
11623  * modes.  A value of zero means that the current handler is not known.
11624  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11625  */
11626
11627 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
11628 #define S_CATCH 2               /* signal is caught */
11629 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
11630 #define S_HARD_IGN 4            /* signal is ignored permenantly */
11631 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
11632
11633
11634
11635 /*
11636  * The trap builtin.
11637  */
11638
11639 int
11640 trapcmd(int argc, char **argv)
11641 {
11642         char *action;
11643         char **ap;
11644         int signo;
11645
11646         nextopt(nullstr);
11647         ap = argptr;
11648         if (!*ap) {
11649                 for (signo = 0 ; signo < NSIG ; signo++) {
11650                         if (trap[signo] != NULL) {
11651                                 const char *sn;
11652
11653                                 sn = u_signal_names(0, &signo, 0);
11654                                 if (sn == NULL)
11655                                         sn = "???";
11656                                 out1fmt("trap -- %s %s\n",
11657                                         single_quote(trap[signo]), sn);
11658                         }
11659                 }
11660                 return 0;
11661         }
11662         if (!ap[1])
11663                 action = NULL;
11664         else
11665                 action = *ap++;
11666         while (*ap) {
11667                 if ((signo = decode_signal(*ap, 0)) < 0)
11668                         error("%s: bad trap", *ap);
11669                 INTOFF;
11670                 if (action) {
11671                         if (action[0] == '-' && action[1] == '\0')
11672                                 action = NULL;
11673                         else
11674                                 action = savestr(action);
11675                 }
11676                 if (trap[signo])
11677                         ckfree(trap[signo]);
11678                 trap[signo] = action;
11679                 if (signo != 0)
11680                         setsignal(signo);
11681                 INTON;
11682                 ap++;
11683         }
11684         return 0;
11685 }
11686
11687
11688 /*
11689  * Clear traps on a fork.
11690  */
11691
11692 void
11693 clear_traps(void)
11694 {
11695         char **tp;
11696
11697         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11698                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
11699                         INTOFF;
11700                         ckfree(*tp);
11701                         *tp = NULL;
11702                         if (tp != &trap[0])
11703                                 setsignal(tp - trap);
11704                         INTON;
11705                 }
11706         }
11707 }
11708
11709
11710 /*
11711  * Set the signal handler for the specified signal.  The routine figures
11712  * out what it should be set to.
11713  */
11714
11715 void
11716 setsignal(int signo)
11717 {
11718         int action;
11719         char *t, tsig;
11720         struct sigaction act;
11721
11722         if ((t = trap[signo]) == NULL)
11723                 action = S_DFL;
11724         else if (*t != '\0')
11725                 action = S_CATCH;
11726         else
11727                 action = S_IGN;
11728         if (rootshell && action == S_DFL) {
11729                 switch (signo) {
11730                 case SIGINT:
11731                         if (iflag || minusc || sflag == 0)
11732                                 action = S_CATCH;
11733                         break;
11734                 case SIGQUIT:
11735 #ifdef DEBUG
11736                         if (debug)
11737                                 break;
11738 #endif
11739                         /* FALLTHROUGH */
11740                 case SIGTERM:
11741                         if (iflag)
11742                                 action = S_IGN;
11743                         break;
11744 #if JOBS
11745                 case SIGTSTP:
11746                 case SIGTTOU:
11747                         if (mflag)
11748                                 action = S_IGN;
11749                         break;
11750 #endif
11751                 }
11752         }
11753
11754         t = &sigmode[signo - 1];
11755         tsig = *t;
11756         if (tsig == 0) {
11757                 /*
11758                  * current setting unknown
11759                  */
11760                 if (sigaction(signo, 0, &act) == -1) {
11761                         /*
11762                          * Pretend it worked; maybe we should give a warning
11763                          * here, but other shells don't. We don't alter
11764                          * sigmode, so that we retry every time.
11765                          */
11766                         return;
11767                 }
11768                 if (act.sa_handler == SIG_IGN) {
11769                         if (mflag && (signo == SIGTSTP ||
11770                              signo == SIGTTIN || signo == SIGTTOU)) {
11771                                 tsig = S_IGN;   /* don't hard ignore these */
11772                         } else
11773                                 tsig = S_HARD_IGN;
11774                 } else {
11775                         tsig = S_RESET; /* force to be set */
11776                 }
11777         }
11778         if (tsig == S_HARD_IGN || tsig == action)
11779                 return;
11780         switch (action) {
11781         case S_CATCH:
11782                 act.sa_handler = onsig;
11783                 break;
11784         case S_IGN:
11785                 act.sa_handler = SIG_IGN;
11786                 break;
11787         default:
11788                 act.sa_handler = SIG_DFL;
11789         }
11790         *t = action;
11791         act.sa_flags = 0;
11792         sigfillset(&act.sa_mask);
11793         sigaction(signo, &act, 0);
11794 }
11795
11796 /*
11797  * Ignore a signal.
11798  */
11799
11800 void
11801 ignoresig(int signo)
11802 {
11803         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11804                 signal(signo, SIG_IGN);
11805         }
11806         sigmode[signo - 1] = S_HARD_IGN;
11807 }
11808
11809
11810 /*
11811  * Signal handler.
11812  */
11813
11814 void
11815 onsig(int signo)
11816 {
11817         gotsig[signo - 1] = 1;
11818         pendingsigs = signo;
11819
11820         if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11821                 if (!suppressint)
11822                         onint();
11823                 intpending = 1;
11824         }
11825 }
11826
11827
11828 /*
11829  * Called to execute a trap.  Perhaps we should avoid entering new trap
11830  * handlers while we are executing a trap handler.
11831  */
11832
11833 void
11834 dotrap(void)
11835 {
11836         char *p;
11837         char *q;
11838         int savestatus;
11839
11840         savestatus = exitstatus;
11841         q = gotsig;
11842         while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11843                 *p = 0;
11844                 p = trap[p - q + 1];
11845                 if (!p)
11846                         continue;
11847                 evalstring(p);
11848                 exitstatus = savestatus;
11849         }
11850 }
11851
11852
11853 /*
11854  * Controls whether the shell is interactive or not.
11855  */
11856
11857 void
11858 setinteractive(int on)
11859 {
11860         static int is_interactive;
11861
11862         if (++on == is_interactive)
11863                 return;
11864         is_interactive = on;
11865         setsignal(SIGINT);
11866         setsignal(SIGQUIT);
11867         setsignal(SIGTERM);
11868 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11869                 if(is_interactive > 1) {
11870                         /* Looks like they want an interactive shell */
11871                         static int do_banner;
11872
11873                                 if(!do_banner) {
11874                                         out1fmt(
11875                         "\n\n" BB_BANNER " Built-in shell (ash)\n"
11876                         "Enter 'help' for a list of built-in commands.\n\n");
11877                                         do_banner++;
11878                                 }
11879                 }
11880 #endif
11881 }
11882
11883
11884 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11885 /*** List the available builtins ***/
11886
11887 static int helpcmd(int argc, char **argv)
11888 {
11889         int col, i;
11890
11891         out1fmt("\nBuilt-in commands:\n-------------------\n");
11892         for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11893                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11894                                           builtincmd[i].name + 1);
11895                 if (col > 60) {
11896                         out1fmt("\n");
11897                         col = 0;
11898                 }
11899         }
11900 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11901         {
11902                 extern const struct BB_applet applets[];
11903                 extern const size_t NUM_APPLETS;
11904
11905                 for (i = 0; i < NUM_APPLETS; i++) {
11906
11907                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11908                         if (col > 60) {
11909                                 out1fmt("\n");
11910                                 col = 0;
11911                         }
11912                 }
11913         }
11914 #endif
11915         out1fmt("\n\n");
11916         return EXIT_SUCCESS;
11917 }
11918 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11919
11920 /*
11921  * Called to exit the shell.
11922  */
11923
11924 void
11925 exitshell(void)
11926 {
11927         struct jmploc loc;
11928         char *p;
11929         int status;
11930         int jmp;
11931
11932         jmp = setjmp(loc.loc);
11933         status = exitstatus;
11934         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11935         if (jmp)
11936                 goto out;
11937         handler = &loc;
11938         if ((p = trap[0]) != NULL && *p != '\0') {
11939                 trap[0] = NULL;
11940                 evalstring(p);
11941         }
11942         flushall();
11943         setjobctl(0);
11944 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11945         if (iflag && rootshell) {
11946                 const char *hp = lookupvar("HISTFILE");
11947
11948                 if(hp != NULL )
11949                         save_history ( hp );
11950         }
11951 #endif
11952 out:
11953         _exit(status);
11954         /* NOTREACHED */
11955 }
11956
11957 static int decode_signal(const char *string, int minsig)
11958 {
11959         int signo;
11960         const char *name = u_signal_names(string, &signo, minsig);
11961
11962         return name ? signo : -1;
11963 }
11964
11965 /*      $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $     */
11966
11967 static struct var *vartab[VTABSIZE];
11968
11969 static int vpcmp(const void *, const void *);
11970 static struct var **findvar(struct var **, const char *);
11971
11972 /*
11973  * Initialize the variable symbol tables and import the environment
11974  */
11975
11976
11977 #ifdef CONFIG_ASH_GETOPTS
11978 /*
11979  * Safe version of setvar, returns 1 on success 0 on failure.
11980  */
11981
11982 int
11983 setvarsafe(const char *name, const char *val, int flags)
11984 {
11985         int err;
11986         volatile int saveint;
11987         struct jmploc *volatile savehandler = handler;
11988         struct jmploc jmploc;
11989
11990         SAVEINT(saveint);
11991         if (setjmp(jmploc.loc))
11992                 err = 1;
11993         else {
11994                 handler = &jmploc;
11995                 setvar(name, val, flags);
11996                 err = 0;
11997         }
11998         handler = savehandler;
11999         RESTOREINT(saveint);
12000         return err;
12001 }
12002 #endif
12003
12004 /*
12005  * Set the value of a variable.  The flags argument is ored with the
12006  * flags of the variable.  If val is NULL, the variable is unset.
12007  */
12008
12009 static void
12010 setvar(const char *name, const char *val, int flags)
12011 {
12012         char *p, *q;
12013         size_t namelen;
12014         char *nameeq;
12015         size_t vallen;
12016
12017         q = endofname(name);
12018         p = strchrnul(q, '=');
12019         namelen = p - name;
12020         if (!namelen || p != q)
12021                 error("%.*s: bad variable name", namelen, name);
12022         vallen = 0;
12023         if (val == NULL) {
12024                 flags |= VUNSET;
12025         } else {
12026                 vallen = strlen(val);
12027         }
12028         INTOFF;
12029         p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12030         *p++ = '\0';
12031         if (val) {
12032                 p[-1] = '=';
12033                 p = mempcpy(p, val, vallen);
12034         }
12035         *p = '\0';
12036         setvareq(nameeq, flags | VNOSAVE);
12037         INTON;
12038 }
12039
12040
12041 /*
12042  * Same as setvar except that the variable and value are passed in
12043  * the first argument as name=value.  Since the first argument will
12044  * be actually stored in the table, it should not be a string that
12045  * will go away.
12046  * Called with interrupts off.
12047  */
12048
12049 void
12050 setvareq(char *s, int flags)
12051 {
12052         struct var *vp, **vpp;
12053
12054         vpp = hashvar(s);
12055         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12056         vp = *findvar(vpp, s);
12057         if (vp) {
12058                 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12059                         const char *n;
12060
12061                         if (flags & VNOSAVE)
12062                                 free(s);
12063                         n = vp->text;
12064                         error("%.*s: is read only", strchrnul(n, '=') - n, n);
12065                 }
12066
12067                 if (flags & VNOSET)
12068                         return;
12069
12070                 if (vp->func && (flags & VNOFUNC) == 0)
12071                         (*vp->func)(strchrnul(s, '=') + 1);
12072
12073                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12074                         ckfree(vp->text);
12075
12076                 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12077         } else {
12078                 if (flags & VNOSET)
12079                         return;
12080                 /* not found */
12081                 vp = ckmalloc(sizeof (*vp));
12082                 vp->next = *vpp;
12083                 vp->func = NULL;
12084                 *vpp = vp;
12085         }
12086         if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12087                 s = savestr(s);
12088         vp->text = s;
12089         vp->flags = flags;
12090 }
12091
12092
12093 /*
12094  * Process a linked list of variable assignments.
12095  */
12096
12097 static void
12098 listsetvar(struct strlist *list_set_var, int flags)
12099 {
12100         struct strlist *lp = list_set_var;
12101
12102         if (!lp)
12103                 return;
12104         INTOFF;
12105         do {
12106                 setvareq(lp->text, flags);
12107         } while ((lp = lp->next));
12108         INTON;
12109 }
12110
12111
12112 /*
12113  * Find the value of a variable.  Returns NULL if not set.
12114  */
12115
12116 static char *
12117 lookupvar(const char *name)
12118 {
12119         struct var *v;
12120
12121         if ((v = *findvar(hashvar(name), name))) {
12122 #ifdef DYNAMIC_VAR
12123         /*
12124          * Dynamic variables are implemented roughly the same way they are
12125          * in bash. Namely, they're "special" so long as they aren't unset.
12126          * As soon as they're unset, they're no longer dynamic, and dynamic
12127          * lookup will no longer happen at that point. -- PFM.
12128          */
12129                 if((v->flags & VDYNAMIC))
12130                         (*v->func)(NULL);
12131 #endif
12132                 if(!(v->flags & VUNSET))
12133                         return strchrnul(v->text, '=') + 1;
12134         }
12135
12136         return NULL;
12137 }
12138
12139
12140 /*
12141  * Search the environment of a builtin command.
12142  */
12143
12144 static char *
12145 bltinlookup(const char *name)
12146 {
12147         struct strlist *sp;
12148
12149         for (sp = cmdenviron ; sp ; sp = sp->next) {
12150                 if (varequal(sp->text, name))
12151                         return strchrnul(sp->text, '=') + 1;
12152         }
12153         return lookupvar(name);
12154 }
12155
12156
12157 /*
12158  * Generate a list of variables satisfying the given conditions.
12159  */
12160
12161 static char **
12162 listvars(int on, int off, char ***end)
12163 {
12164         struct var **vpp;
12165         struct var *vp;
12166         char **ep;
12167         int mask;
12168
12169         STARTSTACKSTR(ep);
12170         vpp = vartab;
12171         mask = on | off;
12172         do {
12173                 for (vp = *vpp ; vp ; vp = vp->next)
12174                         if ((vp->flags & mask) == on) {
12175                                 if (ep == stackstrend())
12176                                         ep = growstackstr();
12177                                 *ep++ = (char *) vp->text;
12178                         }
12179         } while (++vpp < vartab + VTABSIZE);
12180         if (ep == stackstrend())
12181                 ep = growstackstr();
12182         if (end)
12183                 *end = ep;
12184         *ep++ = NULL;
12185         return grabstackstr(ep);
12186 }
12187
12188
12189 /*
12190  * POSIX requires that 'set' (but not export or readonly) output the
12191  * variables in lexicographic order - by the locale's collating order (sigh).
12192  * Maybe we could keep them in an ordered balanced binary tree
12193  * instead of hashed lists.
12194  * For now just roll 'em through qsort for printing...
12195  */
12196
12197 static int
12198 showvars(const char *sep_prefix, int on, int off)
12199 {
12200         const char *sep;
12201         char **ep, **epend;
12202
12203         ep = listvars(on, off, &epend);
12204         qsort(ep, epend - ep, sizeof(char *), vpcmp);
12205
12206         sep = *sep_prefix ? spcstr : sep_prefix;
12207
12208         for (; ep < epend; ep++) {
12209                 const char *p;
12210                 const char *q;
12211
12212                 p = strchrnul(*ep, '=');
12213                 q = nullstr;
12214                 if (*p)
12215                         q = single_quote(++p);
12216
12217                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12218         }
12219
12220         return 0;
12221 }
12222
12223
12224
12225 /*
12226  * The export and readonly commands.
12227  */
12228
12229 static int
12230 exportcmd(int argc, char **argv)
12231 {
12232         struct var *vp;
12233         char *name;
12234         const char *p;
12235         char **aptr;
12236         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12237         int notp;
12238
12239         notp = nextopt("p") - 'p';
12240         if (notp && ((name = *(aptr = argptr)))) {
12241                 do {
12242                         if ((p = strchr(name, '=')) != NULL) {
12243                                 p++;
12244                         } else {
12245                                 if ((vp = *findvar(hashvar(name), name))) {
12246                                         vp->flags |= flag;
12247                                         continue;
12248                                 }
12249                         }
12250                         setvar(name, p, flag);
12251                 } while ((name = *++aptr) != NULL);
12252         } else {
12253                 showvars(argv[0], flag, 0);
12254         }
12255         return 0;
12256 }
12257
12258
12259 /*
12260  * Make a variable a local variable.  When a variable is made local, it's
12261  * value and flags are saved in a localvar structure.  The saved values
12262  * will be restored when the shell function returns.  We handle the name
12263  * "-" as a special case.
12264  */
12265
12266 static inline void
12267 mklocal(char *name)
12268 {
12269         struct localvar *lvp;
12270         struct var **vpp;
12271         struct var *vp;
12272
12273         INTOFF;
12274         lvp = ckmalloc(sizeof (struct localvar));
12275         if (name[0] == '-' && name[1] == '\0') {
12276                 char *p;
12277                 p = ckmalloc(sizeof(optlist));
12278                 lvp->text = memcpy(p, optlist, sizeof(optlist));
12279                 vp = NULL;
12280         } else {
12281                 char *eq;
12282
12283                 vpp = hashvar(name);
12284                 vp = *findvar(vpp, name);
12285                 eq = strchr(name, '=');
12286                 if (vp == NULL) {
12287                         if (eq)
12288                                 setvareq(name, VSTRFIXED);
12289                         else
12290                                 setvar(name, NULL, VSTRFIXED);
12291                         vp = *vpp;      /* the new variable */
12292                         lvp->flags = VUNSET;
12293                 } else {
12294                         lvp->text = vp->text;
12295                         lvp->flags = vp->flags;
12296                         vp->flags |= VSTRFIXED|VTEXTFIXED;
12297                         if (eq)
12298                                 setvareq(name, 0);
12299                 }
12300         }
12301         lvp->vp = vp;
12302         lvp->next = localvars;
12303         localvars = lvp;
12304         INTON;
12305 }
12306
12307 /*
12308  * The "local" command.
12309  */
12310
12311 static int
12312 localcmd(int argc, char **argv)
12313 {
12314         char *name;
12315
12316         argv = argptr;
12317         while ((name = *argv++) != NULL) {
12318                 mklocal(name);
12319         }
12320         return 0;
12321 }
12322
12323
12324 /*
12325  * Called after a function returns.
12326  * Interrupts must be off.
12327  */
12328
12329 static void
12330 poplocalvars(void)
12331 {
12332         struct localvar *lvp;
12333         struct var *vp;
12334
12335         while ((lvp = localvars) != NULL) {
12336                 localvars = lvp->next;
12337                 vp = lvp->vp;
12338                 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12339                 if (vp == NULL) {       /* $- saved */
12340                         memcpy(optlist, lvp->text, sizeof(optlist));
12341                         ckfree(lvp->text);
12342                         optschanged();
12343                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12344                         unsetvar(vp->text);
12345                 } else {
12346                         if (vp->func)
12347                                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12348                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12349                                 ckfree(vp->text);
12350                         vp->flags = lvp->flags;
12351                         vp->text = lvp->text;
12352                 }
12353                 ckfree(lvp);
12354         }
12355 }
12356
12357
12358 /*
12359  * The unset builtin command.  We unset the function before we unset the
12360  * variable to allow a function to be unset when there is a readonly variable
12361  * with the same name.
12362  */
12363
12364 int
12365 unsetcmd(int argc, char **argv)
12366 {
12367         char **ap;
12368         int i;
12369         int flag = 0;
12370         int ret = 0;
12371
12372         while ((i = nextopt("vf")) != '\0') {
12373                 flag = i;
12374         }
12375
12376         for (ap = argptr; *ap ; ap++) {
12377                 if (flag != 'f') {
12378                         i = unsetvar(*ap);
12379                         ret |= i;
12380                         if (!(i & 2))
12381                                 continue;
12382                 }
12383                 if (flag != 'v')
12384                         unsetfunc(*ap);
12385         }
12386         return ret & 1;
12387 }
12388
12389
12390 /*
12391  * Unset the specified variable.
12392  */
12393
12394 int
12395 unsetvar(const char *s)
12396 {
12397         struct var **vpp;
12398         struct var *vp;
12399         int retval;
12400
12401         vpp = findvar(hashvar(s), s);
12402         vp = *vpp;
12403         retval = 2;
12404         if (vp) {
12405                 int flags = vp->flags;
12406
12407                 retval = 1;
12408                 if (flags & VREADONLY)
12409                         goto out;
12410 #ifdef DYNAMIC_VAR
12411                 vp->flags &= ~VDYNAMIC;
12412 #endif
12413                 if (flags & VUNSET)
12414                         goto ok;
12415                 if ((flags & VSTRFIXED) == 0) {
12416                         INTOFF;
12417                         if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12418                                 ckfree(vp->text);
12419                         *vpp = vp->next;
12420                         ckfree(vp);
12421                         INTON;
12422                 } else {
12423                         setvar(s, 0, 0);
12424                         vp->flags &= ~VEXPORT;
12425                 }
12426 ok:
12427                 retval = 0;
12428         }
12429
12430 out:
12431         return retval;
12432 }
12433
12434
12435
12436 /*
12437  * Find the appropriate entry in the hash table from the name.
12438  */
12439
12440 static struct var **
12441 hashvar(const char *p)
12442 {
12443         unsigned int hashval;
12444
12445         hashval = ((unsigned char) *p) << 4;
12446         while (*p && *p != '=')
12447                 hashval += (unsigned char) *p++;
12448         return &vartab[hashval % VTABSIZE];
12449 }
12450
12451
12452
12453 /*
12454  * Compares two strings up to the first = or '\0'.  The first
12455  * string must be terminated by '='; the second may be terminated by
12456  * either '=' or '\0'.
12457  */
12458
12459 int
12460 varcmp(const char *p, const char *q)
12461 {
12462         int c, d;
12463
12464         while ((c = *p) == (d = *q)) {
12465                 if (!c || c == '=')
12466                         goto out;
12467                 p++;
12468                 q++;
12469         }
12470         if (c == '=')
12471                 c = 0;
12472         if (d == '=')
12473                 d = 0;
12474 out:
12475         return c - d;
12476 }
12477
12478 static int
12479 vpcmp(const void *a, const void *b)
12480 {
12481         return varcmp(*(const char **)a, *(const char **)b);
12482 }
12483
12484 static struct var **
12485 findvar(struct var **vpp, const char *name)
12486 {
12487         for (; *vpp; vpp = &(*vpp)->next) {
12488                 if (varequal((*vpp)->text, name)) {
12489                         break;
12490                 }
12491         }
12492         return vpp;
12493 }
12494 /*      $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $      */
12495
12496 #include <sys/times.h>
12497
12498 static const unsigned char timescmd_str[] = {
12499         ' ',  offsetof(struct tms, tms_utime),
12500         '\n', offsetof(struct tms, tms_stime),
12501         ' ',  offsetof(struct tms, tms_cutime),
12502         '\n', offsetof(struct tms, tms_cstime),
12503         0
12504 };
12505
12506 static int timescmd(int ac, char **av)
12507 {
12508         long int clk_tck, s, t;
12509         const unsigned char *p;
12510         struct tms buf;
12511
12512         clk_tck = sysconf(_SC_CLK_TCK);
12513         times(&buf);
12514
12515         p = timescmd_str;
12516         do {
12517                 t = *(clock_t *)(((char *) &buf) + p[1]);
12518                 s = t / clk_tck;
12519                 out1fmt("%ldm%ld.%.3lds%c",
12520                         s/60, s%60,
12521                         ((t - s * clk_tck) * 1000) / clk_tck,
12522                         p[0]);
12523         } while (*(p += 2));
12524
12525         return 0;
12526 }
12527
12528 #ifdef CONFIG_ASH_MATH_SUPPORT
12529 static arith_t
12530 dash_arith(const char *s)
12531 {
12532         arith_t result;
12533         int errcode = 0;
12534
12535         INTOFF;
12536         result = arith(s, &errcode);
12537         if (errcode < 0) {
12538                 if (errcode == -3)
12539                         error("exponent less than 0");
12540                 else if (errcode == -2)
12541                         error("divide by zero");
12542                 else if (errcode == -5)
12543                         error("expression recursion loop detected");
12544                 else
12545                         synerror(s);
12546         }
12547         INTON;
12548
12549         return (result);
12550 }
12551
12552
12553 /*
12554  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12555  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12556  *
12557  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12558  */
12559
12560 static int
12561 letcmd(int argc, char **argv)
12562 {
12563         char **ap;
12564         arith_t i;
12565
12566         ap = argv + 1;
12567         if(!*ap)
12568                 error("expression expected");
12569         for (ap = argv + 1; *ap; ap++) {
12570                 i = dash_arith(*ap);
12571         }
12572
12573         return (!i);
12574 }
12575 #endif /* CONFIG_ASH_MATH_SUPPORT */
12576
12577 /*      $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $  */
12578
12579 /*
12580  * Miscellaneous builtins.
12581  */
12582
12583 #undef rflag
12584
12585 #ifdef __GLIBC__
12586 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12587 typedef enum __rlimit_resource rlim_t;
12588 #endif
12589 #endif
12590
12591
12592 /*
12593  * The read builtin.  The -e option causes backslashes to escape the
12594  * following character.
12595  *
12596  * This uses unbuffered input, which may be avoidable in some cases.
12597  */
12598
12599 static int
12600 readcmd(int argc, char **argv)
12601 {
12602         char **ap;
12603         int backslash;
12604         char c;
12605         int rflag;
12606         char *prompt;
12607         const char *ifs;
12608         char *p;
12609         int startword;
12610         int status;
12611         int i;
12612 #if defined(CONFIG_ASH_READ_NCHARS)
12613         int nch_flag = 0;
12614         int nchars = 0;
12615         int silent = 0;
12616         struct termios tty, old_tty;
12617 #endif
12618 #if defined(CONFIG_ASH_READ_TIMEOUT)
12619         fd_set set;
12620         struct timeval ts;
12621
12622         ts.tv_sec = ts.tv_usec = 0;
12623 #endif
12624
12625         rflag = 0;
12626         prompt = NULL;
12627 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12628         while ((i = nextopt("p:rt:n:s")) != '\0')
12629 #elif defined(CONFIG_ASH_READ_NCHARS)
12630         while ((i = nextopt("p:rn:s")) != '\0')
12631 #elif defined(CONFIG_ASH_READ_TIMEOUT)
12632         while ((i = nextopt("p:rt:")) != '\0')
12633 #else
12634         while ((i = nextopt("p:r")) != '\0')
12635 #endif
12636         {
12637                 switch(i) {
12638                 case 'p':
12639                         prompt = optionarg;
12640                         break;
12641 #if defined(CONFIG_ASH_READ_NCHARS)
12642                 case 'n':
12643                         nchars = strtol(optionarg, &p, 10);
12644                         if (*p)
12645                                 error("invalid count");
12646                         nch_flag = (nchars > 0);
12647                         break;
12648                 case 's':
12649                         silent = 1;
12650                         break;
12651 #endif
12652 #if defined(CONFIG_ASH_READ_TIMEOUT)
12653                 case 't':
12654                         ts.tv_sec = strtol(optionarg, &p, 10);
12655                         ts.tv_usec = 0;
12656                         if (*p == '.') {
12657                                 char *p2;
12658                                 if (*++p) {
12659                                         int scale;
12660                                         ts.tv_usec = strtol(p, &p2, 10);
12661                                         if (*p2)
12662                                                 error("invalid timeout");
12663                                         scale = p2 - p;
12664                                         /* normalize to usec */
12665                                         if (scale > 6)
12666                                                 error("invalid timeout");
12667                                         while (scale++ < 6)
12668                                                 ts.tv_usec *= 10;
12669                                 }
12670                         } else if (*p) {
12671                                 error("invalid timeout");
12672                         }
12673                         if ( ! ts.tv_sec && ! ts.tv_usec)
12674                                 error("invalid timeout");
12675                         break;
12676 #endif
12677                 case 'r':
12678                         rflag = 1;
12679                         break;
12680                 default:
12681                         break;
12682                 }
12683         }
12684         if (prompt && isatty(0)) {
12685                 out2str(prompt);
12686         }
12687         if (*(ap = argptr) == NULL)
12688                 error("arg count");
12689         if ((ifs = bltinlookup("IFS")) == NULL)
12690                 ifs = defifs;
12691 #if defined(CONFIG_ASH_READ_NCHARS)
12692         if (nch_flag || silent) {
12693                 tcgetattr(0, &tty);
12694                 old_tty = tty;
12695                 if (nch_flag) {
12696                     tty.c_lflag &= ~ICANON;
12697                     tty.c_cc[VMIN] = nchars;
12698                 }
12699                 if (silent) {
12700                     tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12701
12702                 }
12703                 tcsetattr(0, TCSANOW, &tty);
12704         }
12705 #endif
12706 #if defined(CONFIG_ASH_READ_TIMEOUT)
12707         if (ts.tv_sec || ts.tv_usec) {
12708                 FD_ZERO (&set);
12709                 FD_SET (0, &set);
12710
12711                 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12712                 if (!i) {
12713 #if defined(CONFIG_ASH_READ_NCHARS)
12714                         if (nch_flag)
12715                                 tcsetattr(0, TCSANOW, &old_tty);
12716 #endif
12717                         return 1;
12718                 }
12719         }
12720 #endif
12721         status = 0;
12722         startword = 1;
12723         backslash = 0;
12724         STARTSTACKSTR(p);
12725 #if defined(CONFIG_ASH_READ_NCHARS)
12726         while (!nch_flag || nchars--)
12727 #else
12728         for (;;)
12729 #endif
12730         {
12731                 if (read(0, &c, 1) != 1) {
12732                         status = 1;
12733                         break;
12734                 }
12735                 if (c == '\0')
12736                         continue;
12737                 if (backslash) {
12738                         backslash = 0;
12739                         if (c != '\n')
12740                                 goto put;
12741                         continue;
12742                 }
12743                 if (!rflag && c == '\\') {
12744                         backslash++;
12745                         continue;
12746                 }
12747                 if (c == '\n')
12748                         break;
12749                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12750                         continue;
12751                 }
12752                 startword = 0;
12753                 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12754                         STACKSTRNUL(p);
12755                         setvar(*ap, stackblock(), 0);
12756                         ap++;
12757                         startword = 1;
12758                         STARTSTACKSTR(p);
12759                 } else {
12760 put:
12761                         STPUTC(c, p);
12762                 }
12763         }
12764 #if defined(CONFIG_ASH_READ_NCHARS)
12765         if (nch_flag || silent)
12766                 tcsetattr(0, TCSANOW, &old_tty);
12767 #endif
12768
12769         STACKSTRNUL(p);
12770         /* Remove trailing blanks */
12771         while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12772                 *p = '\0';
12773         setvar(*ap, stackblock(), 0);
12774         while (*++ap != NULL)
12775                 setvar(*ap, nullstr, 0);
12776         return status;
12777 }
12778
12779
12780 static int umaskcmd(int argc, char **argv)
12781 {
12782         static const char permuser[3] = "ugo";
12783         static const char permmode[3] = "rwx";
12784         static const short int permmask[] = {
12785                 S_IRUSR, S_IWUSR, S_IXUSR,
12786                 S_IRGRP, S_IWGRP, S_IXGRP,
12787                 S_IROTH, S_IWOTH, S_IXOTH
12788         };
12789
12790         char *ap;
12791         mode_t mask;
12792         int i;
12793         int symbolic_mode = 0;
12794
12795         while (nextopt("S") != '\0') {
12796                 symbolic_mode = 1;
12797         }
12798
12799         INTOFF;
12800         mask = umask(0);
12801         umask(mask);
12802         INTON;
12803
12804         if ((ap = *argptr) == NULL) {
12805                 if (symbolic_mode) {
12806                         char buf[18];
12807                         char *p = buf;
12808
12809                         for (i = 0; i < 3; i++) {
12810                                 int j;
12811
12812                                 *p++ = permuser[i];
12813                                 *p++ = '=';
12814                                 for (j = 0; j < 3; j++) {
12815                                         if ((mask & permmask[3 * i + j]) == 0) {
12816                                                 *p++ = permmode[j];
12817                                         }
12818                                 }
12819                                 *p++ = ',';
12820                         }
12821                         *--p = 0;
12822                         puts(buf);
12823                 } else {
12824                         out1fmt("%.4o\n", mask);
12825                 }
12826         } else {
12827                 if (is_digit((unsigned char) *ap)) {
12828                         mask = 0;
12829                         do {
12830                                 if (*ap >= '8' || *ap < '0')
12831                                         error(illnum, argv[1]);
12832                                 mask = (mask << 3) + (*ap - '0');
12833                         } while (*++ap != '\0');
12834                         umask(mask);
12835                 } else {
12836                         mask = ~mask & 0777;
12837                         if (!bb_parse_mode(ap, &mask)) {
12838                                 error("Illegal mode: %s", ap);
12839                         }
12840                         umask(~mask & 0777);
12841                 }
12842         }
12843         return 0;
12844 }
12845
12846 /*
12847  * ulimit builtin
12848  *
12849  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12850  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12851  * ash by J.T. Conklin.
12852  *
12853  * Public domain.
12854  */
12855
12856 struct limits {
12857         const char *name;
12858         int     cmd;
12859         int     factor; /* multiply by to get rlim_{cur,max} values */
12860         char    option;
12861 };
12862
12863 static const struct limits limits[] = {
12864 #ifdef RLIMIT_CPU
12865         { "time(seconds)",              RLIMIT_CPU,        1, 't' },
12866 #endif
12867 #ifdef RLIMIT_FSIZE
12868         { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
12869 #endif
12870 #ifdef RLIMIT_DATA
12871         { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
12872 #endif
12873 #ifdef RLIMIT_STACK
12874         { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
12875 #endif
12876 #ifdef  RLIMIT_CORE
12877         { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
12878 #endif
12879 #ifdef RLIMIT_RSS
12880         { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
12881 #endif
12882 #ifdef RLIMIT_MEMLOCK
12883         { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
12884 #endif
12885 #ifdef RLIMIT_NPROC
12886         { "process",                    RLIMIT_NPROC,      1, 'p' },
12887 #endif
12888 #ifdef RLIMIT_NOFILE
12889         { "nofiles",                    RLIMIT_NOFILE,     1, 'n' },
12890 #endif
12891 #ifdef RLIMIT_AS
12892         { "vmemory(kbytes)",            RLIMIT_AS,      1024, 'v' },
12893 #endif
12894 #ifdef RLIMIT_LOCKS
12895         { "locks",                      RLIMIT_LOCKS,      1, 'w' },
12896 #endif
12897         { (char *) 0,                   0,                 0,  '\0' }
12898 };
12899
12900 enum limtype { SOFT = 0x1, HARD = 0x2 };
12901
12902 static void printlim(enum limtype how, const struct rlimit *limit,
12903                         const struct limits *l)
12904 {
12905         rlim_t val;
12906
12907         val = limit->rlim_max;
12908         if (how & SOFT)
12909                 val = limit->rlim_cur;
12910
12911         if (val == RLIM_INFINITY)
12912                 out1fmt("unlimited\n");
12913         else {
12914                 val /= l->factor;
12915                 out1fmt("%lld\n", (long long) val);
12916         }
12917 }
12918
12919 int
12920 ulimitcmd(int argc, char **argv)
12921 {
12922         int     c;
12923         rlim_t val = 0;
12924         enum limtype how = SOFT | HARD;
12925         const struct limits     *l;
12926         int             set, all = 0;
12927         int             optc, what;
12928         struct rlimit   limit;
12929
12930         what = 'f';
12931         while ((optc = nextopt("HSa"
12932 #ifdef RLIMIT_CPU
12933                                 "t"
12934 #endif
12935 #ifdef RLIMIT_FSIZE
12936                                 "f"
12937 #endif
12938 #ifdef RLIMIT_DATA
12939                                 "d"
12940 #endif
12941 #ifdef RLIMIT_STACK
12942                                 "s"
12943 #endif
12944 #ifdef RLIMIT_CORE
12945                                 "c"
12946 #endif
12947 #ifdef RLIMIT_RSS
12948                                 "m"
12949 #endif
12950 #ifdef RLIMIT_MEMLOCK
12951                                 "l"
12952 #endif
12953 #ifdef RLIMIT_NPROC
12954                                 "p"
12955 #endif
12956 #ifdef RLIMIT_NOFILE
12957                                 "n"
12958 #endif
12959 #ifdef RLIMIT_AS
12960                                 "v"
12961 #endif
12962 #ifdef RLIMIT_LOCKS
12963                                 "w"
12964 #endif
12965                                                 )) != '\0')
12966                 switch (optc) {
12967                 case 'H':
12968                         how = HARD;
12969                         break;
12970                 case 'S':
12971                         how = SOFT;
12972                         break;
12973                 case 'a':
12974                         all = 1;
12975                         break;
12976                 default:
12977                         what = optc;
12978                 }
12979
12980         for (l = limits; l->option != what; l++)
12981                 ;
12982
12983         set = *argptr ? 1 : 0;
12984         if (set) {
12985                 char *p = *argptr;
12986
12987                 if (all || argptr[1])
12988                         error("too many arguments");
12989                 if (strncmp(p, "unlimited\n", 9) == 0)
12990                         val = RLIM_INFINITY;
12991                 else {
12992                         val = (rlim_t) 0;
12993
12994                         while ((c = *p++) >= '0' && c <= '9')
12995                         {
12996                                 val = (val * 10) + (long)(c - '0');
12997                                 if (val < (rlim_t) 0)
12998                                         break;
12999                         }
13000                         if (c)
13001                                 error("bad number");
13002                         val *= l->factor;
13003                 }
13004         }
13005         if (all) {
13006                 for (l = limits; l->name; l++) {
13007                         getrlimit(l->cmd, &limit);
13008                         out1fmt("%-20s ", l->name);
13009                         printlim(how, &limit, l);
13010                 }
13011                 return 0;
13012         }
13013
13014         getrlimit(l->cmd, &limit);
13015         if (set) {
13016                 if (how & HARD)
13017                         limit.rlim_max = val;
13018                 if (how & SOFT)
13019                         limit.rlim_cur = val;
13020                 if (setrlimit(l->cmd, &limit) < 0)
13021                         error("error setting limit (%m)");
13022         } else {
13023                 printlim(how, &limit, l);
13024         }
13025         return 0;
13026 }
13027
13028
13029 #ifdef CONFIG_ASH_MATH_SUPPORT
13030
13031 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13032
13033    Permission is hereby granted, free of charge, to any person obtaining
13034    a copy of this software and associated documentation files (the
13035    "Software"), to deal in the Software without restriction, including
13036    without limitation the rights to use, copy, modify, merge, publish,
13037    distribute, sublicense, and/or sell copies of the Software, and to
13038    permit persons to whom the Software is furnished to do so, subject to
13039    the following conditions:
13040
13041    The above copyright notice and this permission notice shall be
13042    included in all copies or substantial portions of the Software.
13043
13044    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13045    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13046    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13047    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13048    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13049    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13050    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13051 */
13052
13053 /* This is my infix parser/evaluator. It is optimized for size, intended
13054  * as a replacement for yacc-based parsers. However, it may well be faster
13055  * than a comparable parser written in yacc. The supported operators are
13056  * listed in #defines below. Parens, order of operations, and error handling
13057  * are supported. This code is thread safe. The exact expression format should
13058  * be that which POSIX specifies for shells. */
13059
13060 /* The code uses a simple two-stack algorithm. See
13061  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
13062  * for a detailed explanation of the infix-to-postfix algorithm on which
13063  * this is based (this code differs in that it applies operators immediately
13064  * to the stack instead of adding them to a queue to end up with an
13065  * expression). */
13066
13067 /* To use the routine, call it with an expression string and error return
13068  * pointer */
13069
13070 /*
13071  * Aug 24, 2001              Manuel Novoa III
13072  *
13073  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13074  *
13075  * 1) In arith_apply():
13076  *    a) Cached values of *numptr and &(numptr[-1]).
13077  *    b) Removed redundant test for zero denominator.
13078  *
13079  * 2) In arith():
13080  *    a) Eliminated redundant code for processing operator tokens by moving
13081  *       to a table-based implementation.  Also folded handling of parens
13082  *       into the table.
13083  *    b) Combined all 3 loops which called arith_apply to reduce generated
13084  *       code size at the cost of speed.
13085  *
13086  * 3) The following expressions were treated as valid by the original code:
13087  *       1()  ,    0!  ,    1 ( *3 )   .
13088  *    These bugs have been fixed by internally enclosing the expression in
13089  *    parens and then checking that all binary ops and right parens are
13090  *    preceded by a valid expression (NUM_TOKEN).
13091  *
13092  * Note: It may be desirable to replace Aaron's test for whitespace with
13093  * ctype's isspace() if it is used by another busybox applet or if additional
13094  * whitespace chars should be considered.  Look below the "#include"s for a
13095  * precompiler test.
13096  */
13097
13098 /*
13099  * Aug 26, 2001              Manuel Novoa III
13100  *
13101  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
13102  *
13103  * Merge in Aaron's comments previously posted to the busybox list,
13104  * modified slightly to take account of my changes to the code.
13105  *
13106  */
13107
13108 /*
13109  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13110  *
13111  * - allow access to variable,
13112  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13113  * - realize assign syntax (VAR=expr, +=, *= etc)
13114  * - realize exponentiation (** operator)
13115  * - realize comma separated - expr, expr
13116  * - realise ++expr --expr expr++ expr--
13117  * - realise expr ? expr : expr (but, second expr calculate always)
13118  * - allow hexadecimal and octal numbers
13119  * - was restored loses XOR operator
13120  * - remove one goto label, added three ;-)
13121  * - protect $((num num)) as true zero expr (Manuel`s error)
13122  * - always use special isspace(), see comment from bash ;-)
13123  */
13124
13125
13126 #define arith_isspace(arithval) \
13127         (arithval == ' ' || arithval == '\n' || arithval == '\t')
13128
13129
13130 typedef unsigned char operator;
13131
13132 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13133  * precedence, and 3 high bits are an ID unique across operators of that
13134  * precedence. The ID portion is so that multiple operators can have the
13135  * same precedence, ensuring that the leftmost one is evaluated first.
13136  * Consider * and /. */
13137
13138 #define tok_decl(prec,id) (((id)<<5)|(prec))
13139 #define PREC(op) ((op) & 0x1F)
13140
13141 #define TOK_LPAREN tok_decl(0,0)
13142
13143 #define TOK_COMMA tok_decl(1,0)
13144
13145 #define TOK_ASSIGN tok_decl(2,0)
13146 #define TOK_AND_ASSIGN tok_decl(2,1)
13147 #define TOK_OR_ASSIGN tok_decl(2,2)
13148 #define TOK_XOR_ASSIGN tok_decl(2,3)
13149 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13150 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13151 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13152 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13153
13154 #define TOK_MUL_ASSIGN tok_decl(3,0)
13155 #define TOK_DIV_ASSIGN tok_decl(3,1)
13156 #define TOK_REM_ASSIGN tok_decl(3,2)
13157
13158 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13159 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13160
13161 /* conditional is right associativity too */
13162 #define TOK_CONDITIONAL tok_decl(4,0)
13163 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13164
13165 #define TOK_OR tok_decl(5,0)
13166
13167 #define TOK_AND tok_decl(6,0)
13168
13169 #define TOK_BOR tok_decl(7,0)
13170
13171 #define TOK_BXOR tok_decl(8,0)
13172
13173 #define TOK_BAND tok_decl(9,0)
13174
13175 #define TOK_EQ tok_decl(10,0)
13176 #define TOK_NE tok_decl(10,1)
13177
13178 #define TOK_LT tok_decl(11,0)
13179 #define TOK_GT tok_decl(11,1)
13180 #define TOK_GE tok_decl(11,2)
13181 #define TOK_LE tok_decl(11,3)
13182
13183 #define TOK_LSHIFT tok_decl(12,0)
13184 #define TOK_RSHIFT tok_decl(12,1)
13185
13186 #define TOK_ADD tok_decl(13,0)
13187 #define TOK_SUB tok_decl(13,1)
13188
13189 #define TOK_MUL tok_decl(14,0)
13190 #define TOK_DIV tok_decl(14,1)
13191 #define TOK_REM tok_decl(14,2)
13192
13193 /* exponent is right associativity */
13194 #define TOK_EXPONENT tok_decl(15,1)
13195
13196 /* For now unary operators. */
13197 #define UNARYPREC 16
13198 #define TOK_BNOT tok_decl(UNARYPREC,0)
13199 #define TOK_NOT tok_decl(UNARYPREC,1)
13200
13201 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13202 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13203
13204 #define PREC_PRE (UNARYPREC+2)
13205
13206 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13207 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13208
13209 #define PREC_POST (UNARYPREC+3)
13210
13211 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13212 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13213
13214 #define SPEC_PREC (UNARYPREC+4)
13215
13216 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13217 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13218
13219 #define NUMPTR (*numstackptr)
13220
13221 static inline int tok_have_assign(operator op)
13222 {
13223         operator prec = PREC(op);
13224
13225         convert_prec_is_assing(prec);
13226         return (prec == PREC(TOK_ASSIGN) ||
13227                         prec == PREC_PRE || prec == PREC_POST);
13228 }
13229
13230 static inline int is_right_associativity(operator prec)
13231 {
13232     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13233             prec == PREC(TOK_CONDITIONAL));
13234 }
13235
13236
13237 typedef struct ARITCH_VAR_NUM {
13238         arith_t val;
13239         arith_t contidional_second_val;
13240         char contidional_second_val_initialized;
13241         char *var;      /* if NULL then is regular number,
13242                            else is variable name */
13243 } v_n_t;
13244
13245
13246 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13247         const char *var;
13248         struct CHK_VAR_RECURSIVE_LOOPED *next;
13249 } chk_var_recursive_looped_t;
13250
13251 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13252
13253
13254 static int arith_lookup_val(v_n_t *t)
13255 {
13256     if(t->var) {
13257         const char * p = lookupvar(t->var);
13258
13259         if(p) {
13260             int errcode;
13261
13262             /* recursive try as expression */
13263             chk_var_recursive_looped_t *cur;
13264             chk_var_recursive_looped_t cur_save;
13265
13266             for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13267                 if(strcmp(cur->var, t->var) == 0) {
13268                     /* expression recursion loop detected */
13269                     return -5;
13270                 }
13271             }
13272             /* save current lookuped var name */
13273             cur = prev_chk_var_recursive;
13274             cur_save.var = t->var;
13275             cur_save.next = cur;
13276             prev_chk_var_recursive = &cur_save;
13277
13278             t->val = arith (p, &errcode);
13279             /* restore previous ptr after recursiving */
13280             prev_chk_var_recursive = cur;
13281             return errcode;
13282         } else {
13283             /* allow undefined var as 0 */
13284             t->val = 0;
13285         }
13286     }
13287     return 0;
13288 }
13289
13290 /* "applying" a token means performing it on the top elements on the integer
13291  * stack. For a unary operator it will only change the top element, but a
13292  * binary operator will pop two arguments and push a result */
13293 static inline int
13294 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13295 {
13296         v_n_t *numptr_m1;
13297         arith_t numptr_val, rez;
13298         int ret_arith_lookup_val;
13299
13300         if (NUMPTR == numstack) goto err; /* There is no operator that can work
13301                                                                                  without arguments */
13302         numptr_m1 = NUMPTR - 1;
13303
13304         /* check operand is var with noninteger value */
13305         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13306         if(ret_arith_lookup_val)
13307                 return ret_arith_lookup_val;
13308
13309         rez = numptr_m1->val;
13310         if (op == TOK_UMINUS)
13311                 rez *= -1;
13312         else if (op == TOK_NOT)
13313                 rez = !rez;
13314         else if (op == TOK_BNOT)
13315                 rez = ~rez;
13316         else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13317                 rez++;
13318         else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13319                 rez--;
13320         else if (op != TOK_UPLUS) {
13321                 /* Binary operators */
13322
13323             /* check and binary operators need two arguments */
13324             if (numptr_m1 == numstack) goto err;
13325
13326             /* ... and they pop one */
13327             --NUMPTR;
13328             numptr_val = rez;
13329             if (op == TOK_CONDITIONAL) {
13330                 if(! numptr_m1->contidional_second_val_initialized) {
13331                     /* protect $((expr1 ? expr2)) without ": expr" */
13332                     goto err;
13333                 }
13334                 rez = numptr_m1->contidional_second_val;
13335             } else if(numptr_m1->contidional_second_val_initialized) {
13336                     /* protect $((expr1 : expr2)) without "expr ? " */
13337                     goto err;
13338             }
13339             numptr_m1 = NUMPTR - 1;
13340             if(op != TOK_ASSIGN) {
13341                 /* check operand is var with noninteger value for not '=' */
13342                 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13343                 if(ret_arith_lookup_val)
13344                     return ret_arith_lookup_val;
13345             }
13346             if (op == TOK_CONDITIONAL) {
13347                     numptr_m1->contidional_second_val = rez;
13348             }
13349             rez = numptr_m1->val;
13350             if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13351                         rez |= numptr_val;
13352             else if (op == TOK_OR)
13353                         rez = numptr_val || rez;
13354             else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13355                         rez &= numptr_val;
13356             else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13357                         rez ^= numptr_val;
13358             else if (op == TOK_AND)
13359                         rez = rez && numptr_val;
13360             else if (op == TOK_EQ)
13361                         rez = (rez == numptr_val);
13362             else if (op == TOK_NE)
13363                         rez = (rez != numptr_val);
13364             else if (op == TOK_GE)
13365                         rez = (rez >= numptr_val);
13366             else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13367                         rez >>= numptr_val;
13368             else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13369                         rez <<= numptr_val;
13370             else if (op == TOK_GT)
13371                         rez = (rez > numptr_val);
13372             else if (op == TOK_LT)
13373                         rez = (rez < numptr_val);
13374             else if (op == TOK_LE)
13375                         rez = (rez <= numptr_val);
13376             else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13377                         rez *= numptr_val;
13378             else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13379                         rez += numptr_val;
13380             else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13381                         rez -= numptr_val;
13382             else if (op == TOK_ASSIGN || op == TOK_COMMA)
13383                         rez = numptr_val;
13384             else if (op == TOK_CONDITIONAL_SEP) {
13385                         if (numptr_m1 == numstack) {
13386                             /* protect $((expr : expr)) without "expr ? " */
13387                             goto err;
13388                         }
13389                         numptr_m1->contidional_second_val_initialized = op;
13390                         numptr_m1->contidional_second_val = numptr_val;
13391             }
13392             else if (op == TOK_CONDITIONAL) {
13393                         rez = rez ?
13394                               numptr_val : numptr_m1->contidional_second_val;
13395             }
13396             else if(op == TOK_EXPONENT) {
13397                         if(numptr_val < 0)
13398                                 return -3;      /* exponent less than 0 */
13399                         else {
13400                                 arith_t c = 1;
13401
13402                                 if(numptr_val)
13403                                         while(numptr_val--)
13404                                                 c *= rez;
13405                                 rez = c;
13406                         }
13407             }
13408             else if(numptr_val==0)          /* zero divisor check */
13409                         return -2;
13410             else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13411                         rez /= numptr_val;
13412             else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13413                         rez %= numptr_val;
13414         }
13415         if(tok_have_assign(op)) {
13416                 char buf[32];
13417
13418                 if(numptr_m1->var == NULL) {
13419                         /* Hmm, 1=2 ? */
13420                         goto err;
13421                 }
13422                 /* save to shell variable */
13423 #ifdef CONFIG_ASH_MATH_SUPPORT_64
13424                 snprintf(buf, sizeof(buf), "%lld", rez);
13425 #else
13426                 snprintf(buf, sizeof(buf), "%ld", rez);
13427 #endif
13428                 setvar(numptr_m1->var, buf, 0);
13429                 /* after saving, make previous value for v++ or v-- */
13430                 if(op == TOK_POST_INC)
13431                         rez--;
13432                 else if(op == TOK_POST_DEC)
13433                         rez++;
13434         }
13435         numptr_m1->val = rez;
13436         /* protect geting var value, is number now */
13437         numptr_m1->var = NULL;
13438         return 0;
13439 err: return(-1);
13440 }
13441
13442 /* longest must first */
13443 static const char op_tokens[] = {
13444         '<','<','=',0, TOK_LSHIFT_ASSIGN,
13445         '>','>','=',0, TOK_RSHIFT_ASSIGN,
13446         '<','<',    0, TOK_LSHIFT,
13447         '>','>',    0, TOK_RSHIFT,
13448         '|','|',    0, TOK_OR,
13449         '&','&',    0, TOK_AND,
13450         '!','=',    0, TOK_NE,
13451         '<','=',    0, TOK_LE,
13452         '>','=',    0, TOK_GE,
13453         '=','=',    0, TOK_EQ,
13454         '|','=',    0, TOK_OR_ASSIGN,
13455         '&','=',    0, TOK_AND_ASSIGN,
13456         '*','=',    0, TOK_MUL_ASSIGN,
13457         '/','=',    0, TOK_DIV_ASSIGN,
13458         '%','=',    0, TOK_REM_ASSIGN,
13459         '+','=',    0, TOK_PLUS_ASSIGN,
13460         '-','=',    0, TOK_MINUS_ASSIGN,
13461         '-','-',    0, TOK_POST_DEC,
13462         '^','=',    0, TOK_XOR_ASSIGN,
13463         '+','+',    0, TOK_POST_INC,
13464         '*','*',    0, TOK_EXPONENT,
13465         '!',        0, TOK_NOT,
13466         '<',        0, TOK_LT,
13467         '>',        0, TOK_GT,
13468         '=',        0, TOK_ASSIGN,
13469         '|',        0, TOK_BOR,
13470         '&',        0, TOK_BAND,
13471         '*',        0, TOK_MUL,
13472         '/',        0, TOK_DIV,
13473         '%',        0, TOK_REM,
13474         '+',        0, TOK_ADD,
13475         '-',        0, TOK_SUB,
13476         '^',        0, TOK_BXOR,
13477         /* uniq */
13478         '~',        0, TOK_BNOT,
13479         ',',        0, TOK_COMMA,
13480         '?',        0, TOK_CONDITIONAL,
13481         ':',        0, TOK_CONDITIONAL_SEP,
13482         ')',        0, TOK_RPAREN,
13483         '(',        0, TOK_LPAREN,
13484         0
13485 };
13486 /* ptr to ")" */
13487 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13488
13489
13490 static arith_t arith (const char *expr, int *perrcode)
13491 {
13492     register char arithval; /* Current character under analysis */
13493     operator lasttok, op;
13494     operator prec;
13495
13496     const char *p = endexpression;
13497     int errcode;
13498
13499     size_t datasizes = strlen(expr) + 2;
13500
13501     /* Stack of integers */
13502     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13503      * in any given correct or incorrect expression is left as an exercise to
13504      * the reader. */
13505     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13506             *numstackptr = numstack;
13507     /* Stack of operator tokens */
13508     operator *stack = alloca((datasizes) * sizeof(operator)),
13509             *stackptr = stack;
13510
13511     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
13512     *perrcode = errcode = 0;
13513
13514     while(1) {
13515         if ((arithval = *expr) == 0) {
13516                 if (p == endexpression) {
13517                         /* Null expression. */
13518                         return 0;
13519                 }
13520
13521                 /* This is only reached after all tokens have been extracted from the
13522                  * input stream. If there are still tokens on the operator stack, they
13523                  * are to be applied in order. At the end, there should be a final
13524                  * result on the integer stack */
13525
13526                 if (expr != endexpression + 1) {
13527                         /* If we haven't done so already, */
13528                         /* append a closing right paren */
13529                         expr = endexpression;
13530                         /* and let the loop process it. */
13531                         continue;
13532                 }
13533                 /* At this point, we're done with the expression. */
13534                 if (numstackptr != numstack+1) {
13535                         /* ... but if there isn't, it's bad */
13536                   err:
13537                         return (*perrcode = -1);
13538                 }
13539                 if(numstack->var) {
13540                     /* expression is $((var)) only, lookup now */
13541                     errcode = arith_lookup_val(numstack);
13542                 }
13543         ret:
13544                 *perrcode = errcode;
13545                 return numstack->val;
13546         } else {
13547                 /* Continue processing the expression. */
13548                 if (arith_isspace(arithval)) {
13549                         /* Skip whitespace */
13550                         goto prologue;
13551                 }
13552                 if((p = endofname(expr)) != expr) {
13553                         size_t var_name_size = (p-expr) + 1;  /* trailing zero */
13554
13555                         numstackptr->var = alloca(var_name_size);
13556                         safe_strncpy(numstackptr->var, expr, var_name_size);
13557                         expr = p;
13558                 num:
13559                         numstackptr->contidional_second_val_initialized = 0;
13560                         numstackptr++;
13561                         lasttok = TOK_NUM;
13562                         continue;
13563                 } else if (is_digit(arithval)) {
13564                         numstackptr->var = NULL;
13565 #ifdef CONFIG_ASH_MATH_SUPPORT_64
13566                         numstackptr->val = strtoll(expr, (char **) &expr, 0);
13567 #else
13568                         numstackptr->val = strtol(expr, (char **) &expr, 0);
13569 #endif
13570                         goto num;
13571                 }
13572                 for(p = op_tokens; ; p++) {
13573                         const char *o;
13574
13575                         if(*p == 0) {
13576                                 /* strange operator not found */
13577                                 goto err;
13578                         }
13579                         for(o = expr; *p && *o == *p; p++)
13580                                 o++;
13581                         if(! *p) {
13582                                 /* found */
13583                                 expr = o - 1;
13584                                 break;
13585                         }
13586                         /* skip tail uncompared token */
13587                         while(*p)
13588                                 p++;
13589                         /* skip zero delim */
13590                         p++;
13591                 }
13592                 op = p[1];
13593
13594                 /* post grammar: a++ reduce to num */
13595                 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13596                     lasttok = TOK_NUM;
13597
13598                 /* Plus and minus are binary (not unary) _only_ if the last
13599                  * token was as number, or a right paren (which pretends to be
13600                  * a number, since it evaluates to one). Think about it.
13601                  * It makes sense. */
13602                 if (lasttok != TOK_NUM) {
13603                         switch(op) {
13604                                 case TOK_ADD:
13605                                     op = TOK_UPLUS;
13606                                     break;
13607                                 case TOK_SUB:
13608                                     op = TOK_UMINUS;
13609                                     break;
13610                                 case TOK_POST_INC:
13611                                     op = TOK_PRE_INC;
13612                                     break;
13613                                 case TOK_POST_DEC:
13614                                     op = TOK_PRE_DEC;
13615                                     break;
13616                         }
13617                 }
13618                 /* We don't want a unary operator to cause recursive descent on the
13619                  * stack, because there can be many in a row and it could cause an
13620                  * operator to be evaluated before its argument is pushed onto the
13621                  * integer stack. */
13622                 /* But for binary operators, "apply" everything on the operator
13623                  * stack until we find an operator with a lesser priority than the
13624                  * one we have just extracted. */
13625                 /* Left paren is given the lowest priority so it will never be
13626                  * "applied" in this way.
13627                  * if associativity is right and priority eq, applied also skip
13628                  */
13629                 prec = PREC(op);
13630                 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13631                         /* not left paren or unary */
13632                         if (lasttok != TOK_NUM) {
13633                                 /* binary op must be preceded by a num */
13634                                 goto err;
13635                         }
13636                         while (stackptr != stack) {
13637                             if (op == TOK_RPAREN) {
13638                                 /* The algorithm employed here is simple: while we don't
13639                                  * hit an open paren nor the bottom of the stack, pop
13640                                  * tokens and apply them */
13641                                 if (stackptr[-1] == TOK_LPAREN) {
13642                                     --stackptr;
13643                                     /* Any operator directly after a */
13644                                     lasttok = TOK_NUM;
13645                                     /* close paren should consider itself binary */
13646                                     goto prologue;
13647                                 }
13648                             } else {
13649                                 operator prev_prec = PREC(stackptr[-1]);
13650
13651                                 convert_prec_is_assing(prec);
13652                                 convert_prec_is_assing(prev_prec);
13653                                 if (prev_prec < prec)
13654                                         break;
13655                                 /* check right assoc */
13656                                 if(prev_prec == prec && is_right_associativity(prec))
13657                                         break;
13658                             }
13659                             errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13660                             if(errcode) goto ret;
13661                         }
13662                         if (op == TOK_RPAREN) {
13663                                 goto err;
13664                         }
13665                 }
13666
13667                 /* Push this operator to the stack and remember it. */
13668                 *stackptr++ = lasttok = op;
13669
13670           prologue:
13671                 ++expr;
13672         }
13673     }
13674 }
13675 #endif /* CONFIG_ASH_MATH_SUPPORT */
13676
13677
13678 #ifdef DEBUG
13679 const char *bb_applet_name = "debug stuff usage";
13680 int main(int argc, char **argv)
13681 {
13682         return ash_main(argc, argv);
13683 }
13684 #endif
13685
13686 /*-
13687  * Copyright (c) 1989, 1991, 1993, 1994
13688  *      The Regents of the University of California.  All rights reserved.
13689  *
13690  * This code is derived from software contributed to Berkeley by
13691  * Kenneth Almquist.
13692  *
13693  * Redistribution and use in source and binary forms, with or without
13694  * modification, are permitted provided that the following conditions
13695  * are met:
13696  * 1. Redistributions of source code must retain the above copyright
13697  *    notice, this list of conditions and the following disclaimer.
13698  * 2. Redistributions in binary form must reproduce the above copyright
13699  *    notice, this list of conditions and the following disclaimer in the
13700  *    documentation and/or other materials provided with the distribution.
13701  *
13702  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13703  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13704  *
13705  * 4. Neither the name of the University nor the names of its contributors
13706  *    may be used to endorse or promote products derived from this software
13707  *    without specific prior written permission.
13708  *
13709  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13710  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13711  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13712  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13713  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13714  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13715  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13716  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13717  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13718  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13719  * SUCH DAMAGE.
13720  */