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