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