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