1fe1e8290c72fadd196e56312f69c6087f5dae98
[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 *);
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);
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)
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, 0);
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 static inline int
3480 goodname(const char *p)
3481 {
3482         return !*endofname(p);
3483 }
3484
3485 /*
3486  * Search for a command.  This is called before we fork so that the
3487  * location of the command will be available in the parent as well as
3488  * the child.  The check for "goodname" is an overly conservative
3489  * check that the name will not be subject to expansion.
3490  */
3491
3492 static void
3493 prehash(union node *n)
3494 {
3495         struct cmdentry entry;
3496
3497         if (n->type == NCMD && n->ncmd.args)
3498                 if (goodname(n->ncmd.args->narg.text))
3499                         find_command(n->ncmd.args->narg.text, &entry, 0,
3500                                      pathval());
3501 }
3502
3503
3504
3505 /*
3506  * Builtin commands.  Builtin commands whose functions are closely
3507  * tied to evaluation are implemented here.
3508  */
3509
3510 /*
3511  * No command given.
3512  */
3513
3514 static int
3515 bltincmd(int argc, char **argv)
3516 {
3517         /*
3518          * Preserve exitstatus of a previous possible redirection
3519          * as POSIX mandates
3520          */
3521         return back_exitstatus;
3522 }
3523
3524
3525 /*
3526  * Handle break and continue commands.  Break, continue, and return are
3527  * all handled by setting the evalskip flag.  The evaluation routines
3528  * above all check this flag, and if it is set they start skipping
3529  * commands rather than executing them.  The variable skipcount is
3530  * the number of loops to break/continue, or the number of function
3531  * levels to return.  (The latter is always 1.)  It should probably
3532  * be an error to break out of more loops than exist, but it isn't
3533  * in the standard shell so we don't make it one here.
3534  */
3535
3536 static int
3537 breakcmd(int argc, char **argv)
3538 {
3539         int n = argc > 1 ? number(argv[1]) : 1;
3540
3541         if (n <= 0)
3542                 error(illnum, argv[1]);
3543         if (n > loopnest)
3544                 n = loopnest;
3545         if (n > 0) {
3546                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3547                 skipcount = n;
3548         }
3549         return 0;
3550 }
3551
3552
3553 /*
3554  * The return command.
3555  */
3556
3557 static int
3558 returncmd(int argc, char **argv)
3559 {
3560         int ret = argc > 1 ? number(argv[1]) : exitstatus;
3561
3562         if (funcnest) {
3563                 evalskip = SKIPFUNC;
3564                 skipcount = 1;
3565                 return ret;
3566         }
3567         else {
3568                 /* Do what ksh does; skip the rest of the file */
3569                 evalskip = SKIPFILE;
3570                 skipcount = 1;
3571                 return ret;
3572         }
3573 }
3574
3575
3576 static int
3577 falsecmd(int argc, char **argv)
3578 {
3579         return 1;
3580 }
3581
3582
3583 static int
3584 truecmd(int argc, char **argv)
3585 {
3586         return 0;
3587 }
3588
3589
3590 static int
3591 execcmd(int argc, char **argv)
3592 {
3593         if (argc > 1) {
3594                 iflag = 0;              /* exit on error */
3595                 mflag = 0;
3596                 optschanged();
3597                 shellexec(argv + 1, pathval(), 0);
3598         }
3599         return 0;
3600 }
3601
3602
3603 /*      $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $    */
3604
3605 /*
3606  * When commands are first encountered, they are entered in a hash table.
3607  * This ensures that a full path search will not have to be done for them
3608  * on each invocation.
3609  *
3610  * We should investigate converting to a linear search, even though that
3611  * would make the command name "hash" a misnomer.
3612  */
3613
3614 #define CMDTABLESIZE 31         /* should be prime */
3615 #define ARB 1                   /* actual size determined at run time */
3616
3617
3618
3619 struct tblentry {
3620         struct tblentry *next;  /* next entry in hash chain */
3621         union param param;      /* definition of builtin function */
3622         short cmdtype;          /* index identifying command */
3623         char rehash;            /* if set, cd done since entry created */
3624         char cmdname[ARB];      /* name of command */
3625 };
3626
3627
3628 static struct tblentry *cmdtable[CMDTABLESIZE];
3629 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
3630
3631
3632 static void tryexec(char *, char **, char **);
3633 static void clearcmdentry(int);
3634 static struct tblentry *cmdlookup(const char *, int);
3635 static void delete_cmd_entry(void);
3636
3637
3638 /*
3639  * Exec a program.  Never returns.  If you change this routine, you may
3640  * have to change the find_command routine as well.
3641  */
3642
3643 static void
3644 shellexec(char **argv, const char *path, int idx)
3645 {
3646         char *cmdname;
3647         int e;
3648         char **envp;
3649
3650         clearredir(1);
3651         envp = environment();
3652         if (strchr(argv[0], '/') != NULL
3653 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3654                 || find_applet_by_name(argv[0])
3655 #endif
3656                                                 ) {
3657                 tryexec(argv[0], argv, envp);
3658                 e = errno;
3659         } else {
3660                 e = ENOENT;
3661                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3662                         if (--idx < 0 && pathopt == NULL) {
3663                                 tryexec(cmdname, argv, envp);
3664                                 if (errno != ENOENT && errno != ENOTDIR)
3665                                         e = errno;
3666                         }
3667                         stunalloc(cmdname);
3668                 }
3669         }
3670
3671         /* Map to POSIX errors */
3672         switch (e) {
3673         case EACCES:
3674                 exerrno = 126;
3675                 break;
3676         case ENOENT:
3677                 exerrno = 127;
3678                 break;
3679         default:
3680                 exerrno = 2;
3681                 break;
3682         }
3683         TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3684                 argv[0], e, suppressint ));
3685         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3686         /* NOTREACHED */
3687 }
3688
3689
3690 static void
3691 tryexec(char *cmd, char **argv, char **envp)
3692 {
3693         int repeated = 0;
3694 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3695         int flg_bb = 0;
3696         char *name = cmd;
3697
3698 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3699         name = bb_get_last_path_component(name);
3700         if(find_applet_by_name(name) != NULL)
3701                 flg_bb = 1;
3702 #else
3703         if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3704                 flg_bb = 1;
3705         }
3706 #endif
3707         if(flg_bb) {
3708                 char **ap;
3709                 char **new;
3710
3711                 *argv = name;
3712                 if(strcmp(name, "busybox")) {
3713                         for (ap = argv; *ap; ap++);
3714                         ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3715                         *ap++ = cmd = "/bin/busybox";
3716                         while ((*ap++ = *argv++));
3717                         argv = new;
3718                         repeated++;
3719                 } else {
3720                         cmd = "/bin/busybox";
3721                 }
3722         }
3723 #endif
3724
3725 repeat:
3726 #ifdef SYSV
3727         do {
3728                 execve(cmd, argv, envp);
3729         } while (errno == EINTR);
3730 #else
3731         execve(cmd, argv, envp);
3732 #endif
3733         if (repeated++) {
3734                 ckfree(argv);
3735         } else if (errno == ENOEXEC) {
3736                 char **ap;
3737                 char **new;
3738
3739                 for (ap = argv; *ap; ap++)
3740                         ;
3741                 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3742                 ap[1] = cmd;
3743                 *ap = cmd = (char *)DEFAULT_SHELL;
3744                 ap += 2;
3745                 argv++;
3746                 while ((*ap++ = *argv++))
3747                         ;
3748                 argv = new;
3749                 goto repeat;
3750         }
3751 }
3752
3753
3754
3755 /*
3756  * Do a path search.  The variable path (passed by reference) should be
3757  * set to the start of the path before the first call; padvance will update
3758  * this value as it proceeds.  Successive calls to padvance will return
3759  * the possible path expansions in sequence.  If an option (indicated by
3760  * a percent sign) appears in the path entry then the global variable
3761  * pathopt will be set to point to it; otherwise pathopt will be set to
3762  * NULL.
3763  */
3764
3765 static char *
3766 padvance(const char **path, const char *name)
3767 {
3768         const char *p;
3769         char *q;
3770         const char *start;
3771         size_t len;
3772
3773         if (*path == NULL)
3774                 return NULL;
3775         start = *path;
3776         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3777         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
3778         while (stackblocksize() < len)
3779                 growstackblock();
3780         q = stackblock();
3781         if (p != start) {
3782                 memcpy(q, start, p - start);
3783                 q += p - start;
3784                 *q++ = '/';
3785         }
3786         strcpy(q, name);
3787         pathopt = NULL;
3788         if (*p == '%') {
3789                 pathopt = ++p;
3790                 while (*p && *p != ':')  p++;
3791         }
3792         if (*p == ':')
3793                 *path = p + 1;
3794         else
3795                 *path = NULL;
3796         return stalloc(len);
3797 }
3798
3799
3800 /*** Command hashing code ***/
3801
3802 static void
3803 printentry(struct tblentry *cmdp)
3804 {
3805         int idx;
3806         const char *path;
3807         char *name;
3808
3809         idx = cmdp->param.index;
3810         path = pathval();
3811         do {
3812                 name = padvance(&path, cmdp->cmdname);
3813                 stunalloc(name);
3814         } while (--idx >= 0);
3815         out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3816 }
3817
3818
3819 static int
3820 hashcmd(int argc, char **argv)
3821 {
3822         struct tblentry **pp;
3823         struct tblentry *cmdp;
3824         int c;
3825         struct cmdentry entry;
3826         char *name;
3827
3828         while ((c = nextopt("r")) != '\0') {
3829                 clearcmdentry(0);
3830                 return 0;
3831         }
3832         if (*argptr == NULL) {
3833                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3834                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3835                                 if (cmdp->cmdtype == CMDNORMAL)
3836                                         printentry(cmdp);
3837                         }
3838                 }
3839                 return 0;
3840         }
3841         c = 0;
3842         while ((name = *argptr) != NULL) {
3843                 if ((cmdp = cmdlookup(name, 0)) != NULL
3844                  && (cmdp->cmdtype == CMDNORMAL
3845                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3846                         delete_cmd_entry();
3847                 find_command(name, &entry, DO_ERR, pathval());
3848                 if (entry.cmdtype == CMDUNKNOWN)
3849                         c = 1;
3850                 argptr++;
3851         }
3852         return c;
3853 }
3854
3855
3856 /*
3857  * Resolve a command name.  If you change this routine, you may have to
3858  * change the shellexec routine as well.
3859  */
3860
3861 static void
3862 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3863 {
3864         struct tblentry *cmdp;
3865         int idx;
3866         int prev;
3867         char *fullname;
3868         struct stat statb;
3869         int e;
3870         int updatetbl;
3871         struct builtincmd *bcmd;
3872
3873         /* If name contains a slash, don't use PATH or hash table */
3874         if (strchr(name, '/') != NULL) {
3875                 entry->u.index = -1;
3876                 if (act & DO_ABS) {
3877                         while (stat(name, &statb) < 0) {
3878 #ifdef SYSV
3879                                 if (errno == EINTR)
3880                                         continue;
3881 #endif
3882                                 entry->cmdtype = CMDUNKNOWN;
3883                                 return;
3884                         }
3885                 }
3886                 entry->cmdtype = CMDNORMAL;
3887                 return;
3888         }
3889
3890 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3891         if (find_applet_by_name(name)) {
3892                 entry->cmdtype = CMDNORMAL;
3893                 entry->u.index = -1;
3894                 return;
3895         }
3896 #endif
3897
3898         updatetbl = (path == pathval());
3899         if (!updatetbl) {
3900                 act |= DO_ALTPATH;
3901                 if (strstr(path, "%builtin") != NULL)
3902                         act |= DO_ALTBLTIN;
3903         }
3904
3905         /* If name is in the table, check answer will be ok */
3906         if ((cmdp = cmdlookup(name, 0)) != NULL) {
3907                 int bit;
3908
3909                 switch (cmdp->cmdtype) {
3910                 default:
3911 #if DEBUG
3912                         abort();
3913 #endif
3914                 case CMDNORMAL:
3915                         bit = DO_ALTPATH;
3916                         break;
3917                 case CMDFUNCTION:
3918                         bit = DO_NOFUNC;
3919                         break;
3920                 case CMDBUILTIN:
3921                         bit = DO_ALTBLTIN;
3922                         break;
3923                 }
3924                 if (act & bit) {
3925                         updatetbl = 0;
3926                         cmdp = NULL;
3927                 } else if (cmdp->rehash == 0)
3928                         /* if not invalidated by cd, we're done */
3929                         goto success;
3930         }
3931
3932         /* If %builtin not in path, check for builtin next */
3933         bcmd = find_builtin(name);
3934         if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3935                 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3936         )))
3937                 goto builtin_success;
3938
3939         /* We have to search path. */
3940         prev = -1;              /* where to start */
3941         if (cmdp && cmdp->rehash) {     /* doing a rehash */
3942                 if (cmdp->cmdtype == CMDBUILTIN)
3943                         prev = builtinloc;
3944                 else
3945                         prev = cmdp->param.index;
3946         }
3947
3948         e = ENOENT;
3949         idx = -1;
3950 loop:
3951         while ((fullname = padvance(&path, name)) != NULL) {
3952                 stunalloc(fullname);
3953                 idx++;
3954                 if (pathopt) {
3955                         if (prefix(pathopt, "builtin")) {
3956                                 if (bcmd)
3957                                         goto builtin_success;
3958                                 continue;
3959                         } else if (!(act & DO_NOFUNC) &&
3960                                    prefix(pathopt, "func")) {
3961                                 /* handled below */
3962                         } else {
3963                                 /* ignore unimplemented options */
3964                                 continue;
3965                         }
3966                 }
3967                 /* if rehash, don't redo absolute path names */
3968                 if (fullname[0] == '/' && idx <= prev) {
3969                         if (idx < prev)
3970                                 continue;
3971                         TRACE(("searchexec \"%s\": no change\n", name));
3972                         goto success;
3973                 }
3974                 while (stat(fullname, &statb) < 0) {
3975 #ifdef SYSV
3976                         if (errno == EINTR)
3977                                 continue;
3978 #endif
3979                         if (errno != ENOENT && errno != ENOTDIR)
3980                                 e = errno;
3981                         goto loop;
3982                 }
3983                 e = EACCES;     /* if we fail, this will be the error */
3984                 if (!S_ISREG(statb.st_mode))
3985                         continue;
3986                 if (pathopt) {          /* this is a %func directory */
3987                         stalloc(strlen(fullname) + 1);
3988                         readcmdfile(fullname);
3989                         if ((cmdp = cmdlookup(name, 0)) == NULL ||
3990                             cmdp->cmdtype != CMDFUNCTION)
3991                                 error("%s not defined in %s", name, fullname);
3992                         stunalloc(fullname);
3993                         goto success;
3994                 }
3995                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3996                 if (!updatetbl) {
3997                         entry->cmdtype = CMDNORMAL;
3998                         entry->u.index = idx;
3999                         return;
4000                 }
4001                 INTOFF;
4002                 cmdp = cmdlookup(name, 1);
4003                 cmdp->cmdtype = CMDNORMAL;
4004                 cmdp->param.index = idx;
4005                 INTON;
4006                 goto success;
4007         }
4008
4009         /* We failed.  If there was an entry for this command, delete it */
4010         if (cmdp && updatetbl)
4011                 delete_cmd_entry();
4012         if (act & DO_ERR)
4013                 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4014         entry->cmdtype = CMDUNKNOWN;
4015         return;
4016
4017 builtin_success:
4018         if (!updatetbl) {
4019                 entry->cmdtype = CMDBUILTIN;
4020                 entry->u.cmd = bcmd;
4021                 return;
4022         }
4023         INTOFF;
4024         cmdp = cmdlookup(name, 1);
4025         cmdp->cmdtype = CMDBUILTIN;
4026         cmdp->param.cmd = bcmd;
4027         INTON;
4028 success:
4029         cmdp->rehash = 0;
4030         entry->cmdtype = cmdp->cmdtype;
4031         entry->u = cmdp->param;
4032 }
4033
4034
4035 /*
4036  * Wrapper around strcmp for qsort/bsearch/...
4037  */
4038 static int pstrcmp(const void *a, const void *b)
4039 {
4040         return strcmp((const char *) a, (*(const char *const *) b) + 1);
4041 }
4042
4043 /*
4044  * Search the table of builtin commands.
4045  */
4046
4047 static struct builtincmd *
4048 find_builtin(const char *name)
4049 {
4050         struct builtincmd *bp;
4051
4052         bp = bsearch(
4053                 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4054                 pstrcmp
4055         );
4056         return bp;
4057 }
4058
4059
4060
4061 /*
4062  * Called when a cd is done.  Marks all commands so the next time they
4063  * are executed they will be rehashed.
4064  */
4065
4066 static void
4067 hashcd(void)
4068 {
4069         struct tblentry **pp;
4070         struct tblentry *cmdp;
4071
4072         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4073                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4074                         if (cmdp->cmdtype == CMDNORMAL || (
4075                                 cmdp->cmdtype == CMDBUILTIN &&
4076                                 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4077                                 builtinloc > 0
4078                         ))
4079                                 cmdp->rehash = 1;
4080                 }
4081         }
4082 }
4083
4084
4085
4086 /*
4087  * Fix command hash table when PATH changed.
4088  * Called before PATH is changed.  The argument is the new value of PATH;
4089  * pathval() still returns the old value at this point.
4090  * Called with interrupts off.
4091  */
4092
4093 static void
4094 changepath(const char *newval)
4095 {
4096         const char *old, *new;
4097         int idx;
4098         int firstchange;
4099         int idx_bltin;
4100
4101         old = pathval();
4102         new = newval;
4103         firstchange = 9999;     /* assume no change */
4104         idx = 0;
4105         idx_bltin = -1;
4106         for (;;) {
4107                 if (*old != *new) {
4108                         firstchange = idx;
4109                         if ((*old == '\0' && *new == ':')
4110                          || (*old == ':' && *new == '\0'))
4111                                 firstchange++;
4112                         old = new;      /* ignore subsequent differences */
4113                 }
4114                 if (*new == '\0')
4115                         break;
4116                 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4117                         idx_bltin = idx;
4118                 if (*new == ':') {
4119                         idx++;
4120                 }
4121                 new++, old++;
4122         }
4123         if (builtinloc < 0 && idx_bltin >= 0)
4124                 builtinloc = idx_bltin;             /* zap builtins */
4125         if (builtinloc >= 0 && idx_bltin < 0)
4126                 firstchange = 0;
4127         clearcmdentry(firstchange);
4128         builtinloc = idx_bltin;
4129 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
4130         cmdedit_path_lookup = newval;
4131 #endif
4132 }
4133
4134
4135 /*
4136  * Clear out command entries.  The argument specifies the first entry in
4137  * PATH which has changed.
4138  */
4139
4140 static void
4141 clearcmdentry(int firstchange)
4142 {
4143         struct tblentry **tblp;
4144         struct tblentry **pp;
4145         struct tblentry *cmdp;
4146
4147         INTOFF;
4148         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4149                 pp = tblp;
4150                 while ((cmdp = *pp) != NULL) {
4151                         if ((cmdp->cmdtype == CMDNORMAL &&
4152                              cmdp->param.index >= firstchange)
4153                          || (cmdp->cmdtype == CMDBUILTIN &&
4154                              builtinloc >= firstchange)) {
4155                                 *pp = cmdp->next;
4156                                 ckfree(cmdp);
4157                         } else {
4158                                 pp = &cmdp->next;
4159                         }
4160                 }
4161         }
4162         INTON;
4163 }
4164
4165
4166
4167 /*
4168  * Locate a command in the command hash table.  If "add" is nonzero,
4169  * add the command to the table if it is not already present.  The
4170  * variable "lastcmdentry" is set to point to the address of the link
4171  * pointing to the entry, so that delete_cmd_entry can delete the
4172  * entry.
4173  *
4174  * Interrupts must be off if called with add != 0.
4175  */
4176
4177 static struct tblentry **lastcmdentry;
4178
4179
4180 static struct tblentry *
4181 cmdlookup(const char *name, int add)
4182 {
4183         unsigned int hashval;
4184         const char *p;
4185         struct tblentry *cmdp;
4186         struct tblentry **pp;
4187
4188         p = name;
4189         hashval = (unsigned char)*p << 4;
4190         while (*p)
4191                 hashval += (unsigned char)*p++;
4192         hashval &= 0x7FFF;
4193         pp = &cmdtable[hashval % CMDTABLESIZE];
4194         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4195                 if (equal(cmdp->cmdname, name))
4196                         break;
4197                 pp = &cmdp->next;
4198         }
4199         if (add && cmdp == NULL) {
4200                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4201                                         + strlen(name) + 1);
4202                 cmdp->next = NULL;
4203                 cmdp->cmdtype = CMDUNKNOWN;
4204                 strcpy(cmdp->cmdname, name);
4205         }
4206         lastcmdentry = pp;
4207         return cmdp;
4208 }
4209
4210 /*
4211  * Delete the command entry returned on the last lookup.
4212  */
4213
4214 static void
4215 delete_cmd_entry(void)
4216 {
4217         struct tblentry *cmdp;
4218
4219         INTOFF;
4220         cmdp = *lastcmdentry;
4221         *lastcmdentry = cmdp->next;
4222         if (cmdp->cmdtype == CMDFUNCTION)
4223                 freefunc(cmdp->param.func);
4224         ckfree(cmdp);
4225         INTON;
4226 }
4227
4228
4229 /*
4230  * Add a new command entry, replacing any existing command entry for
4231  * the same name - except special builtins.
4232  */
4233
4234 static inline void
4235 addcmdentry(char *name, struct cmdentry *entry)
4236 {
4237         struct tblentry *cmdp;
4238
4239         cmdp = cmdlookup(name, 1);
4240         if (cmdp->cmdtype == CMDFUNCTION) {
4241                 freefunc(cmdp->param.func);
4242         }
4243         cmdp->cmdtype = entry->cmdtype;
4244         cmdp->param = entry->u;
4245         cmdp->rehash = 0;
4246 }
4247
4248 /*
4249  * Make a copy of a parse tree.
4250  */
4251
4252 static inline struct funcnode *
4253 copyfunc(union node *n)
4254 {
4255         struct funcnode *f;
4256         size_t blocksize;
4257
4258         funcblocksize = offsetof(struct funcnode, n);
4259         funcstringsize = 0;
4260         calcsize(n);
4261         blocksize = funcblocksize;
4262         f = ckmalloc(blocksize + funcstringsize);
4263         funcblock = (char *) f + offsetof(struct funcnode, n);
4264         funcstring = (char *) f + blocksize;
4265         copynode(n);
4266         f->count = 0;
4267         return f;
4268 }
4269
4270 /*
4271  * Define a shell function.
4272  */
4273
4274 static void
4275 defun(char *name, union node *func)
4276 {
4277         struct cmdentry entry;
4278
4279         INTOFF;
4280         entry.cmdtype = CMDFUNCTION;
4281         entry.u.func = copyfunc(func);
4282         addcmdentry(name, &entry);
4283         INTON;
4284 }
4285
4286
4287 /*
4288  * Delete a function if it exists.
4289  */
4290
4291 static void
4292 unsetfunc(const char *name)
4293 {
4294         struct tblentry *cmdp;
4295
4296         if ((cmdp = cmdlookup(name, 0)) != NULL &&
4297             cmdp->cmdtype == CMDFUNCTION)
4298                 delete_cmd_entry();
4299 }
4300
4301 /*
4302  * Locate and print what a word is...
4303  */
4304
4305
4306 #ifdef CONFIG_ASH_CMDCMD
4307 static int
4308 describe_command(char *command, int describe_command_verbose)
4309 #else
4310 #define describe_command_verbose 1
4311 static int
4312 describe_command(char *command)
4313 #endif
4314 {
4315         struct cmdentry entry;
4316         struct tblentry *cmdp;
4317 #ifdef CONFIG_ASH_ALIAS
4318         const struct alias *ap;
4319 #endif
4320         const char *path = pathval();
4321
4322         if (describe_command_verbose) {
4323                 out1str(command);
4324         }
4325
4326         /* First look at the keywords */
4327         if (findkwd(command)) {
4328                 out1str(describe_command_verbose ? " is a shell keyword" : command);
4329                 goto out;
4330         }
4331
4332 #ifdef CONFIG_ASH_ALIAS
4333         /* Then look at the aliases */
4334         if ((ap = lookupalias(command, 0)) != NULL) {
4335                 if (describe_command_verbose) {
4336                         out1fmt(" is an alias for %s", ap->val);
4337                 } else {
4338                         out1str("alias ");
4339                         printalias(ap);
4340                         return 0;
4341                 }
4342                 goto out;
4343         }
4344 #endif
4345         /* Then check if it is a tracked alias */
4346         if ((cmdp = cmdlookup(command, 0)) != NULL) {
4347                 entry.cmdtype = cmdp->cmdtype;
4348                 entry.u = cmdp->param;
4349         } else {
4350                 /* Finally use brute force */
4351                 find_command(command, &entry, DO_ABS, path);
4352         }
4353
4354         switch (entry.cmdtype) {
4355         case CMDNORMAL: {
4356                 int j = entry.u.index;
4357                 char *p;
4358                 if (j == -1) {
4359                         p = command;
4360                 } else {
4361                         do {
4362                                 p = padvance(&path, command);
4363                                 stunalloc(p);
4364                         } while (--j >= 0);
4365                 }
4366                 if (describe_command_verbose) {
4367                         out1fmt(" is%s %s",
4368                                 (cmdp ? " a tracked alias for" : nullstr), p
4369                         );
4370                 } else {
4371                         out1str(p);
4372                 }
4373                 break;
4374         }
4375
4376         case CMDFUNCTION:
4377                 if (describe_command_verbose) {
4378                         out1str(" is a shell function");
4379                 } else {
4380                         out1str(command);
4381                 }
4382                 break;
4383
4384         case CMDBUILTIN:
4385                 if (describe_command_verbose) {
4386                         out1fmt(" is a %sshell builtin",
4387                                 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4388                                         "special " : nullstr
4389                         );
4390                 } else {
4391                         out1str(command);
4392                 }
4393                 break;
4394
4395         default:
4396                 if (describe_command_verbose) {
4397                         out1str(": not found\n");
4398                 }
4399                 return 127;
4400         }
4401
4402 out:
4403         outstr("\n", stdout);
4404         return 0;
4405 }
4406
4407 static int
4408 typecmd(int argc, char **argv)
4409 {
4410         int i;
4411         int err = 0;
4412
4413         for (i = 1; i < argc; i++) {
4414 #ifdef CONFIG_ASH_CMDCMD
4415                 err |= describe_command(argv[i], 1);
4416 #else
4417                 err |= describe_command(argv[i]);
4418 #endif
4419         }
4420         return err;
4421 }
4422
4423 #ifdef CONFIG_ASH_CMDCMD
4424 static int
4425 commandcmd(int argc, char **argv)
4426 {
4427         int c;
4428         int default_path = 0;
4429         int verify_only = 0;
4430         int verbose_verify_only = 0;
4431
4432         while ((c = nextopt("pvV")) != '\0')
4433                 switch (c) {
4434                 default:
4435 #ifdef DEBUG
4436                         fprintf(stderr,
4437 "command: nextopt returned character code 0%o\n", c);
4438                         return EX_SOFTWARE;
4439 #endif
4440                 case 'p':
4441                         default_path = 1;
4442                         break;
4443                 case 'v':
4444                         verify_only = 1;
4445                         break;
4446                 case 'V':
4447                         verbose_verify_only = 1;
4448                         break;
4449                 }
4450
4451         if (default_path + verify_only + verbose_verify_only > 1 ||
4452             !*argptr) {
4453                         fprintf(stderr,
4454                                 "command [-p] command [arg ...]\n"
4455                                 "command {-v|-V} command\n");
4456                         return EX_USAGE;
4457         }
4458
4459         if (verify_only || verbose_verify_only) {
4460                 return describe_command(*argptr, verbose_verify_only);
4461         }
4462
4463         return 0;
4464 }
4465 #endif
4466
4467 /*      $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $     */
4468
4469 /*
4470  * Routines to expand arguments to commands.  We have to deal with
4471  * backquotes, shell variables, and file metacharacters.
4472  */
4473
4474 /*
4475  * _rmescape() flags
4476  */
4477 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
4478 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
4479 #define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
4480 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
4481 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
4482
4483 /*
4484  * Structure specifying which parts of the string should be searched
4485  * for IFS characters.
4486  */
4487
4488 struct ifsregion {
4489         struct ifsregion *next; /* next region in list */
4490         int begoff;             /* offset of start of region */
4491         int endoff;             /* offset of end of region */
4492         int nulonly;            /* search for nul bytes only */
4493 };
4494
4495 /* output of current string */
4496 static char *expdest;
4497 /* list of back quote expressions */
4498 static struct nodelist *argbackq;
4499 /* first struct in list of ifs regions */
4500 static struct ifsregion ifsfirst;
4501 /* last struct in list */
4502 static struct ifsregion *ifslastp;
4503 /* holds expanded arg list */
4504 static struct arglist exparg;
4505
4506 static void argstr(char *, int);
4507 static char *exptilde(char *, char *, int);
4508 static void expbackq(union node *, int, int);
4509 static const char *subevalvar(char *, char *, int, int, int, int, int);
4510 static char *evalvar(char *, int);
4511 static void strtodest(const char *, int, int);
4512 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4513 static ssize_t varvalue(char *, int, int);
4514 static void recordregion(int, int, int);
4515 static void removerecordregions(int);
4516 static void ifsbreakup(char *, struct arglist *);
4517 static void ifsfree(void);
4518 static void expandmeta(struct strlist *, int);
4519 static int patmatch(char *, const char *);
4520
4521 static int cvtnum(long);
4522 static size_t esclen(const char *, const char *);
4523 static char *scanleft(char *, char *, char *, char *, int, int);
4524 static char *scanright(char *, char *, char *, char *, int, int);
4525 static void varunset(const char *, const char *, const char *, int)
4526         __attribute__((__noreturn__));
4527
4528
4529 #define pmatch(a, b) !fnmatch((a), (b), 0)
4530 /*
4531  * Prepare a pattern for a expmeta (internal glob(3)) call.
4532  *
4533  * Returns an stalloced string.
4534  */
4535
4536 static inline char *
4537 preglob(const char *pattern, int quoted, int flag) {
4538         flag |= RMESCAPE_GLOB;
4539         if (quoted) {
4540                 flag |= RMESCAPE_QUOTED;
4541         }
4542         return _rmescapes((char *)pattern, flag);
4543 }
4544
4545
4546 static size_t
4547 esclen(const char *start, const char *p) {
4548         size_t esc = 0;
4549
4550         while (p > start && *--p == CTLESC) {
4551                 esc++;
4552         }
4553         return esc;
4554 }
4555
4556
4557 /*
4558  * Expand shell variables and backquotes inside a here document.
4559  */
4560
4561 static inline void
4562 expandhere(union node *arg, int fd)
4563 {
4564         herefd = fd;
4565         expandarg(arg, (struct arglist *)NULL, 0);
4566         xwrite(fd, stackblock(), expdest - (char *)stackblock());
4567 }
4568
4569
4570 /*
4571  * Perform variable substitution and command substitution on an argument,
4572  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
4573  * perform splitting and file name expansion.  When arglist is NULL, perform
4574  * here document expansion.
4575  */
4576
4577 void
4578 expandarg(union node *arg, struct arglist *arglist, int flag)
4579 {
4580         struct strlist *sp;
4581         char *p;
4582
4583         argbackq = arg->narg.backquote;
4584         STARTSTACKSTR(expdest);
4585         ifsfirst.next = NULL;
4586         ifslastp = NULL;
4587         argstr(arg->narg.text, flag);
4588         if (arglist == NULL) {
4589                 return;                 /* here document expanded */
4590         }
4591         STPUTC('\0', expdest);
4592         p = grabstackstr(expdest);
4593         exparg.lastp = &exparg.list;
4594         /*
4595          * TODO - EXP_REDIR
4596          */
4597         if (flag & EXP_FULL) {
4598                 ifsbreakup(p, &exparg);
4599                 *exparg.lastp = NULL;
4600                 exparg.lastp = &exparg.list;
4601                 expandmeta(exparg.list, flag);
4602         } else {
4603                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4604                         rmescapes(p);
4605                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4606                 sp->text = p;
4607                 *exparg.lastp = sp;
4608                 exparg.lastp = &sp->next;
4609         }
4610         if (ifsfirst.next)
4611                 ifsfree();
4612         *exparg.lastp = NULL;
4613         if (exparg.list) {
4614                 *arglist->lastp = exparg.list;
4615                 arglist->lastp = exparg.lastp;
4616         }
4617 }
4618
4619
4620 /*
4621  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
4622  * characters to allow for further processing.  Otherwise treat
4623  * $@ like $* since no splitting will be performed.
4624  */
4625
4626 static void
4627 argstr(char *p, int flag)
4628 {
4629         static const char spclchars[] = {
4630                 '=',
4631                 ':',
4632                 CTLQUOTEMARK,
4633                 CTLENDVAR,
4634                 CTLESC,
4635                 CTLVAR,
4636                 CTLBACKQ,
4637                 CTLBACKQ | CTLQUOTE,
4638 #ifdef CONFIG_ASH_MATH_SUPPORT
4639                 CTLENDARI,
4640 #endif
4641                 0
4642         };
4643         const char *reject = spclchars;
4644         int c;
4645         int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
4646         int breakall = flag & EXP_WORD;
4647         int inquotes;
4648         size_t length;
4649         int startloc;
4650
4651         if (!(flag & EXP_VARTILDE)) {
4652                 reject += 2;
4653         } else if (flag & EXP_VARTILDE2) {
4654                 reject++;
4655         }
4656         inquotes = 0;
4657         length = 0;
4658         if (flag & EXP_TILDE) {
4659                 char *q;
4660
4661                 flag &= ~EXP_TILDE;
4662 tilde:
4663                 q = p;
4664                 if (*q == CTLESC && (flag & EXP_QWORD))
4665                         q++;
4666                 if (*q == '~')
4667                         p = exptilde(p, q, flag);
4668         }
4669 start:
4670         startloc = expdest - (char *)stackblock();
4671         for (;;) {
4672                 length += strcspn(p + length, reject);
4673                 c = p[length];
4674                 if (c && (!(c & 0x80)
4675 #ifdef CONFIG_ASH_MATH_SUPPORT
4676                                         || c == CTLENDARI
4677 #endif
4678                    )) {
4679                         /* c == '=' || c == ':' || c == CTLENDARI */
4680                         length++;
4681                 }
4682                 if (length > 0) {
4683                         int newloc;
4684                         expdest = stnputs(p, length, expdest);
4685                         newloc = expdest - (char *)stackblock();
4686                         if (breakall && !inquotes && newloc > startloc) {
4687                                 recordregion(startloc, newloc, 0);
4688                         }
4689                         startloc = newloc;
4690                 }
4691                 p += length + 1;
4692                 length = 0;
4693
4694                 switch (c) {
4695                 case '\0':
4696                         goto breakloop;
4697                 case '=':
4698                         if (flag & EXP_VARTILDE2) {
4699                                 p--;
4700                                 continue;
4701                         }
4702                         flag |= EXP_VARTILDE2;
4703                         reject++;
4704                         /* fall through */
4705                 case ':':
4706                         /*
4707                          * sort of a hack - expand tildes in variable
4708                          * assignments (after the first '=' and after ':'s).
4709                          */
4710                         if (*--p == '~') {
4711                                 goto tilde;
4712                         }
4713                         continue;
4714                 }
4715
4716                 switch (c) {
4717                 case CTLENDVAR: /* ??? */
4718                         goto breakloop;
4719                 case CTLQUOTEMARK:
4720                         /* "$@" syntax adherence hack */
4721                         if (
4722                                 !inquotes &&
4723                                 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4724                                 (p[4] == CTLQUOTEMARK || (
4725                                         p[4] == CTLENDVAR &&
4726                                         p[5] == CTLQUOTEMARK
4727                                 ))
4728                         ) {
4729                                 p = evalvar(p + 1, flag) + 1;
4730                                 goto start;
4731                         }
4732                         inquotes = !inquotes;
4733 addquote:
4734                         if (quotes) {
4735                                 p--;
4736                                 length++;
4737                                 startloc++;
4738                         }
4739                         break;
4740                 case CTLESC:
4741                         startloc++;
4742                         length++;
4743                         goto addquote;
4744                 case CTLVAR:
4745                         p = evalvar(p, flag);
4746                         goto start;
4747                 case CTLBACKQ:
4748                         c = 0;
4749                 case CTLBACKQ|CTLQUOTE:
4750                         expbackq(argbackq->n, c, quotes);
4751                         argbackq = argbackq->next;
4752                         goto start;
4753 #ifdef CONFIG_ASH_MATH_SUPPORT
4754                 case CTLENDARI:
4755                         p--;
4756                         expari(quotes);
4757                         goto start;
4758 #endif
4759                 }
4760         }
4761 breakloop:
4762         ;
4763 }
4764
4765 static char *
4766 exptilde(char *startp, char *p, int flag)
4767 {
4768         char c;
4769         char *name;
4770         struct passwd *pw;
4771         const char *home;
4772         int quotes = flag & (EXP_FULL | EXP_CASE);
4773         int startloc;
4774
4775         name = p + 1;
4776
4777         while ((c = *++p) != '\0') {
4778                 switch(c) {
4779                 case CTLESC:
4780                         return (startp);
4781                 case CTLQUOTEMARK:
4782                         return (startp);
4783                 case ':':
4784                         if (flag & EXP_VARTILDE)
4785                                 goto done;
4786                         break;
4787                 case '/':
4788                 case CTLENDVAR:
4789                         goto done;
4790                 }
4791         }
4792 done:
4793         *p = '\0';
4794         if (*name == '\0') {
4795                 if ((home = lookupvar(homestr)) == NULL)
4796                         goto lose;
4797         } else {
4798                 if ((pw = getpwnam(name)) == NULL)
4799                         goto lose;
4800                 home = pw->pw_dir;
4801         }
4802         if (*home == '\0')
4803                 goto lose;
4804         *p = c;
4805         startloc = expdest - (char *)stackblock();
4806         strtodest(home, SQSYNTAX, quotes);
4807         recordregion(startloc, expdest - (char *)stackblock(), 0);
4808         return (p);
4809 lose:
4810         *p = c;
4811         return (startp);
4812 }
4813
4814
4815 static void
4816 removerecordregions(int endoff)
4817 {
4818         if (ifslastp == NULL)
4819                 return;
4820
4821         if (ifsfirst.endoff > endoff) {
4822                 while (ifsfirst.next != NULL) {
4823                         struct ifsregion *ifsp;
4824                         INTOFF;
4825                         ifsp = ifsfirst.next->next;
4826                         ckfree(ifsfirst.next);
4827                         ifsfirst.next = ifsp;
4828                         INTON;
4829                 }
4830                 if (ifsfirst.begoff > endoff)
4831                         ifslastp = NULL;
4832                 else {
4833                         ifslastp = &ifsfirst;
4834                         ifsfirst.endoff = endoff;
4835                 }
4836                 return;
4837         }
4838
4839         ifslastp = &ifsfirst;
4840         while (ifslastp->next && ifslastp->next->begoff < endoff)
4841                 ifslastp=ifslastp->next;
4842         while (ifslastp->next != NULL) {
4843                 struct ifsregion *ifsp;
4844                 INTOFF;
4845                 ifsp = ifslastp->next->next;
4846                 ckfree(ifslastp->next);
4847                 ifslastp->next = ifsp;
4848                 INTON;
4849         }
4850         if (ifslastp->endoff > endoff)
4851                 ifslastp->endoff = endoff;
4852 }
4853
4854
4855 #ifdef CONFIG_ASH_MATH_SUPPORT
4856 /*
4857  * Expand arithmetic expression.  Backup to start of expression,
4858  * evaluate, place result in (backed up) result, adjust string position.
4859  */
4860 void
4861 expari(int quotes)
4862 {
4863         char *p, *start;
4864         int begoff;
4865         int flag;
4866         int len;
4867
4868         /*      ifsfree(); */
4869
4870         /*
4871          * This routine is slightly over-complicated for
4872          * efficiency.  Next we scan backwards looking for the
4873          * start of arithmetic.
4874          */
4875         start = stackblock();
4876         p = expdest - 1;
4877         *p = '\0';
4878         p--;
4879         do {
4880                 int esc;
4881
4882                 while (*p != CTLARI) {
4883                         p--;
4884 #ifdef DEBUG
4885                         if (p < start) {
4886                                 error("missing CTLARI (shouldn't happen)");
4887                         }
4888 #endif
4889                 }
4890
4891                 esc = esclen(start, p);
4892                 if (!(esc % 2)) {
4893                         break;
4894                 }
4895
4896                 p -= esc + 1;
4897         } while (1);
4898
4899         begoff = p - start;
4900
4901         removerecordregions(begoff);
4902
4903         flag = p[1];
4904
4905         expdest = p;
4906
4907         if (quotes)
4908                 rmescapes(p + 2);
4909
4910         len = cvtnum(dash_arith(p + 2));
4911
4912         if (flag != '"')
4913                 recordregion(begoff, begoff + len, 0);
4914 }
4915 #endif
4916
4917 /*
4918  * Expand stuff in backwards quotes.
4919  */
4920
4921 static void
4922 expbackq(union node *cmd, int quoted, int quotes)
4923 {
4924         struct backcmd in;
4925         int i;
4926         char buf[128];
4927         char *p;
4928         char *dest;
4929         int startloc;
4930         int syntax = quoted? DQSYNTAX : BASESYNTAX;
4931         struct stackmark smark;
4932
4933         INTOFF;
4934         setstackmark(&smark);
4935         dest = expdest;
4936         startloc = dest - (char *)stackblock();
4937         grabstackstr(dest);
4938         evalbackcmd(cmd, (struct backcmd *) &in);
4939         popstackmark(&smark);
4940
4941         p = in.buf;
4942         i = in.nleft;
4943         if (i == 0)
4944                 goto read;
4945         for (;;) {
4946                 memtodest(p, i, syntax, quotes);
4947 read:
4948                 if (in.fd < 0)
4949                         break;
4950                 i = safe_read(in.fd, buf, sizeof buf);
4951                 TRACE(("expbackq: read returns %d\n", i));
4952                 if (i <= 0)
4953                         break;
4954                 p = buf;
4955         }
4956
4957         if (in.buf)
4958                 ckfree(in.buf);
4959         if (in.fd >= 0) {
4960                 close(in.fd);
4961                 back_exitstatus = waitforjob(in.jp);
4962         }
4963         INTON;
4964
4965         /* Eat all trailing newlines */
4966         dest = expdest;
4967         for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4968                 STUNPUTC(dest);
4969         expdest = dest;
4970
4971         if (quoted == 0)
4972                 recordregion(startloc, dest - (char *)stackblock(), 0);
4973         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4974                 (dest - (char *)stackblock()) - startloc,
4975                 (dest - (char *)stackblock()) - startloc,
4976                 stackblock() + startloc));
4977 }
4978
4979
4980 static char *
4981 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4982         int zero)
4983 {
4984         char *loc;
4985         char *loc2;
4986         char c;
4987
4988         loc = startp;
4989         loc2 = rmesc;
4990         do {
4991                 int match;
4992                 const char *s = loc2;
4993                 c = *loc2;
4994                 if (zero) {
4995                         *loc2 = '\0';
4996                         s = rmesc;
4997                 }
4998                 match = pmatch(str, s);
4999                 *loc2 = c;
5000                 if (match)
5001                         return loc;
5002                 if (quotes && *loc == CTLESC)
5003                         loc++;
5004                 loc++;
5005                 loc2++;
5006         } while (c);
5007         return 0;
5008 }
5009
5010
5011 static char *
5012 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5013         int zero)
5014 {
5015         int esc = 0;
5016         char *loc;
5017         char *loc2;
5018
5019         for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5020                 int match;
5021                 char c = *loc2;
5022                 const char *s = loc2;
5023                 if (zero) {
5024                         *loc2 = '\0';
5025                         s = rmesc;
5026                 }
5027                 match = pmatch(str, s);
5028                 *loc2 = c;
5029                 if (match)
5030                         return loc;
5031                 loc--;
5032                 if (quotes) {
5033                         if (--esc < 0) {
5034                                 esc = esclen(startp, loc);
5035                         }
5036                         if (esc % 2) {
5037                                 esc--;
5038                                 loc--;
5039                         }
5040                 }
5041         }
5042         return 0;
5043 }
5044
5045 static const char *
5046 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5047 {
5048         char *startp;
5049         char *loc;
5050         int saveherefd = herefd;
5051         struct nodelist *saveargbackq = argbackq;
5052         int amount;
5053         char *rmesc, *rmescend;
5054         int zero;
5055         char *(*scan)(char *, char *, char *, char *, int , int);
5056
5057         herefd = -1;
5058         argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5059         STPUTC('\0', expdest);
5060         herefd = saveherefd;
5061         argbackq = saveargbackq;
5062         startp = stackblock() + startloc;
5063
5064         switch (subtype) {
5065         case VSASSIGN:
5066                 setvar(str, startp, 0);
5067                 amount = startp - expdest;
5068                 STADJUST(amount, expdest);
5069                 return startp;
5070
5071         case VSQUESTION:
5072                 varunset(p, str, startp, varflags);
5073                 /* NOTREACHED */
5074         }
5075
5076         subtype -= VSTRIMRIGHT;
5077 #ifdef DEBUG
5078         if (subtype < 0 || subtype > 3)
5079                 abort();
5080 #endif
5081
5082         rmesc = startp;
5083         rmescend = stackblock() + strloc;
5084         if (quotes) {
5085                 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5086                 if (rmesc != startp) {
5087                         rmescend = expdest;
5088                         startp = stackblock() + startloc;
5089                 }
5090         }
5091         rmescend--;
5092         str = stackblock() + strloc;
5093         preglob(str, varflags & VSQUOTE, 0);
5094
5095         /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5096         zero = subtype >> 1;
5097         /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5098         scan = (subtype & 1) ^ zero ? scanleft : scanright;
5099
5100         loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5101         if (loc) {
5102                 if (zero) {
5103                         memmove(startp, loc, str - loc);
5104                         loc = startp + (str - loc) - 1;
5105                 }
5106                 *loc = '\0';
5107                 amount = loc - expdest;
5108                 STADJUST(amount, expdest);
5109         }
5110         return loc;
5111 }
5112
5113
5114 /*
5115  * Expand a variable, and return a pointer to the next character in the
5116  * input string.
5117  */
5118 static char *
5119 evalvar(char *p, int flag)
5120 {
5121         int subtype;
5122         int varflags;
5123         char *var;
5124         int patloc;
5125         int c;
5126         int startloc;
5127         ssize_t varlen;
5128         int easy;
5129         int quotes;
5130         int quoted;
5131
5132         quotes = flag & (EXP_FULL | EXP_CASE);
5133         varflags = *p++;
5134         subtype = varflags & VSTYPE;
5135         quoted = varflags & VSQUOTE;
5136         var = p;
5137         easy = (!quoted || (*var == '@' && shellparam.nparam));
5138         startloc = expdest - (char *)stackblock();
5139         p = strchr(p, '=') + 1;
5140
5141 again:
5142         varlen = varvalue(var, varflags, flag);
5143         if (varflags & VSNUL)
5144                 varlen--;
5145
5146         if (subtype == VSPLUS) {
5147                 varlen = -1 - varlen;
5148                 goto vsplus;
5149         }
5150
5151         if (subtype == VSMINUS) {
5152 vsplus:
5153                 if (varlen < 0) {
5154                         argstr(
5155                                 p, flag | EXP_TILDE |
5156                                         (quoted ?  EXP_QWORD : EXP_WORD)
5157                         );
5158                         goto end;
5159                 }
5160                 if (easy)
5161                         goto record;
5162                 goto end;
5163         }
5164
5165         if (subtype == VSASSIGN || subtype == VSQUESTION) {
5166                 if (varlen < 0) {
5167                         if (subevalvar(p, var, 0, subtype, startloc,
5168                                        varflags, 0)) {
5169                                 varflags &= ~VSNUL;
5170                                 /*
5171                                  * Remove any recorded regions beyond
5172                                  * start of variable
5173                                  */
5174                                 removerecordregions(startloc);
5175                                 goto again;
5176                         }
5177                         goto end;
5178                 }
5179                 if (easy)
5180                         goto record;
5181                 goto end;
5182         }
5183
5184         if (varlen < 0 && uflag)
5185                 varunset(p, var, 0, 0);
5186
5187         if (subtype == VSLENGTH) {
5188                 cvtnum(varlen > 0 ? varlen : 0);
5189                 goto record;
5190         }
5191
5192         if (subtype == VSNORMAL) {
5193                 if (!easy)
5194                         goto end;
5195 record:
5196                 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5197                 goto end;
5198         }
5199
5200 #ifdef DEBUG
5201         switch (subtype) {
5202         case VSTRIMLEFT:
5203         case VSTRIMLEFTMAX:
5204         case VSTRIMRIGHT:
5205         case VSTRIMRIGHTMAX:
5206                 break;
5207         default:
5208                 abort();
5209         }
5210 #endif
5211
5212         if (varlen >= 0) {
5213                 /*
5214                  * Terminate the string and start recording the pattern
5215                  * right after it
5216                  */
5217                 STPUTC('\0', expdest);
5218                 patloc = expdest - (char *)stackblock();
5219                 if (subevalvar(p, NULL, patloc, subtype,
5220                                startloc, varflags, quotes) == 0) {
5221                         int amount = expdest - (
5222                                 (char *)stackblock() + patloc - 1
5223                         );
5224                         STADJUST(-amount, expdest);
5225                 }
5226                 /* Remove any recorded regions beyond start of variable */
5227                 removerecordregions(startloc);
5228                 goto record;
5229         }
5230
5231 end:
5232         if (subtype != VSNORMAL) {      /* skip to end of alternative */
5233                 int nesting = 1;
5234                 for (;;) {
5235                         if ((c = *p++) == CTLESC)
5236                                 p++;
5237                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5238                                 if (varlen >= 0)
5239                                         argbackq = argbackq->next;
5240                         } else if (c == CTLVAR) {
5241                                 if ((*p++ & VSTYPE) != VSNORMAL)
5242                                         nesting++;
5243                         } else if (c == CTLENDVAR) {
5244                                 if (--nesting == 0)
5245                                         break;
5246                         }
5247                 }
5248         }
5249         return p;
5250 }
5251
5252
5253 /*
5254  * Put a string on the stack.
5255  */
5256
5257 static void
5258 memtodest(const char *p, size_t len, int syntax, int quotes) {
5259         char *q = expdest;
5260
5261         q = makestrspace(len * 2, q);
5262
5263         while (len--) {
5264                 int c = *p++;
5265                 if (!c)
5266                         continue;
5267                 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5268                         USTPUTC(CTLESC, q);
5269                 USTPUTC(c, q);
5270         }
5271
5272         expdest = q;
5273 }
5274
5275
5276 static void
5277 strtodest(const char *p, int syntax, int quotes)
5278 {
5279         memtodest(p, strlen(p), syntax, quotes);
5280 }
5281
5282
5283 /*
5284  * Add the value of a specialized variable to the stack string.
5285  */
5286
5287 static ssize_t
5288 varvalue(char *name, int varflags, int flags)
5289 {
5290         int num;
5291         char *p;
5292         int i;
5293         int sep = 0;
5294         int sepq = 0;
5295         ssize_t len = 0;
5296         char **ap;
5297         int syntax;
5298         int quoted = varflags & VSQUOTE;
5299         int subtype = varflags & VSTYPE;
5300         int quotes = flags & (EXP_FULL | EXP_CASE);
5301
5302         if (quoted && (flags & EXP_FULL))
5303                 sep = 1 << CHAR_BIT;
5304
5305         syntax = quoted ? DQSYNTAX : BASESYNTAX;
5306         switch (*name) {
5307         case '$':
5308                 num = rootpid;
5309                 goto numvar;
5310         case '?':
5311                 num = exitstatus;
5312                 goto numvar;
5313         case '#':
5314                 num = shellparam.nparam;
5315                 goto numvar;
5316         case '!':
5317                 num = backgndpid;
5318                 if (num == 0)
5319                         return -1;
5320 numvar:
5321                 len = cvtnum(num);
5322                 break;
5323         case '-':
5324                 p = makestrspace(NOPTS, expdest);
5325                 for (i = NOPTS - 1; i >= 0; i--) {
5326                         if (optlist[i]) {
5327                                 USTPUTC(optletters(i), p);
5328                                 len++;
5329                         }
5330                 }
5331                 expdest = p;
5332                 break;
5333         case '@':
5334                 if (sep)
5335                         goto param;
5336                 /* fall through */
5337         case '*':
5338                 sep = ifsset() ? ifsval()[0] : ' ';
5339                 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5340                         sepq = 1;
5341 param:
5342                 if (!(ap = shellparam.p))
5343                         return -1;
5344                 while ((p = *ap++)) {
5345                         size_t partlen;
5346
5347                         partlen = strlen(p);
5348
5349                         len += partlen;
5350                         if (len > partlen && sep) {
5351                                 char *q;
5352
5353                                 len++;
5354                                 if (subtype == VSPLUS || subtype == VSLENGTH) {
5355                                         continue;
5356                                 }
5357                                 q = expdest;
5358                                 if (sepq)
5359                                         STPUTC(CTLESC, q);
5360                                 STPUTC(sep, q);
5361                                 expdest = q;
5362                         }
5363
5364                         if (!(subtype == VSPLUS || subtype == VSLENGTH))
5365                                 memtodest(p, partlen, syntax, quotes);
5366                 }
5367                 return len;
5368         case '0':
5369         case '1':
5370         case '2':
5371         case '3':
5372         case '4':
5373         case '5':
5374         case '6':
5375         case '7':
5376         case '8':
5377         case '9':
5378                 num = atoi(name);
5379                 if (num < 0 || num > shellparam.nparam)
5380                         return -1;
5381                 p = num ? shellparam.p[num - 1] : arg0;
5382                 goto value;
5383         default:
5384                 p = lookupvar(name);
5385 value:
5386                 if (!p)
5387                         return -1;
5388
5389                 len = strlen(p);
5390                 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5391                         memtodest(p, len, syntax, quotes);
5392                 return len;
5393         }
5394
5395         if (subtype == VSPLUS || subtype == VSLENGTH)
5396                 STADJUST(-len, expdest);
5397         return len;
5398 }
5399
5400
5401 /*
5402  * Record the fact that we have to scan this region of the
5403  * string for IFS characters.
5404  */
5405
5406 static void
5407 recordregion(int start, int end, int nulonly)
5408 {
5409         struct ifsregion *ifsp;
5410
5411         if (ifslastp == NULL) {
5412                 ifsp = &ifsfirst;
5413         } else {
5414                 INTOFF;
5415                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5416                 ifsp->next = NULL;
5417                 ifslastp->next = ifsp;
5418                 INTON;
5419         }
5420         ifslastp = ifsp;
5421         ifslastp->begoff = start;
5422         ifslastp->endoff = end;
5423         ifslastp->nulonly = nulonly;
5424 }
5425
5426
5427 /*
5428  * Break the argument string into pieces based upon IFS and add the
5429  * strings to the argument list.  The regions of the string to be
5430  * searched for IFS characters have been stored by recordregion.
5431  */
5432 static void
5433 ifsbreakup(char *string, struct arglist *arglist)
5434 {
5435         struct ifsregion *ifsp;
5436         struct strlist *sp;
5437         char *start;
5438         char *p;
5439         char *q;
5440         const char *ifs, *realifs;
5441         int ifsspc;
5442         int nulonly;
5443
5444
5445         start = string;
5446         if (ifslastp != NULL) {
5447                 ifsspc = 0;
5448                 nulonly = 0;
5449                 realifs = ifsset() ? ifsval() : defifs;
5450                 ifsp = &ifsfirst;
5451                 do {
5452                         p = string + ifsp->begoff;
5453                         nulonly = ifsp->nulonly;
5454                         ifs = nulonly ? nullstr : realifs;
5455                         ifsspc = 0;
5456                         while (p < string + ifsp->endoff) {
5457                                 q = p;
5458                                 if (*p == CTLESC)
5459                                         p++;
5460                                 if (strchr(ifs, *p)) {
5461                                         if (!nulonly)
5462                                                 ifsspc = (strchr(defifs, *p) != NULL);
5463                                         /* Ignore IFS whitespace at start */
5464                                         if (q == start && ifsspc) {
5465                                                 p++;
5466                                                 start = p;
5467                                                 continue;
5468                                         }
5469                                         *q = '\0';
5470                                         sp = (struct strlist *)stalloc(sizeof *sp);
5471                                         sp->text = start;
5472                                         *arglist->lastp = sp;
5473                                         arglist->lastp = &sp->next;
5474                                         p++;
5475                                         if (!nulonly) {
5476                                                 for (;;) {
5477                                                         if (p >= string + ifsp->endoff) {
5478                                                                 break;
5479                                                         }
5480                                                         q = p;
5481                                                         if (*p == CTLESC)
5482                                                                 p++;
5483                                                         if (strchr(ifs, *p) == NULL ) {
5484                                                                 p = q;
5485                                                                 break;
5486                                                         } else if (strchr(defifs, *p) == NULL) {
5487                                                                 if (ifsspc) {
5488                                                                         p++;
5489                                                                         ifsspc = 0;
5490                                                                 } else {
5491                                                                         p = q;
5492                                                                         break;
5493                                                                 }
5494                                                         } else
5495                                                                 p++;
5496                                                 }
5497                                         }
5498                                         start = p;
5499                                 } else
5500                                         p++;
5501                         }
5502                 } while ((ifsp = ifsp->next) != NULL);
5503                 if (nulonly)
5504                         goto add;
5505         }
5506
5507         if (!*start)
5508                 return;
5509
5510 add:
5511         sp = (struct strlist *)stalloc(sizeof *sp);
5512         sp->text = start;
5513         *arglist->lastp = sp;
5514         arglist->lastp = &sp->next;
5515 }
5516
5517 static void
5518 ifsfree(void)
5519 {
5520         struct ifsregion *p;
5521
5522         INTOFF;
5523         p = ifsfirst.next;
5524         do {
5525                 struct ifsregion *ifsp;
5526                 ifsp = p->next;
5527                 ckfree(p);
5528                 p = ifsp;
5529         } while (p);
5530         ifslastp = NULL;
5531         ifsfirst.next = NULL;
5532         INTON;
5533 }
5534
5535 static void expmeta(char *, char *);
5536 static struct strlist *expsort(struct strlist *);
5537 static struct strlist *msort(struct strlist *, int);
5538
5539 static char *expdir;
5540
5541
5542 static void
5543 expandmeta(struct strlist *str, int flag)
5544 {
5545         static const char metachars[] = {
5546                 '*', '?', '[', 0
5547         };
5548         /* TODO - EXP_REDIR */
5549
5550         while (str) {
5551                 struct strlist **savelastp;
5552                 struct strlist *sp;
5553                 char *p;
5554
5555                 if (fflag)
5556                         goto nometa;
5557                 if (!strpbrk(str->text, metachars))
5558                         goto nometa;
5559                 savelastp = exparg.lastp;
5560
5561                 INTOFF;
5562                 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5563                 {
5564                         int i = strlen(str->text);
5565                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5566                 }
5567
5568                 expmeta(expdir, p);
5569                 ckfree(expdir);
5570                 if (p != str->text)
5571                         ckfree(p);
5572                 INTON;
5573                 if (exparg.lastp == savelastp) {
5574                         /*
5575                          * no matches
5576                          */
5577 nometa:
5578                         *exparg.lastp = str;
5579                         rmescapes(str->text);
5580                         exparg.lastp = &str->next;
5581                 } else {
5582                         *exparg.lastp = NULL;
5583                         *savelastp = sp = expsort(*savelastp);
5584                         while (sp->next != NULL)
5585                                 sp = sp->next;
5586                         exparg.lastp = &sp->next;
5587                 }
5588                 str = str->next;
5589         }
5590 }
5591
5592 /*
5593  * Add a file name to the list.
5594  */
5595
5596 static void
5597 addfname(const char *name)
5598 {
5599         struct strlist *sp;
5600
5601         sp = (struct strlist *)stalloc(sizeof *sp);
5602         sp->text = sstrdup(name);
5603         *exparg.lastp = sp;
5604         exparg.lastp = &sp->next;
5605 }
5606
5607
5608 /*
5609  * Do metacharacter (i.e. *, ?, [...]) expansion.
5610  */
5611
5612 static void
5613 expmeta(char *enddir, char *name)
5614 {
5615         char *p;
5616         const char *cp;
5617         char *start;
5618         char *endname;
5619         int metaflag;
5620         struct stat statb;
5621         DIR *dirp;
5622         struct dirent *dp;
5623         int atend;
5624         int matchdot;
5625
5626         metaflag = 0;
5627         start = name;
5628         for (p = name; *p; p++) {
5629                 if (*p == '*' || *p == '?')
5630                         metaflag = 1;
5631                 else if (*p == '[') {
5632                         char *q = p + 1;
5633                         if (*q == '!')
5634                                 q++;
5635                         for (;;) {
5636                                 if (*q == '\\')
5637                                         q++;
5638                                 if (*q == '/' || *q == '\0')
5639                                         break;
5640                                 if (*++q == ']') {
5641                                         metaflag = 1;
5642                                         break;
5643                                 }
5644                         }
5645                 } else if (*p == '\\')
5646                         p++;
5647                 else if (*p == '/') {
5648                         if (metaflag)
5649                                 goto out;
5650                         start = p + 1;
5651                 }
5652         }
5653 out:
5654         if (metaflag == 0) {    /* we've reached the end of the file name */
5655                 if (enddir != expdir)
5656                         metaflag++;
5657                 p = name;
5658                 do {
5659                         if (*p == '\\')
5660                                 p++;
5661                         *enddir++ = *p;
5662                 } while (*p++);
5663                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5664                         addfname(expdir);
5665                 return;
5666         }
5667         endname = p;
5668         if (name < start) {
5669                 p = name;
5670                 do {
5671                         if (*p == '\\')
5672                                 p++;
5673                         *enddir++ = *p++;
5674                 } while (p < start);
5675         }
5676         if (enddir == expdir) {
5677                 cp = ".";
5678         } else if (enddir == expdir + 1 && *expdir == '/') {
5679                 cp = "/";
5680         } else {
5681                 cp = expdir;
5682                 enddir[-1] = '\0';
5683         }
5684         if ((dirp = opendir(cp)) == NULL)
5685                 return;
5686         if (enddir != expdir)
5687                 enddir[-1] = '/';
5688         if (*endname == 0) {
5689                 atend = 1;
5690         } else {
5691                 atend = 0;
5692                 *endname++ = '\0';
5693         }
5694         matchdot = 0;
5695         p = start;
5696         if (*p == '\\')
5697                 p++;
5698         if (*p == '.')
5699                 matchdot++;
5700         while (! intpending && (dp = readdir(dirp)) != NULL) {
5701                 if (dp->d_name[0] == '.' && ! matchdot)
5702                         continue;
5703                 if (pmatch(start, dp->d_name)) {
5704                         if (atend) {
5705                                 scopy(dp->d_name, enddir);
5706                                 addfname(expdir);
5707                         } else {
5708                                 for (p = enddir, cp = dp->d_name;
5709                                      (*p++ = *cp++) != '\0';)
5710                                         continue;
5711                                 p[-1] = '/';
5712                                 expmeta(p, endname);
5713                         }
5714                 }
5715         }
5716         closedir(dirp);
5717         if (! atend)
5718                 endname[-1] = '/';
5719 }
5720
5721 /*
5722  * Sort the results of file name expansion.  It calculates the number of
5723  * strings to sort and then calls msort (short for merge sort) to do the
5724  * work.
5725  */
5726
5727 static struct strlist *
5728 expsort(struct strlist *str)
5729 {
5730         int len;
5731         struct strlist *sp;
5732
5733         len = 0;
5734         for (sp = str ; sp ; sp = sp->next)
5735                 len++;
5736         return msort(str, len);
5737 }
5738
5739
5740 static struct strlist *
5741 msort(struct strlist *list, int len)
5742 {
5743         struct strlist *p, *q = NULL;
5744         struct strlist **lpp;
5745         int half;
5746         int n;
5747
5748         if (len <= 1)
5749                 return list;
5750         half = len >> 1;
5751         p = list;
5752         for (n = half ; --n >= 0 ; ) {
5753                 q = p;
5754                 p = p->next;
5755         }
5756         q->next = NULL;                 /* terminate first half of list */
5757         q = msort(list, half);          /* sort first half of list */
5758         p = msort(p, len - half);               /* sort second half */
5759         lpp = &list;
5760         for (;;) {
5761 #ifdef CONFIG_LOCALE_SUPPORT
5762                 if (strcoll(p->text, q->text) < 0)
5763 #else
5764                 if (strcmp(p->text, q->text) < 0)
5765 #endif
5766                                                 {
5767                         *lpp = p;
5768                         lpp = &p->next;
5769                         if ((p = *lpp) == NULL) {
5770                                 *lpp = q;
5771                                 break;
5772                         }
5773                 } else {
5774                         *lpp = q;
5775                         lpp = &q->next;
5776                         if ((q = *lpp) == NULL) {
5777                                 *lpp = p;
5778                                 break;
5779                         }
5780                 }
5781         }
5782         return list;
5783 }
5784
5785
5786 /*
5787  * Returns true if the pattern matches the string.
5788  */
5789
5790 static inline int
5791 patmatch(char *pattern, const char *string)
5792 {
5793         return pmatch(preglob(pattern, 0, 0), string);
5794 }
5795
5796
5797 /*
5798  * Remove any CTLESC characters from a string.
5799  */
5800
5801 static char *
5802 _rmescapes(char *str, int flag)
5803 {
5804         char *p, *q, *r;
5805         static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5806         unsigned inquotes;
5807         int notescaped;
5808         int globbing;
5809
5810         p = strpbrk(str, qchars);
5811         if (!p) {
5812                 return str;
5813         }
5814         q = p;
5815         r = str;
5816         if (flag & RMESCAPE_ALLOC) {
5817                 size_t len = p - str;
5818                 size_t fulllen = len + strlen(p) + 1;
5819
5820                 if (flag & RMESCAPE_GROW) {
5821                         r = makestrspace(fulllen, expdest);
5822                 } else if (flag & RMESCAPE_HEAP) {
5823                         r = ckmalloc(fulllen);
5824                 } else {
5825                         r = stalloc(fulllen);
5826                 }
5827                 q = r;
5828                 if (len > 0) {
5829                         q = mempcpy(q, str, len);
5830                 }
5831         }
5832         inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5833         globbing = flag & RMESCAPE_GLOB;
5834         notescaped = globbing;
5835         while (*p) {
5836                 if (*p == CTLQUOTEMARK) {
5837                         inquotes = ~inquotes;
5838                         p++;
5839                         notescaped = globbing;
5840                         continue;
5841                 }
5842                 if (*p == '\\') {
5843                         /* naked back slash */
5844                         notescaped = 0;
5845                         goto copy;
5846                 }
5847                 if (*p == CTLESC) {
5848                         p++;
5849                         if (notescaped && inquotes && *p != '/') {
5850                                 *q++ = '\\';
5851                         }
5852                 }
5853                 notescaped = globbing;
5854 copy:
5855                 *q++ = *p++;
5856         }
5857         *q = '\0';
5858         if (flag & RMESCAPE_GROW) {
5859                 expdest = r;
5860                 STADJUST(q - r + 1, expdest);
5861         }
5862         return r;
5863 }
5864
5865
5866 /*
5867  * See if a pattern matches in a case statement.
5868  */
5869
5870 int
5871 casematch(union node *pattern, char *val)
5872 {
5873         struct stackmark smark;
5874         int result;
5875
5876         setstackmark(&smark);
5877         argbackq = pattern->narg.backquote;
5878         STARTSTACKSTR(expdest);
5879         ifslastp = NULL;
5880         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5881         STACKSTRNUL(expdest);
5882         result = patmatch(stackblock(), val);
5883         popstackmark(&smark);
5884         return result;
5885 }
5886
5887 /*
5888  * Our own itoa().
5889  */
5890
5891 static int
5892 cvtnum(long num)
5893 {
5894         int len;
5895
5896         expdest = makestrspace(32, expdest);
5897         len = fmtstr(expdest, 32, "%ld", num);
5898         STADJUST(len, expdest);
5899         return len;
5900 }
5901
5902 static void
5903 varunset(const char *end, const char *var, const char *umsg, int varflags)
5904 {
5905         const char *msg;
5906         const char *tail;
5907
5908         tail = nullstr;
5909         msg = "parameter not set";
5910         if (umsg) {
5911                 if (*end == CTLENDVAR) {
5912                         if (varflags & VSNUL)
5913                                 tail = " or null";
5914                 } else
5915                         msg = umsg;
5916         }
5917         error("%.*s: %s%s", end - var - 1, var, msg, tail);
5918 }
5919
5920
5921 /*      $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $      */
5922
5923 /*
5924  * This implements the input routines used by the parser.
5925  */
5926
5927 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
5928 #define IBUFSIZ (BUFSIZ + 1)
5929
5930 static void pushfile(void);
5931
5932 /*
5933  * Read a line from the script.
5934  */
5935
5936 static inline char *
5937 pfgets(char *line, int len)
5938 {
5939         char *p = line;
5940         int nleft = len;
5941         int c;
5942
5943         while (--nleft > 0) {
5944                 c = pgetc2();
5945                 if (c == PEOF) {
5946                         if (p == line)
5947                                 return NULL;
5948                         break;
5949                 }
5950                 *p++ = c;
5951                 if (c == '\n')
5952                         break;
5953         }
5954         *p = '\0';
5955         return line;
5956 }
5957
5958
5959 /*
5960  * Read a character from the script, returning PEOF on end of file.
5961  * Nul characters in the input are silently discarded.
5962  */
5963
5964 #define pgetc_as_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5965
5966 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5967 #define pgetc_macro() pgetc()
5968 static int
5969 pgetc(void)
5970 {
5971         return pgetc_as_macro();
5972 }
5973 #else
5974 #define pgetc_macro()   pgetc_as_macro()
5975 static int
5976 pgetc(void)
5977 {
5978         return pgetc_macro();
5979 }
5980 #endif
5981
5982
5983 /*
5984  * Same as pgetc(), but ignores PEOA.
5985  */
5986 #ifdef CONFIG_ASH_ALIAS
5987 static int pgetc2(void)
5988 {
5989         int c;
5990
5991         do {
5992                 c = pgetc_macro();
5993         } while (c == PEOA);
5994         return c;
5995 }
5996 #else
5997 static inline int pgetc2(void)
5998 {
5999         return pgetc_macro();
6000 }
6001 #endif
6002
6003
6004 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6005 static const char *cmdedit_prompt;
6006 static inline void putprompt(const char *s)
6007 {
6008         cmdedit_prompt = s;
6009 }
6010 #else
6011 static inline void putprompt(const char *s)
6012 {
6013         out2str(s);
6014 }
6015 #endif
6016
6017 static inline int
6018 preadfd(void)
6019 {
6020         int nr;
6021         char *buf =  parsefile->buf;
6022         parsenextc = buf;
6023
6024 retry:
6025 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6026         if (!iflag || parsefile->fd)
6027                 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6028         else {
6029                 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6030                 if(nr == 0) {
6031                         /* Ctrl+C presend */
6032                         if(trap[SIGINT]) {
6033                                 buf[0] = '\n';
6034                                 buf[1] = 0;
6035                                 raise(SIGINT);
6036                                 return 1;
6037                         }
6038                         goto retry;
6039                 }
6040                 if(nr < 0) {
6041                         /* Ctrl+D presend */
6042                         nr = 0;
6043                 }
6044         }
6045 #else
6046         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6047 #endif
6048
6049         if (nr < 0) {
6050                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6051                         int flags = fcntl(0, F_GETFL, 0);
6052                         if (flags >= 0 && flags & O_NONBLOCK) {
6053                                 flags &=~ O_NONBLOCK;
6054                                 if (fcntl(0, F_SETFL, flags) >= 0) {
6055                                         out2str("sh: turning off NDELAY mode\n");
6056                                         goto retry;
6057                                 }
6058                         }
6059                 }
6060         }
6061         return nr;
6062 }
6063
6064 /*
6065  * Refill the input buffer and return the next input character:
6066  *
6067  * 1) If a string was pushed back on the input, pop it;
6068  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6069  *    from a string so we can't refill the buffer, return EOF.
6070  * 3) If the is more stuff in this buffer, use it else call read to fill it.
6071  * 4) Process input up to the next newline, deleting nul characters.
6072  */
6073
6074 int
6075 preadbuffer(void)
6076 {
6077         char *p, *q;
6078         int more;
6079         char savec;
6080
6081         while (parsefile->strpush) {
6082 #ifdef CONFIG_ASH_ALIAS
6083                 if (parsenleft == -1 && parsefile->strpush->ap &&
6084                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6085                         return PEOA;
6086                 }
6087 #endif
6088                 popstring();
6089                 if (--parsenleft >= 0)
6090                         return (*parsenextc++);
6091         }
6092         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6093                 return PEOF;
6094         flushall();
6095
6096 again:
6097         if (parselleft <= 0) {
6098                 if ((parselleft = preadfd()) <= 0) {
6099                         parselleft = parsenleft = EOF_NLEFT;
6100                         return PEOF;
6101                 }
6102         }
6103
6104         q = p = parsenextc;
6105
6106         /* delete nul characters */
6107         for (more = 1; more;) {
6108                 switch (*p) {
6109                 case '\0':
6110                         p++;    /* Skip nul */
6111                         goto check;
6112
6113                 case '\n':
6114                         parsenleft = q - parsenextc;
6115                         more = 0; /* Stop processing here */
6116                         break;
6117
6118                 }
6119
6120                 *q++ = *p++;
6121 check:
6122                 if (--parselleft <= 0 && more) {
6123                         parsenleft = q - parsenextc - 1;
6124                         if (parsenleft < 0)
6125                                 goto again;
6126                         more = 0;
6127                 }
6128         }
6129
6130         savec = *q;
6131         *q = '\0';
6132
6133         if (vflag) {
6134                 out2str(parsenextc);
6135         }
6136
6137         *q = savec;
6138
6139         return *parsenextc++;
6140 }
6141
6142 /*
6143  * Undo the last call to pgetc.  Only one character may be pushed back.
6144  * PEOF may be pushed back.
6145  */
6146
6147 void
6148 pungetc(void)
6149 {
6150         parsenleft++;
6151         parsenextc--;
6152 }
6153
6154 /*
6155  * Push a string back onto the input at this current parsefile level.
6156  * We handle aliases this way.
6157  */
6158 void
6159 pushstring(char *s, void *ap)
6160 {
6161         struct strpush *sp;
6162         size_t len;
6163
6164         len = strlen(s);
6165         INTOFF;
6166 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6167         if (parsefile->strpush) {
6168                 sp = ckmalloc(sizeof (struct strpush));
6169                 sp->prev = parsefile->strpush;
6170                 parsefile->strpush = sp;
6171         } else
6172                 sp = parsefile->strpush = &(parsefile->basestrpush);
6173         sp->prevstring = parsenextc;
6174         sp->prevnleft = parsenleft;
6175 #ifdef CONFIG_ASH_ALIAS
6176         sp->ap = (struct alias *)ap;
6177         if (ap) {
6178                 ((struct alias *)ap)->flag |= ALIASINUSE;
6179                 sp->string = s;
6180         }
6181 #endif
6182         parsenextc = s;
6183         parsenleft = len;
6184         INTON;
6185 }
6186
6187 void
6188 popstring(void)
6189 {
6190         struct strpush *sp = parsefile->strpush;
6191
6192         INTOFF;
6193 #ifdef CONFIG_ASH_ALIAS
6194         if (sp->ap) {
6195                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6196                         checkkwd |= CHKALIAS;
6197                 }
6198                 if (sp->string != sp->ap->val) {
6199                         ckfree(sp->string);
6200                 }
6201                 sp->ap->flag &= ~ALIASINUSE;
6202                 if (sp->ap->flag & ALIASDEAD) {
6203                         unalias(sp->ap->name);
6204                 }
6205         }
6206 #endif
6207         parsenextc = sp->prevstring;
6208         parsenleft = sp->prevnleft;
6209 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6210         parsefile->strpush = sp->prev;
6211         if (sp != &(parsefile->basestrpush))
6212                 ckfree(sp);
6213         INTON;
6214 }
6215
6216 /*
6217  * Set the input to take input from a file.  If push is set, push the
6218  * old input onto the stack first.
6219  */
6220
6221 void
6222 setinputfile(const char *fname, int push)
6223 {
6224         int fd;
6225         int fd2;
6226
6227         INTOFF;
6228         if ((fd = open(fname, O_RDONLY)) < 0)
6229                 error("Can't open %s", fname);
6230         if (fd < 10) {
6231                 fd2 = copyfd(fd, 10);
6232                 close(fd);
6233                 if (fd2 < 0)
6234                         error("Out of file descriptors");
6235                 fd = fd2;
6236         }
6237         setinputfd(fd, push);
6238         INTON;
6239 }
6240
6241
6242 /*
6243  * Like setinputfile, but takes an open file descriptor.  Call this with
6244  * interrupts off.
6245  */
6246
6247 static void
6248 setinputfd(int fd, int push)
6249 {
6250         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6251         if (push) {
6252                 pushfile();
6253                 parsefile->buf = 0;
6254         }
6255         parsefile->fd = fd;
6256         if (parsefile->buf == NULL)
6257                 parsefile->buf = ckmalloc(IBUFSIZ);
6258         parselleft = parsenleft = 0;
6259         plinno = 1;
6260 }
6261
6262
6263 /*
6264  * Like setinputfile, but takes input from a string.
6265  */
6266
6267 static void
6268 setinputstring(char *string)
6269 {
6270         INTOFF;
6271         pushfile();
6272         parsenextc = string;
6273         parsenleft = strlen(string);
6274         parsefile->buf = NULL;
6275         plinno = 1;
6276         INTON;
6277 }
6278
6279
6280 /*
6281  * To handle the "." command, a stack of input files is used.  Pushfile
6282  * adds a new entry to the stack and popfile restores the previous level.
6283  */
6284
6285 static void
6286 pushfile(void)
6287 {
6288         struct parsefile *pf;
6289
6290         parsefile->nleft = parsenleft;
6291         parsefile->lleft = parselleft;
6292         parsefile->nextc = parsenextc;
6293         parsefile->linno = plinno;
6294         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6295         pf->prev = parsefile;
6296         pf->fd = -1;
6297         pf->strpush = NULL;
6298         pf->basestrpush.prev = NULL;
6299         parsefile = pf;
6300 }
6301
6302
6303 static void
6304 popfile(void)
6305 {
6306         struct parsefile *pf = parsefile;
6307
6308         INTOFF;
6309         if (pf->fd >= 0)
6310                 close(pf->fd);
6311         if (pf->buf)
6312                 ckfree(pf->buf);
6313         while (pf->strpush)
6314                 popstring();
6315         parsefile = pf->prev;
6316         ckfree(pf);
6317         parsenleft = parsefile->nleft;
6318         parselleft = parsefile->lleft;
6319         parsenextc = parsefile->nextc;
6320         plinno = parsefile->linno;
6321         INTON;
6322 }
6323
6324
6325 /*
6326  * Return to top level.
6327  */
6328
6329 static void
6330 popallfiles(void)
6331 {
6332         while (parsefile != &basepf)
6333                 popfile();
6334 }
6335
6336
6337 /*
6338  * Close the file(s) that the shell is reading commands from.  Called
6339  * after a fork is done.
6340  */
6341
6342 static void
6343 closescript(void)
6344 {
6345         popallfiles();
6346         if (parsefile->fd > 0) {
6347                 close(parsefile->fd);
6348                 parsefile->fd = 0;
6349         }
6350 }
6351
6352 /*      $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $    */
6353
6354 /* mode flags for set_curjob */
6355 #define CUR_DELETE 2
6356 #define CUR_RUNNING 1
6357 #define CUR_STOPPED 0
6358
6359 /* mode flags for dowait */
6360 #define DOWAIT_NORMAL 0
6361 #define DOWAIT_BLOCK 1
6362
6363 /* array of jobs */
6364 static struct job *jobtab;
6365 /* size of array */
6366 static unsigned njobs;
6367 #if JOBS
6368 /* pgrp of shell on invocation */
6369 static int initialpgrp;
6370 static int ttyfd = -1;
6371 #endif
6372 /* current job */
6373 static struct job *curjob;
6374 /* number of presumed living untracked jobs */
6375 static int jobless;
6376
6377 static void set_curjob(struct job *, unsigned);
6378 #if JOBS
6379 static int restartjob(struct job *, int);
6380 static void xtcsetpgrp(int, pid_t);
6381 static char *commandtext(union node *);
6382 static void cmdlist(union node *, int);
6383 static void cmdtxt(union node *);
6384 static void cmdputs(const char *);
6385 static void showpipe(struct job *, FILE *);
6386 #endif
6387 static int sprint_status(char *, int, int);
6388 static void freejob(struct job *);
6389 static struct job *getjob(const char *, int);
6390 static struct job *growjobtab(void);
6391 static void forkchild(struct job *, union node *, int);
6392 static void forkparent(struct job *, union node *, int, pid_t);
6393 static int dowait(int, struct job *);
6394 static int getstatus(struct job *);
6395
6396 static void
6397 set_curjob(struct job *jp, unsigned mode)
6398 {
6399         struct job *jp1;
6400         struct job **jpp, **curp;
6401
6402         /* first remove from list */
6403         jpp = curp = &curjob;
6404         do {
6405                 jp1 = *jpp;
6406                 if (jp1 == jp)
6407                         break;
6408                 jpp = &jp1->prev_job;
6409         } while (1);
6410         *jpp = jp1->prev_job;
6411
6412         /* Then re-insert in correct position */
6413         jpp = curp;
6414         switch (mode) {
6415         default:
6416 #ifdef DEBUG
6417                 abort();
6418 #endif
6419         case CUR_DELETE:
6420                 /* job being deleted */
6421                 break;
6422         case CUR_RUNNING:
6423                 /* newly created job or backgrounded job,
6424                    put after all stopped jobs. */
6425                 do {
6426                         jp1 = *jpp;
6427 #ifdef JOBS
6428                         if (!jp1 || jp1->state != JOBSTOPPED)
6429 #endif
6430                                 break;
6431                         jpp = &jp1->prev_job;
6432                 } while (1);
6433                 /* FALLTHROUGH */
6434 #ifdef JOBS
6435         case CUR_STOPPED:
6436 #endif
6437                 /* newly stopped job - becomes curjob */
6438                 jp->prev_job = *jpp;
6439                 *jpp = jp;
6440                 break;
6441         }
6442 }
6443
6444 #if JOBS
6445 /*
6446  * Turn job control on and off.
6447  *
6448  * Note:  This code assumes that the third arg to ioctl is a character
6449  * pointer, which is true on Berkeley systems but not System V.  Since
6450  * System V doesn't have job control yet, this isn't a problem now.
6451  *
6452  * Called with interrupts off.
6453  */
6454
6455 void
6456 setjobctl(int on)
6457 {
6458         int fd;
6459         int pgrp;
6460
6461         if (on == jobctl || rootshell == 0)
6462                 return;
6463         if (on) {
6464                 int ofd;
6465                 ofd = fd = open(_PATH_TTY, O_RDWR);
6466                 if (fd < 0) {
6467                         fd += 3;
6468                         while (!isatty(fd) && --fd >= 0)
6469                                 ;
6470                 }
6471                 fd = fcntl(fd, F_DUPFD, 10);
6472                 close(ofd);
6473                 if (fd < 0)
6474                         goto out;
6475                 fcntl(fd, F_SETFD, FD_CLOEXEC);
6476                 do { /* while we are in the background */
6477                         if ((pgrp = tcgetpgrp(fd)) < 0) {
6478 out:
6479                                 sh_warnx("can't access tty; job control turned off");
6480                                 mflag = on = 0;
6481                                 goto close;
6482                         }
6483                         if (pgrp == getpgrp())
6484                                 break;
6485                         killpg(0, SIGTTIN);
6486                 } while (1);
6487                 initialpgrp = pgrp;
6488
6489                 setsignal(SIGTSTP);
6490                 setsignal(SIGTTOU);
6491                 setsignal(SIGTTIN);
6492                 pgrp = rootpid;
6493                 setpgid(0, pgrp);
6494                 xtcsetpgrp(fd, pgrp);
6495         } else {
6496                 /* turning job control off */
6497                 fd = ttyfd;
6498                 pgrp = initialpgrp;
6499                 xtcsetpgrp(fd, pgrp);
6500                 setpgid(0, pgrp);
6501                 setsignal(SIGTSTP);
6502                 setsignal(SIGTTOU);
6503                 setsignal(SIGTTIN);
6504 close:
6505                 close(fd);
6506                 fd = -1;
6507         }
6508         ttyfd = fd;
6509         jobctl = on;
6510 }
6511
6512 static int
6513 killcmd(int argc, char **argv)
6514 {
6515         int signo = -1;
6516         int list = 0;
6517         int i;
6518         pid_t pid;
6519         struct job *jp;
6520
6521         if (argc <= 1) {
6522 usage:
6523                 error(
6524 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6525 "kill -l [exitstatus]"
6526                 );
6527         }
6528
6529         if (**++argv == '-') {
6530                 signo = decode_signal(*argv + 1, 1);
6531                 if (signo < 0) {
6532                         int c;
6533
6534                         while ((c = nextopt("ls:")) != '\0')
6535                                 switch (c) {
6536                                 default:
6537 #ifdef DEBUG
6538                                         abort();
6539 #endif
6540                                 case 'l':
6541                                         list = 1;
6542                                         break;
6543                                 case 's':
6544                                         signo = decode_signal(optionarg, 1);
6545                                         if (signo < 0) {
6546                                                 error(
6547                                                         "invalid signal number or name: %s",
6548                                                         optionarg
6549                                                 );
6550                                         }
6551                                         break;
6552                                 }
6553                         argv = argptr;
6554                 } else
6555                         argv++;
6556         }
6557
6558         if (!list && signo < 0)
6559                 signo = SIGTERM;
6560
6561         if ((signo < 0 || !*argv) ^ list) {
6562                 goto usage;
6563         }
6564
6565         if (list) {
6566                 const char *name;
6567
6568                 if (!*argv) {
6569                         for (i = 1; i < NSIG; i++) {
6570                                 name = u_signal_names(0, &i, 1);
6571                                 if (name)
6572                                         out1fmt(snlfmt, name);
6573                         }
6574                         return 0;
6575                 }
6576                 name = u_signal_names(*argptr, &signo, -1);
6577                 if (name)
6578                         out1fmt(snlfmt, name);
6579                 else
6580                         error("invalid signal number or exit status: %s", *argptr);
6581                 return 0;
6582         }
6583
6584         i = 0;
6585         do {
6586                 if (**argv == '%') {
6587                         jp = getjob(*argv, 0);
6588                         pid = -jp->ps[0].pid;
6589                 } else
6590                         pid = number(*argv);
6591                 if (kill(pid, signo) != 0) {
6592                         sh_warnx("%m\n");
6593                         i = 1;
6594                 }
6595         } while (*++argv);
6596
6597         return i;
6598 }
6599 #endif /* JOBS */
6600
6601 #if defined(JOBS) || defined(DEBUG)
6602 static int
6603 jobno(const struct job *jp)
6604 {
6605         return jp - jobtab + 1;
6606 }
6607 #endif
6608
6609 #ifdef JOBS
6610 static int
6611 fgcmd(int argc, char **argv)
6612 {
6613         struct job *jp;
6614         FILE *out;
6615         int mode;
6616         int retval;
6617
6618         mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6619         nextopt(nullstr);
6620         argv = argptr;
6621         out = stdout;
6622         do {
6623                 jp = getjob(*argv, 1);
6624                 if (mode == FORK_BG) {
6625                         set_curjob(jp, CUR_RUNNING);
6626                         fprintf(out, "[%d] ", jobno(jp));
6627                 }
6628                 outstr(jp->ps->cmd, out);
6629                 showpipe(jp, out);
6630                 retval = restartjob(jp, mode);
6631         } while (*argv && *++argv);
6632         return retval;
6633 }
6634
6635 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6636
6637
6638 static int
6639 restartjob(struct job *jp, int mode)
6640 {
6641         struct procstat *ps;
6642         int i;
6643         int status;
6644         pid_t pgid;
6645
6646         INTOFF;
6647         if (jp->state == JOBDONE)
6648                 goto out;
6649         jp->state = JOBRUNNING;
6650         pgid = jp->ps->pid;
6651         if (mode == FORK_FG)
6652                 xtcsetpgrp(ttyfd, pgid);
6653         killpg(pgid, SIGCONT);
6654         ps = jp->ps;
6655         i = jp->nprocs;
6656         do {
6657                 if (WIFSTOPPED(ps->status)) {
6658                         ps->status = -1;
6659                 }
6660         } while (ps++, --i);
6661 out:
6662         status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6663         INTON;
6664         return status;
6665 }
6666 #endif
6667
6668 static int
6669 sprint_status(char *s, int status, int sigonly)
6670 {
6671         int col;
6672         int st;
6673
6674         col = 0;
6675         if (!WIFEXITED(status)) {
6676 #if JOBS
6677                 if (WIFSTOPPED(status))
6678                         st = WSTOPSIG(status);
6679                 else
6680 #endif
6681                         st = WTERMSIG(status);
6682                 if (sigonly) {
6683                         if (st == SIGINT || st == SIGPIPE)
6684                                 goto out;
6685 #if JOBS
6686                         if (WIFSTOPPED(status))
6687                                 goto out;
6688 #endif
6689                 }
6690                 st &= 0x7f;
6691                 col = fmtstr(s, 32, strsignal(st));
6692                 if (WCOREDUMP(status)) {
6693                         col += fmtstr(s + col, 16, " (core dumped)");
6694                 }
6695         } else if (!sigonly) {
6696                 st = WEXITSTATUS(status);
6697                 if (st)
6698                         col = fmtstr(s, 16, "Done(%d)", st);
6699                 else
6700                         col = fmtstr(s, 16, "Done");
6701         }
6702
6703 out:
6704         return col;
6705 }
6706
6707 #if JOBS
6708 static void
6709 showjob(FILE *out, struct job *jp, int mode)
6710 {
6711         struct procstat *ps;
6712         struct procstat *psend;
6713         int col;
6714         int indent;
6715         char s[80];
6716
6717         ps = jp->ps;
6718
6719         if (mode & SHOW_PGID) {
6720                 /* just output process (group) id of pipeline */
6721                 fprintf(out, "%d\n", ps->pid);
6722                 return;
6723         }
6724
6725         col = fmtstr(s, 16, "[%d]   ", jobno(jp));
6726         indent = col;
6727
6728         if (jp == curjob)
6729                 s[col - 2] = '+';
6730         else if (curjob && jp == curjob->prev_job)
6731                 s[col - 2] = '-';
6732
6733         if (mode & SHOW_PID)
6734                 col += fmtstr(s + col, 16, "%d ", ps->pid);
6735
6736         psend = ps + jp->nprocs;
6737
6738         if (jp->state == JOBRUNNING) {
6739                 scopy("Running", s + col);
6740                 col += strlen("Running");
6741         } else {
6742                 int status = psend[-1].status;
6743 #if JOBS
6744                 if (jp->state == JOBSTOPPED)
6745                         status = jp->stopstatus;
6746 #endif
6747                 col += sprint_status(s + col, status, 0);
6748         }
6749
6750         goto start;
6751
6752         do {
6753                 /* for each process */
6754                 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6755
6756 start:
6757                 fprintf(out, "%s%*c%s",
6758                         s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6759                 );
6760                 if (!(mode & SHOW_PID)) {
6761                         showpipe(jp, out);
6762                         break;
6763                 }
6764                 if (++ps == psend) {
6765                         outcslow('\n', out);
6766                         break;
6767                 }
6768         } while (1);
6769
6770         jp->changed = 0;
6771
6772         if (jp->state == JOBDONE) {
6773                 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6774                 freejob(jp);
6775         }
6776 }
6777
6778
6779 static int
6780 jobscmd(int argc, char **argv)
6781 {
6782         int mode, m;
6783         FILE *out;
6784
6785         mode = 0;
6786         while ((m = nextopt("lp")))
6787                 if (m == 'l')
6788                         mode = SHOW_PID;
6789                 else
6790                         mode = SHOW_PGID;
6791
6792         out = stdout;
6793         argv = argptr;
6794         if (*argv)
6795                 do
6796                         showjob(out, getjob(*argv,0), mode);
6797                 while (*++argv);
6798         else
6799                 showjobs(out, mode);
6800
6801         return 0;
6802 }
6803
6804
6805 /*
6806  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
6807  * statuses have changed since the last call to showjobs.
6808  */
6809
6810 static void
6811 showjobs(FILE *out, int mode)
6812 {
6813         struct job *jp;
6814
6815         TRACE(("showjobs(%x) called\n", mode));
6816
6817         /* If not even one one job changed, there is nothing to do */
6818         while (dowait(DOWAIT_NORMAL, NULL) > 0)
6819                 continue;
6820
6821         for (jp = curjob; jp; jp = jp->prev_job) {
6822                 if (!(mode & SHOW_CHANGED) || jp->changed)
6823                         showjob(out, jp, mode);
6824         }
6825 }
6826 #endif /* JOBS */
6827
6828 /*
6829  * Mark a job structure as unused.
6830  */
6831
6832 static void
6833 freejob(struct job *jp)
6834 {
6835         struct procstat *ps;
6836         int i;
6837
6838         INTOFF;
6839         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6840                 if (ps->cmd != nullstr)
6841                         ckfree(ps->cmd);
6842         }
6843         if (jp->ps != &jp->ps0)
6844                 ckfree(jp->ps);
6845         jp->used = 0;
6846         set_curjob(jp, CUR_DELETE);
6847         INTON;
6848 }
6849
6850
6851 static int
6852 waitcmd(int argc, char **argv)
6853 {
6854         struct job *job;
6855         int retval;
6856         struct job *jp;
6857
6858         EXSIGON();
6859
6860         nextopt(nullstr);
6861         retval = 0;
6862
6863         argv = argptr;
6864         if (!*argv) {
6865                 /* wait for all jobs */
6866                 for (;;) {
6867                         jp = curjob;
6868                         while (1) {
6869                                 if (!jp) {
6870                                         /* no running procs */
6871                                         goto out;
6872                                 }
6873                                 if (jp->state == JOBRUNNING)
6874                                         break;
6875                                 jp->waited = 1;
6876                                 jp = jp->prev_job;
6877                         }
6878                         dowait(DOWAIT_BLOCK, 0);
6879                 }
6880         }
6881
6882         retval = 127;
6883         do {
6884                 if (**argv != '%') {
6885                         pid_t pid = number(*argv);
6886                         job = curjob;
6887                         goto start;
6888                         do {
6889                                 if (job->ps[job->nprocs - 1].pid == pid)
6890                                         break;
6891                                 job = job->prev_job;
6892 start:
6893                                 if (!job)
6894                                         goto repeat;
6895                         } while (1);
6896                 } else
6897                         job = getjob(*argv, 0);
6898                 /* loop until process terminated or stopped */
6899                 while (job->state == JOBRUNNING)
6900                         dowait(DOWAIT_BLOCK, 0);
6901                 job->waited = 1;
6902                 retval = getstatus(job);
6903 repeat:
6904                 ;
6905         } while (*++argv);
6906
6907 out:
6908         return retval;
6909 }
6910
6911
6912 /*
6913  * Convert a job name to a job structure.
6914  */
6915
6916 static struct job *
6917 getjob(const char *name, int getctl)
6918 {
6919         struct job *jp;
6920         struct job *found;
6921         const char *err_msg = "No such job: %s";
6922         unsigned num;
6923         int c;
6924         const char *p;
6925         char *(*match)(const char *, const char *);
6926
6927         jp = curjob;
6928         p = name;
6929         if (!p)
6930                 goto currentjob;
6931
6932         if (*p != '%')
6933                 goto err;
6934
6935         c = *++p;
6936         if (!c)
6937                 goto currentjob;
6938
6939         if (!p[1]) {
6940                 if (c == '+' || c == '%') {
6941 currentjob:
6942                         err_msg = "No current job";
6943                         goto check;
6944                 } else if (c == '-') {
6945                         if (jp)
6946                                 jp = jp->prev_job;
6947                         err_msg = "No previous job";
6948 check:
6949                         if (!jp)
6950                                 goto err;
6951                         goto gotit;
6952                 }
6953         }
6954
6955         if (is_number(p)) {
6956                 num = atoi(p);
6957                 if (num < njobs) {
6958                         jp = jobtab + num - 1;
6959                         if (jp->used)
6960                                 goto gotit;
6961                         goto err;
6962                 }
6963         }
6964
6965         match = prefix;
6966         if (*p == '?') {
6967                 match = strstr;
6968                 p++;
6969         }
6970
6971         found = 0;
6972         while (1) {
6973                 if (!jp)
6974                         goto err;
6975                 if (match(jp->ps[0].cmd, p)) {
6976                         if (found)
6977                                 goto err;
6978                         found = jp;
6979                         err_msg = "%s: ambiguous";
6980                 }
6981                 jp = jp->prev_job;
6982         }
6983
6984 gotit:
6985 #if JOBS
6986         err_msg = "job %s not created under job control";
6987         if (getctl && jp->jobctl == 0)
6988                 goto err;
6989 #endif
6990         return jp;
6991 err:
6992         error(err_msg, name);
6993 }
6994
6995
6996 /*
6997  * Return a new job structure.
6998  * Called with interrupts off.
6999  */
7000
7001 static struct job *
7002 makejob(union node *node, int nprocs)
7003 {
7004         int i;
7005         struct job *jp;
7006
7007         for (i = njobs, jp = jobtab ; ; jp++) {
7008                 if (--i < 0) {
7009                         jp = growjobtab();
7010                         break;
7011                 }
7012                 if (jp->used == 0)
7013                         break;
7014                 if (jp->state != JOBDONE || !jp->waited)
7015                         continue;
7016 #if JOBS
7017                 if (jobctl)
7018                         continue;
7019 #endif
7020                 freejob(jp);
7021                 break;
7022         }
7023         memset(jp, 0, sizeof(*jp));
7024 #if JOBS
7025         if (jobctl)
7026                 jp->jobctl = 1;
7027 #endif
7028         jp->prev_job = curjob;
7029         curjob = jp;
7030         jp->used = 1;
7031         jp->ps = &jp->ps0;
7032         if (nprocs > 1) {
7033                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7034         }
7035         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7036             jobno(jp)));
7037         return jp;
7038 }
7039
7040 static struct job *
7041 growjobtab(void)
7042 {
7043         size_t len;
7044         ptrdiff_t offset;
7045         struct job *jp, *jq;
7046
7047         len = njobs * sizeof(*jp);
7048         jq = jobtab;
7049         jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7050
7051         offset = (char *)jp - (char *)jq;
7052         if (offset) {
7053                 /* Relocate pointers */
7054                 size_t l = len;
7055
7056                 jq = (struct job *)((char *)jq + l);
7057                 while (l) {
7058                         l -= sizeof(*jp);
7059                         jq--;
7060 #define joff(p) ((struct job *)((char *)(p) + l))
7061 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7062                         if (likely(joff(jp)->ps == &jq->ps0))
7063                                 jmove(joff(jp)->ps);
7064                         if (joff(jp)->prev_job)
7065                                 jmove(joff(jp)->prev_job);
7066                 }
7067                 if (curjob)
7068                         jmove(curjob);
7069 #undef joff
7070 #undef jmove
7071         }
7072
7073         njobs += 4;
7074         jobtab = jp;
7075         jp = (struct job *)((char *)jp + len);
7076         jq = jp + 3;
7077         do {
7078                 jq->used = 0;
7079         } while (--jq >= jp);
7080         return jp;
7081 }
7082
7083
7084 /*
7085  * Fork off a subshell.  If we are doing job control, give the subshell its
7086  * own process group.  Jp is a job structure that the job is to be added to.
7087  * N is the command that will be evaluated by the child.  Both jp and n may
7088  * be NULL.  The mode parameter can be one of the following:
7089  *      FORK_FG - Fork off a foreground process.
7090  *      FORK_BG - Fork off a background process.
7091  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
7092  *                   process group even if job control is on.
7093  *
7094  * When job control is turned off, background processes have their standard
7095  * input redirected to /dev/null (except for the second and later processes
7096  * in a pipeline).
7097  *
7098  * Called with interrupts off.
7099  */
7100
7101 static inline void
7102 forkchild(struct job *jp, union node *n, int mode)
7103 {
7104         int wasroot;
7105
7106         TRACE(("Child shell %d\n", getpid()));
7107         wasroot = rootshell;
7108         rootshell = 0;
7109
7110         closescript();
7111         clear_traps();
7112 #if JOBS
7113         /* do job control only in root shell */
7114         jobctl = 0;
7115         if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7116                 pid_t pgrp;
7117
7118                 if (jp->nprocs == 0)
7119                         pgrp = getpid();
7120                 else
7121                         pgrp = jp->ps[0].pid;
7122                 /* This can fail because we are doing it in the parent also */
7123                 (void)setpgid(0, pgrp);
7124                 if (mode == FORK_FG)
7125                         xtcsetpgrp(ttyfd, pgrp);
7126                 setsignal(SIGTSTP);
7127                 setsignal(SIGTTOU);
7128         } else
7129 #endif
7130         if (mode == FORK_BG) {
7131                 ignoresig(SIGINT);
7132                 ignoresig(SIGQUIT);
7133                 if (jp->nprocs == 0) {
7134                         close(0);
7135                         if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7136                                 error("Can't open %s", _PATH_DEVNULL);
7137                 }
7138         }
7139         if (wasroot && iflag) {
7140                 setsignal(SIGINT);
7141                 setsignal(SIGQUIT);
7142                 setsignal(SIGTERM);
7143         }
7144         for (jp = curjob; jp; jp = jp->prev_job)
7145                 freejob(jp);
7146         jobless = 0;
7147 }
7148
7149 static inline void
7150 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7151 {
7152         TRACE(("In parent shell:  child = %d\n", pid));
7153         if (!jp) {
7154                 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7155                 jobless++;
7156                 return;
7157         }
7158 #if JOBS
7159         if (mode != FORK_NOJOB && jp->jobctl) {
7160                 int pgrp;
7161
7162                 if (jp->nprocs == 0)
7163                         pgrp = pid;
7164                 else
7165                         pgrp = jp->ps[0].pid;
7166                 /* This can fail because we are doing it in the child also */
7167                 (void)setpgid(pid, pgrp);
7168         }
7169 #endif
7170         if (mode == FORK_BG) {
7171                 backgndpid = pid;               /* set $! */
7172                 set_curjob(jp, CUR_RUNNING);
7173         }
7174         if (jp) {
7175                 struct procstat *ps = &jp->ps[jp->nprocs++];
7176                 ps->pid = pid;
7177                 ps->status = -1;
7178                 ps->cmd = nullstr;
7179 #if JOBS
7180                 if (jobctl && n)
7181                         ps->cmd = commandtext(n);
7182 #endif
7183         }
7184 }
7185
7186 static int
7187 forkshell(struct job *jp, union node *n, int mode)
7188 {
7189         int pid;
7190
7191         TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7192         pid = fork();
7193         if (pid < 0) {
7194                 TRACE(("Fork failed, errno=%d", errno));
7195                 if (jp)
7196                         freejob(jp);
7197                 error("Cannot fork");
7198         }
7199         if (pid == 0)
7200                 forkchild(jp, n, mode);
7201         else
7202                 forkparent(jp, n, mode, pid);
7203         return pid;
7204 }
7205
7206 /*
7207  * Wait for job to finish.
7208  *
7209  * Under job control we have the problem that while a child process is
7210  * running interrupts generated by the user are sent to the child but not
7211  * to the shell.  This means that an infinite loop started by an inter-
7212  * active user may be hard to kill.  With job control turned off, an
7213  * interactive user may place an interactive program inside a loop.  If
7214  * the interactive program catches interrupts, the user doesn't want
7215  * these interrupts to also abort the loop.  The approach we take here
7216  * is to have the shell ignore interrupt signals while waiting for a
7217  * forground process to terminate, and then send itself an interrupt
7218  * signal if the child process was terminated by an interrupt signal.
7219  * Unfortunately, some programs want to do a bit of cleanup and then
7220  * exit on interrupt; unless these processes terminate themselves by
7221  * sending a signal to themselves (instead of calling exit) they will
7222  * confuse this approach.
7223  *
7224  * Called with interrupts off.
7225  */
7226
7227 int
7228 waitforjob(struct job *jp)
7229 {
7230         int st;
7231
7232         TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7233         while (jp->state == JOBRUNNING) {
7234                 dowait(DOWAIT_BLOCK, jp);
7235         }
7236         st = getstatus(jp);
7237 #if JOBS
7238         if (jp->jobctl) {
7239                 xtcsetpgrp(ttyfd, rootpid);
7240                 /*
7241                  * This is truly gross.
7242                  * If we're doing job control, then we did a TIOCSPGRP which
7243                  * caused us (the shell) to no longer be in the controlling
7244                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
7245                  * intuit from the subprocess exit status whether a SIGINT
7246                  * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
7247                  */
7248                 if (jp->sigint)
7249                         raise(SIGINT);
7250         }
7251         if (jp->state == JOBDONE)
7252 #endif
7253                 freejob(jp);
7254         return st;
7255 }
7256
7257
7258 /*
7259  * Do a wait system call.  If job control is compiled in, we accept
7260  * stopped processes.  If block is zero, we return a value of zero
7261  * rather than blocking.
7262  *
7263  * System V doesn't have a non-blocking wait system call.  It does
7264  * have a SIGCLD signal that is sent to a process when one of it's
7265  * children dies.  The obvious way to use SIGCLD would be to install
7266  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7267  * was received, and have waitproc bump another counter when it got
7268  * the status of a process.  Waitproc would then know that a wait
7269  * system call would not block if the two counters were different.
7270  * This approach doesn't work because if a process has children that
7271  * have not been waited for, System V will send it a SIGCLD when it
7272  * installs a signal handler for SIGCLD.  What this means is that when
7273  * a child exits, the shell will be sent SIGCLD signals continuously
7274  * until is runs out of stack space, unless it does a wait call before
7275  * restoring the signal handler.  The code below takes advantage of
7276  * this (mis)feature by installing a signal handler for SIGCLD and
7277  * then checking to see whether it was called.  If there are any
7278  * children to be waited for, it will be.
7279  *
7280  * If neither SYSV nor BSD is defined, we don't implement nonblocking
7281  * waits at all.  In this case, the user will not be informed when
7282  * a background process until the next time she runs a real program
7283  * (as opposed to running a builtin command or just typing return),
7284  * and the jobs command may give out of date information.
7285  */
7286
7287 static inline int
7288 waitproc(int block, int *status)
7289 {
7290         int flags = 0;
7291
7292 #if JOBS
7293         if (jobctl)
7294                 flags |= WUNTRACED;
7295 #endif
7296         if (block == 0)
7297                 flags |= WNOHANG;
7298         return wait3(status, flags, (struct rusage *)NULL);
7299 }
7300
7301 /*
7302  * Wait for a process to terminate.
7303  */
7304
7305 static int
7306 dowait(int block, struct job *job)
7307 {
7308         int pid;
7309         int status;
7310         struct job *jp;
7311         struct job *thisjob;
7312         int state;
7313
7314         TRACE(("dowait(%d) called\n", block));
7315         pid = waitproc(block, &status);
7316         TRACE(("wait returns pid %d, status=%d\n", pid, status));
7317         if (pid <= 0)
7318                 return pid;
7319         INTOFF;
7320         thisjob = NULL;
7321         for (jp = curjob; jp; jp = jp->prev_job) {
7322                 struct procstat *sp;
7323                 struct procstat *spend;
7324                 if (jp->state == JOBDONE)
7325                         continue;
7326                 state = JOBDONE;
7327                 spend = jp->ps + jp->nprocs;
7328                 sp = jp->ps;
7329                 do {
7330                         if (sp->pid == pid) {
7331                                 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7332                                 sp->status = status;
7333                                 thisjob = jp;
7334                         }
7335                         if (sp->status == -1)
7336                                 state = JOBRUNNING;
7337 #ifdef JOBS
7338                         if (state == JOBRUNNING)
7339                                 continue;
7340                         if (WIFSTOPPED(sp->status)) {
7341                                 jp->stopstatus = sp->status;
7342                                 state = JOBSTOPPED;
7343                         }
7344 #endif
7345                 } while (++sp < spend);
7346                 if (thisjob)
7347                         goto gotjob;
7348         }
7349 #ifdef JOBS
7350         if (!WIFSTOPPED(status))
7351 #endif
7352
7353                 jobless--;
7354         goto out;
7355
7356 gotjob:
7357         if (state != JOBRUNNING) {
7358                 thisjob->changed = 1;
7359
7360                 if (thisjob->state != state) {
7361                         TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7362                         thisjob->state = state;
7363 #ifdef JOBS
7364                         if (state == JOBSTOPPED) {
7365                                 set_curjob(thisjob, CUR_STOPPED);
7366                         }
7367 #endif
7368                 }
7369         }
7370
7371 out:
7372         INTON;
7373
7374         if (thisjob && thisjob == job) {
7375                 char s[48 + 1];
7376                 int len;
7377
7378                 len = sprint_status(s, status, 1);
7379                 if (len) {
7380                         s[len] = '\n';
7381                         s[len + 1] = 0;
7382                         out2str(s);
7383                 }
7384         }
7385         return pid;
7386 }
7387
7388
7389 /*
7390  * return 1 if there are stopped jobs, otherwise 0
7391  */
7392
7393 int
7394 stoppedjobs(void)
7395 {
7396         struct job *jp;
7397         int retval;
7398
7399         retval = 0;
7400         if (job_warning)
7401                 goto out;
7402         jp = curjob;
7403         if (jp && jp->state == JOBSTOPPED) {
7404                 out2str("You have stopped jobs.\n");
7405                 job_warning = 2;
7406                 retval++;
7407         }
7408
7409 out:
7410         return retval;
7411 }
7412
7413 /*
7414  * Return a string identifying a command (to be printed by the
7415  * jobs command).
7416  */
7417
7418 #if JOBS
7419 static char *cmdnextc;
7420
7421 static char *
7422 commandtext(union node *n)
7423 {
7424         char *name;
7425
7426         STARTSTACKSTR(cmdnextc);
7427         cmdtxt(n);
7428         name = stackblock();
7429         TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7430                 name, cmdnextc, cmdnextc));
7431         return savestr(name);
7432 }
7433
7434 static void
7435 cmdtxt(union node *n)
7436 {
7437         union node *np;
7438         struct nodelist *lp;
7439         const char *p;
7440         char s[2];
7441
7442         if (!n)
7443                 return;
7444         switch (n->type) {
7445         default:
7446 #if DEBUG
7447                 abort();
7448 #endif
7449         case NPIPE:
7450                 lp = n->npipe.cmdlist;
7451                 for (;;) {
7452                         cmdtxt(lp->n);
7453                         lp = lp->next;
7454                         if (!lp)
7455                                 break;
7456                         cmdputs(" | ");
7457                 }
7458                 break;
7459         case NSEMI:
7460                 p = "; ";
7461                 goto binop;
7462         case NAND:
7463                 p = " && ";
7464                 goto binop;
7465         case NOR:
7466                 p = " || ";
7467 binop:
7468                 cmdtxt(n->nbinary.ch1);
7469                 cmdputs(p);
7470                 n = n->nbinary.ch2;
7471                 goto donode;
7472         case NREDIR:
7473         case NBACKGND:
7474                 n = n->nredir.n;
7475                 goto donode;
7476         case NNOT:
7477                 cmdputs("!");
7478                 n = n->nnot.com;
7479 donode:
7480                 cmdtxt(n);
7481                 break;
7482         case NIF:
7483                 cmdputs("if ");
7484                 cmdtxt(n->nif.test);
7485                 cmdputs("; then ");
7486                 n = n->nif.ifpart;
7487                 if (n->nif.elsepart) {
7488                         cmdtxt(n);
7489                         cmdputs("; else ");
7490                         n = n->nif.elsepart;
7491                 }
7492                 p = "; fi";
7493                 goto dotail;
7494         case NSUBSHELL:
7495                 cmdputs("(");
7496                 n = n->nredir.n;
7497                 p = ")";
7498                 goto dotail;
7499         case NWHILE:
7500                 p = "while ";
7501                 goto until;
7502         case NUNTIL:
7503                 p = "until ";
7504 until:
7505                 cmdputs(p);
7506                 cmdtxt(n->nbinary.ch1);
7507                 n = n->nbinary.ch2;
7508                 p = "; done";
7509 dodo:
7510                 cmdputs("; do ");
7511 dotail:
7512                 cmdtxt(n);
7513                 goto dotail2;
7514         case NFOR:
7515                 cmdputs("for ");
7516                 cmdputs(n->nfor.var);
7517                 cmdputs(" in ");
7518                 cmdlist(n->nfor.args, 1);
7519                 n = n->nfor.body;
7520                 p = "; done";
7521                 goto dodo;
7522         case NDEFUN:
7523                 cmdputs(n->narg.text);
7524                 p = "() { ... }";
7525                 goto dotail2;
7526         case NCMD:
7527                 cmdlist(n->ncmd.args, 1);
7528                 cmdlist(n->ncmd.redirect, 0);
7529                 break;
7530         case NARG:
7531                 p = n->narg.text;
7532 dotail2:
7533                 cmdputs(p);
7534                 break;
7535         case NHERE:
7536         case NXHERE:
7537                 p = "<<...";
7538                 goto dotail2;
7539         case NCASE:
7540                 cmdputs("case ");
7541                 cmdputs(n->ncase.expr->narg.text);
7542                 cmdputs(" in ");
7543                 for (np = n->ncase.cases; np; np = np->nclist.next) {
7544                         cmdtxt(np->nclist.pattern);
7545                         cmdputs(") ");
7546                         cmdtxt(np->nclist.body);
7547                         cmdputs(";; ");
7548                 }
7549                 p = "esac";
7550                 goto dotail2;
7551         case NTO:
7552                 p = ">";
7553                 goto redir;
7554         case NCLOBBER:
7555                 p = ">|";
7556                 goto redir;
7557         case NAPPEND:
7558                 p = ">>";
7559                 goto redir;
7560         case NTOFD:
7561                 p = ">&";
7562                 goto redir;
7563         case NFROM:
7564                 p = "<";
7565                 goto redir;
7566         case NFROMFD:
7567                 p = "<&";
7568                 goto redir;
7569         case NFROMTO:
7570                 p = "<>";
7571 redir:
7572                 s[0] = n->nfile.fd + '0';
7573                 s[1] = '\0';
7574                 cmdputs(s);
7575                 cmdputs(p);
7576                 if (n->type == NTOFD || n->type == NFROMFD) {
7577                         s[0] = n->ndup.dupfd + '0';
7578                         p = s;
7579                         goto dotail2;
7580                 } else {
7581                         n = n->nfile.fname;
7582                         goto donode;
7583                 }
7584         }
7585 }
7586
7587 static void
7588 cmdlist(union node *np, int sep)
7589 {
7590         for (; np; np = np->narg.next) {
7591                 if (!sep)
7592                         cmdputs(spcstr);
7593                 cmdtxt(np);
7594                 if (sep && np->narg.next)
7595                         cmdputs(spcstr);
7596         }
7597 }
7598
7599 static void
7600 cmdputs(const char *s)
7601 {
7602         const char *p, *str;
7603         char c, cc[2] = " ";
7604         char *nextc;
7605         int subtype = 0;
7606         int quoted = 0;
7607         static const char *const vstype[16] = {
7608                 nullstr, "}", "-", "+", "?", "=",
7609                 "#", "##", "%", "%%"
7610         };
7611
7612         nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7613         p = s;
7614         while ((c = *p++) != 0) {
7615                 str = 0;
7616                 switch (c) {
7617                 case CTLESC:
7618                         c = *p++;
7619                         break;
7620                 case CTLVAR:
7621                         subtype = *p++;
7622                         if ((subtype & VSTYPE) == VSLENGTH)
7623                                 str = "${#";
7624                         else
7625                                 str = "${";
7626                         if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7627                                 quoted ^= 1;
7628                                 c = '"';
7629                         } else
7630                                 goto dostr;
7631                         break;
7632                 case CTLENDVAR:
7633                         quoted >>= 1;
7634                         subtype = 0;
7635                         if (quoted & 1) {
7636                                 str = "\"}";
7637                                 goto dostr;
7638                         }
7639                         c = '}';
7640                         break;
7641                 case CTLBACKQ:
7642                         str = "$(...)";
7643                         goto dostr;
7644                 case CTLBACKQ+CTLQUOTE:
7645                         str = "\"$(...)\"";
7646                         goto dostr;
7647 #ifdef CONFIG_ASH_MATH_SUPPORT
7648                 case CTLARI:
7649                         str = "$((";
7650                         goto dostr;
7651                 case CTLENDARI:
7652                         str = "))";
7653                         goto dostr;
7654 #endif
7655                 case CTLQUOTEMARK:
7656                         quoted ^= 1;
7657                         c = '"';
7658                         break;
7659                 case '=':
7660                         if (subtype == 0)
7661                                 break;
7662                         str = vstype[subtype & VSTYPE];
7663                         if (subtype & VSNUL)
7664                                 c = ':';
7665                         else
7666                                 c = *str++;
7667                         if (c != '}')
7668                                 quoted <<= 1;
7669                         break;
7670                 case '\'':
7671                 case '\\':
7672                 case '"':
7673                 case '$':
7674                         /* These can only happen inside quotes */
7675                         cc[0] = c;
7676                         str = cc;
7677                         c = '\\';
7678                         break;
7679                 default:
7680                         break;
7681                 }
7682                 USTPUTC(c, nextc);
7683                 if (!str)
7684                         continue;
7685 dostr:
7686                 while ((c = *str++)) {
7687                         USTPUTC(c, nextc);
7688                 }
7689         }
7690         if (quoted & 1) {
7691                 USTPUTC('"', nextc);
7692         }
7693         *nextc = 0;
7694         cmdnextc = nextc;
7695 }
7696
7697
7698 static void
7699 showpipe(struct job *jp, FILE *out)
7700 {
7701         struct procstat *sp;
7702         struct procstat *spend;
7703
7704         spend = jp->ps + jp->nprocs;
7705         for (sp = jp->ps + 1; sp < spend; sp++)
7706                 fprintf(out, " | %s", sp->cmd);
7707         outcslow('\n', out);
7708         flushall();
7709 }
7710
7711 static void
7712 xtcsetpgrp(int fd, pid_t pgrp)
7713 {
7714         if (tcsetpgrp(fd, pgrp))
7715                 error("Cannot set tty process group (%m)");
7716 }
7717 #endif /* JOBS */
7718
7719 static int
7720 getstatus(struct job *job) {
7721         int status;
7722         int retval;
7723
7724         status = job->ps[job->nprocs - 1].status;
7725         retval = WEXITSTATUS(status);
7726         if (!WIFEXITED(status)) {
7727 #if JOBS
7728                 retval = WSTOPSIG(status);
7729                 if (!WIFSTOPPED(status))
7730 #endif
7731                 {
7732                         /* XXX: limits number of signals */
7733                         retval = WTERMSIG(status);
7734 #if JOBS
7735                         if (retval == SIGINT)
7736                                 job->sigint = 1;
7737 #endif
7738                 }
7739                 retval += 128;
7740         }
7741         TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7742                 jobno(job), job->nprocs, status, retval));
7743         return retval;
7744 }
7745
7746 #ifdef CONFIG_ASH_MAIL
7747 /*      $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $       */
7748
7749 /*
7750  * Routines to check for mail.  (Perhaps make part of main.c?)
7751  */
7752
7753 #define MAXMBOXES 10
7754
7755 /* times of mailboxes */
7756 static time_t mailtime[MAXMBOXES];
7757 /* Set if MAIL or MAILPATH is changed. */
7758 static int mail_var_path_changed;
7759
7760
7761
7762 /*
7763  * Print appropriate message(s) if mail has arrived.
7764  * If mail_var_path_changed is set,
7765  * then the value of MAIL has mail_var_path_changed,
7766  * so we just update the values.
7767  */
7768
7769 static void
7770 chkmail(void)
7771 {
7772         const char *mpath;
7773         char *p;
7774         char *q;
7775         time_t *mtp;
7776         struct stackmark smark;
7777         struct stat statb;
7778
7779         setstackmark(&smark);
7780         mpath = mpathset() ? mpathval() : mailval();
7781         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7782                 p = padvance(&mpath, nullstr);
7783                 if (p == NULL)
7784                         break;
7785                 if (*p == '\0')
7786                         continue;
7787                 for (q = p ; *q ; q++);
7788 #ifdef DEBUG
7789                 if (q[-1] != '/')
7790                         abort();
7791 #endif
7792                 q[-1] = '\0';                   /* delete trailing '/' */
7793                 if (stat(p, &statb) < 0) {
7794                         *mtp = 0;
7795                         continue;
7796                 }
7797                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7798                         fprintf(
7799                                 stderr, snlfmt,
7800                                 pathopt ? pathopt : "you have mail"
7801                         );
7802                 }
7803                 *mtp = statb.st_mtime;
7804         }
7805         mail_var_path_changed = 0;
7806         popstackmark(&smark);
7807 }
7808
7809
7810 static void
7811 changemail(const char *val)
7812 {
7813         mail_var_path_changed++;
7814 }
7815
7816 #endif /* CONFIG_ASH_MAIL */
7817
7818 /*      $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $       */
7819
7820
7821 #if PROFILE
7822 static short profile_buf[16384];
7823 extern int etext();
7824 #endif
7825
7826 static int isloginsh;
7827
7828 static void read_profile(const char *);
7829
7830 /*
7831  * Main routine.  We initialize things, parse the arguments, execute
7832  * profiles if we're a login shell, and then call cmdloop to execute
7833  * commands.  The setjmp call sets up the location to jump to when an
7834  * exception occurs.  When an exception occurs the variable "state"
7835  * is used to figure out how far we had gotten.
7836  */
7837
7838 int
7839 ash_main(int argc, char **argv)
7840 {
7841         char *shinit;
7842         volatile int state;
7843         struct jmploc jmploc;
7844         struct stackmark smark;
7845
7846 #ifdef __GLIBC__
7847         dash_errno = __errno_location();
7848 #endif
7849
7850 #if PROFILE
7851         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7852 #endif
7853         state = 0;
7854         if (setjmp(jmploc.loc)) {
7855                 int status;
7856                 int e;
7857
7858                 reset();
7859
7860                 e = exception;
7861                 switch (exception) {
7862                 case EXEXEC:
7863                         status = exerrno;
7864                         break;
7865
7866                 case EXERROR:
7867                         status = 2;
7868                         break;
7869
7870                 default:
7871                         status = exitstatus;
7872                         break;
7873                 }
7874                 exitstatus = status;
7875
7876                 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7877                         exitshell();
7878
7879                 if (e == EXINT) {
7880                         outcslow('\n', stderr);
7881                 }
7882                 popstackmark(&smark);
7883                 FORCEINTON;                             /* enable interrupts */
7884                 if (state == 1)
7885                         goto state1;
7886                 else if (state == 2)
7887                         goto state2;
7888                 else if (state == 3)
7889                         goto state3;
7890                 else
7891                         goto state4;
7892         }
7893         handler = &jmploc;
7894 #ifdef DEBUG
7895         opentrace();
7896         trputs("Shell args:  ");  trargs(argv);
7897 #endif
7898         rootpid = getpid();
7899         rootshell = 1;
7900         init();
7901         setstackmark(&smark);
7902         procargs(argc, argv);
7903 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7904         if ( iflag ) {
7905                 const char *hp = lookupvar("HISTFILE");
7906
7907                 if(hp == NULL ) {
7908                         hp = lookupvar("HOME");
7909                         if(hp != NULL) {
7910                                 char *defhp = concat_path_file(hp, ".ash_history");
7911                                 setvar("HISTFILE", defhp, 0);
7912                                 free(defhp);
7913                         }
7914                 }
7915         }
7916 #endif
7917         if (argv[0] && argv[0][0] == '-')
7918                 isloginsh = 1;
7919         if (isloginsh) {
7920                 state = 1;
7921                 read_profile("/etc/profile");
7922 state1:
7923                 state = 2;
7924                 read_profile(".profile");
7925         }
7926 state2:
7927         state = 3;
7928         if (
7929 #ifndef linux
7930                 getuid() == geteuid() && getgid() == getegid() &&
7931 #endif
7932                 iflag
7933         ) {
7934                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7935                         read_profile(shinit);
7936                 }
7937         }
7938 state3:
7939         state = 4;
7940         if (minusc)
7941                 evalstring(minusc);
7942
7943         if (sflag || minusc == NULL) {
7944 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7945             if ( iflag ) {
7946                 const char *hp = lookupvar("HISTFILE");
7947
7948                 if(hp != NULL )
7949                         load_history ( hp );
7950             }
7951 #endif
7952 state4: /* XXX ??? - why isn't this before the "if" statement */
7953                 cmdloop(1);
7954         }
7955 #if PROFILE
7956         monitor(0);
7957 #endif
7958 #if GPROF
7959         {
7960                 extern void _mcleanup(void);
7961                 _mcleanup();
7962         }
7963 #endif
7964         exitshell();
7965         /* NOTREACHED */
7966 }
7967
7968
7969 /*
7970  * Read and execute commands.  "Top" is nonzero for the top level command
7971  * loop; it turns on prompting if the shell is interactive.
7972  */
7973
7974 static void
7975 cmdloop(int top)
7976 {
7977         union node *n;
7978         struct stackmark smark;
7979         int inter;
7980         int numeof = 0;
7981
7982         TRACE(("cmdloop(%d) called\n", top));
7983         for (;;) {
7984                 setstackmark(&smark);
7985                 if (pendingsigs)
7986                         dotrap();
7987 #if JOBS
7988                 if (jobctl)
7989                         showjobs(stderr, SHOW_CHANGED);
7990 #endif
7991                 inter = 0;
7992                 if (iflag && top) {
7993                         inter++;
7994 #ifdef CONFIG_ASH_MAIL
7995                         chkmail();
7996 #endif
7997                 }
7998                 n = parsecmd(inter);
7999                 /* showtree(n); DEBUG */
8000                 if (n == NEOF) {
8001                         if (!top || numeof >= 50)
8002                                 break;
8003                         if (!stoppedjobs()) {
8004                                 if (!Iflag)
8005                                         break;
8006                                 out2str("\nUse \"exit\" to leave shell.\n");
8007                         }
8008                         numeof++;
8009                 } else if (n != NULL && nflag == 0) {
8010                         job_warning = (job_warning == 2) ? 1 : 0;
8011                         numeof = 0;
8012                         evaltree(n, 0);
8013                 }
8014                 popstackmark(&smark);
8015                 if (evalskip) {
8016                         evalskip = 0;
8017                         break;
8018                 }
8019         }
8020 }
8021
8022
8023 /*
8024  * Read /etc/profile or .profile.  Return on error.
8025  */
8026
8027 static void
8028 read_profile(const char *name)
8029 {
8030         int fd;
8031         int xflag_set = 0;
8032         int vflag_set = 0;
8033
8034         INTOFF;
8035         if ((fd = open(name, O_RDONLY)) >= 0)
8036                 setinputfd(fd, 1);
8037         INTON;
8038         if (fd < 0)
8039                 return;
8040         /* -q turns off -x and -v just when executing init files */
8041         if (qflag)  {
8042             if (xflag)
8043                     xflag = 0, xflag_set = 1;
8044             if (vflag)
8045                     vflag = 0, vflag_set = 1;
8046         }
8047         cmdloop(0);
8048         if (qflag)  {
8049             if (xflag_set)
8050                     xflag = 1;
8051             if (vflag_set)
8052                     vflag = 1;
8053         }
8054         popfile();
8055 }
8056
8057
8058 /*
8059  * Read a file containing shell functions.
8060  */
8061
8062 static void
8063 readcmdfile(char *name)
8064 {
8065         int fd;
8066
8067         INTOFF;
8068         if ((fd = open(name, O_RDONLY)) >= 0)
8069                 setinputfd(fd, 1);
8070         else
8071                 error("Can't open %s", name);
8072         INTON;
8073         cmdloop(0);
8074         popfile();
8075 }
8076
8077
8078 /*
8079  * Take commands from a file.  To be compatible we should do a path
8080  * search for the file, which is necessary to find sub-commands.
8081  */
8082
8083 static inline char *
8084 find_dot_file(char *name)
8085 {
8086         char *fullname;
8087         const char *path = pathval();
8088         struct stat statb;
8089
8090         /* don't try this for absolute or relative paths */
8091         if (strchr(name, '/'))
8092                 return name;
8093
8094         while ((fullname = padvance(&path, name)) != NULL) {
8095                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8096                         /*
8097                          * Don't bother freeing here, since it will
8098                          * be freed by the caller.
8099                          */
8100                         return fullname;
8101                 }
8102                 stunalloc(fullname);
8103         }
8104
8105         /* not found in the PATH */
8106         error(not_found_msg, name);
8107         /* NOTREACHED */
8108 }
8109
8110 int
8111 dotcmd(int argc, char **argv)
8112 {
8113         exitstatus = 0;
8114
8115         if (argc >= 2) {                /* That's what SVR2 does */
8116                 char *fullname;
8117                 struct stackmark smark;
8118
8119                 setstackmark(&smark);
8120                 fullname = find_dot_file(argv[1]);
8121                 setinputfile(fullname, 1);
8122                 commandname = fullname;
8123                 cmdloop(0);
8124                 popfile();
8125                 popstackmark(&smark);
8126         }
8127         return exitstatus;
8128 }
8129
8130
8131 static int
8132 exitcmd(int argc, char **argv)
8133 {
8134         if (stoppedjobs())
8135                 return 0;
8136         if (argc > 1)
8137                 exitstatus = number(argv[1]);
8138         exraise(EXEXIT);
8139         /* NOTREACHED */
8140 }
8141
8142 /*      $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $        */
8143
8144 /*
8145  * Same for malloc, realloc, but returns an error when out of space.
8146  */
8147
8148 static pointer
8149 ckrealloc(pointer p, size_t nbytes)
8150 {
8151         p = realloc(p, nbytes);
8152         if (p == NULL)
8153                 error(bb_msg_memory_exhausted);
8154         return p;
8155 }
8156
8157 static pointer
8158 ckmalloc(size_t nbytes)
8159 {
8160         return ckrealloc(NULL, nbytes);
8161 }
8162
8163 /*
8164  * Make a copy of a string in safe storage.
8165  */
8166
8167 static char *
8168 savestr(const char *s)
8169 {
8170         char *p = strdup(s);
8171         if (!p)
8172                 error(bb_msg_memory_exhausted);
8173         return p;
8174 }
8175
8176
8177 /*
8178  * Parse trees for commands are allocated in lifo order, so we use a stack
8179  * to make this more efficient, and also to avoid all sorts of exception
8180  * handling code to handle interrupts in the middle of a parse.
8181  *
8182  * The size 504 was chosen because the Ultrix malloc handles that size
8183  * well.
8184  */
8185
8186
8187 static pointer
8188 stalloc(size_t nbytes)
8189 {
8190         char *p;
8191         size_t aligned;
8192
8193         aligned = SHELL_ALIGN(nbytes);
8194         if (aligned > stacknleft) {
8195                 size_t len;
8196                 size_t blocksize;
8197                 struct stack_block *sp;
8198
8199                 blocksize = aligned;
8200                 if (blocksize < MINSIZE)
8201                         blocksize = MINSIZE;
8202                 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8203                 if (len < blocksize)
8204                         error(bb_msg_memory_exhausted);
8205                 INTOFF;
8206                 sp = ckmalloc(len);
8207                 sp->prev = stackp;
8208                 stacknxt = sp->space;
8209                 stacknleft = blocksize;
8210                 sstrend = stacknxt + blocksize;
8211                 stackp = sp;
8212                 INTON;
8213         }
8214         p = stacknxt;
8215         stacknxt += aligned;
8216         stacknleft -= aligned;
8217         return p;
8218 }
8219
8220
8221 void
8222 stunalloc(pointer p)
8223 {
8224 #ifdef DEBUG
8225         if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8226                 write(2, "stunalloc\n", 10);
8227                 abort();
8228         }
8229 #endif
8230         stacknleft += stacknxt - (char *)p;
8231         stacknxt = p;
8232 }
8233
8234
8235 void
8236 setstackmark(struct stackmark *mark)
8237 {
8238         mark->stackp = stackp;
8239         mark->stacknxt = stacknxt;
8240         mark->stacknleft = stacknleft;
8241         mark->marknext = markp;
8242         markp = mark;
8243 }
8244
8245
8246 void
8247 popstackmark(struct stackmark *mark)
8248 {
8249         struct stack_block *sp;
8250
8251         INTOFF;
8252         markp = mark->marknext;
8253         while (stackp != mark->stackp) {
8254                 sp = stackp;
8255                 stackp = sp->prev;
8256                 ckfree(sp);
8257         }
8258         stacknxt = mark->stacknxt;
8259         stacknleft = mark->stacknleft;
8260         sstrend = mark->stacknxt + mark->stacknleft;
8261         INTON;
8262 }
8263
8264
8265 /*
8266  * When the parser reads in a string, it wants to stick the string on the
8267  * stack and only adjust the stack pointer when it knows how big the
8268  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
8269  * of space on top of the stack and stackblocklen returns the length of
8270  * this block.  Growstackblock will grow this space by at least one byte,
8271  * possibly moving it (like realloc).  Grabstackblock actually allocates the
8272  * part of the block that has been used.
8273  */
8274
8275 void
8276 growstackblock(void)
8277 {
8278         size_t newlen;
8279
8280         newlen = stacknleft * 2;
8281         if (newlen < stacknleft)
8282                 error(bb_msg_memory_exhausted);
8283         if (newlen < 128)
8284                 newlen += 128;
8285
8286         if (stacknxt == stackp->space && stackp != &stackbase) {
8287                 struct stack_block *oldstackp;
8288                 struct stackmark *xmark;
8289                 struct stack_block *sp;
8290                 struct stack_block *prevstackp;
8291                 size_t grosslen;
8292
8293                 INTOFF;
8294                 oldstackp = stackp;
8295                 sp = stackp;
8296                 prevstackp = sp->prev;
8297                 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8298                 sp = ckrealloc((pointer)sp, grosslen);
8299                 sp->prev = prevstackp;
8300                 stackp = sp;
8301                 stacknxt = sp->space;
8302                 stacknleft = newlen;
8303                 sstrend = sp->space + newlen;
8304
8305                 /*
8306                  * Stack marks pointing to the start of the old block
8307                  * must be relocated to point to the new block
8308                  */
8309                 xmark = markp;
8310                 while (xmark != NULL && xmark->stackp == oldstackp) {
8311                         xmark->stackp = stackp;
8312                         xmark->stacknxt = stacknxt;
8313                         xmark->stacknleft = stacknleft;
8314                         xmark = xmark->marknext;
8315                 }
8316                 INTON;
8317         } else {
8318                 char *oldspace = stacknxt;
8319                 int oldlen = stacknleft;
8320                 char *p = stalloc(newlen);
8321
8322                 /* free the space we just allocated */
8323                 stacknxt = memcpy(p, oldspace, oldlen);
8324                 stacknleft += newlen;
8325         }
8326 }
8327
8328 static inline void
8329 grabstackblock(size_t len)
8330 {
8331         len = SHELL_ALIGN(len);
8332         stacknxt += len;
8333         stacknleft -= len;
8334 }
8335
8336 /*
8337  * The following routines are somewhat easier to use than the above.
8338  * The user declares a variable of type STACKSTR, which may be declared
8339  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
8340  * the user uses the macro STPUTC to add characters to the string.  In
8341  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8342  * grown as necessary.  When the user is done, she can just leave the
8343  * string there and refer to it using stackblock().  Or she can allocate
8344  * the space for it using grabstackstr().  If it is necessary to allow
8345  * someone else to use the stack temporarily and then continue to grow
8346  * the string, the user should use grabstack to allocate the space, and
8347  * then call ungrabstr(p) to return to the previous mode of operation.
8348  *
8349  * USTPUTC is like STPUTC except that it doesn't check for overflow.
8350  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8351  * is space for at least one character.
8352  */
8353
8354 void *
8355 growstackstr(void)
8356 {
8357         size_t len = stackblocksize();
8358         if (herefd >= 0 && len >= 1024) {
8359                 xwrite(herefd, stackblock(), len);
8360                 return stackblock();
8361         }
8362         growstackblock();
8363         return stackblock() + len;
8364 }
8365
8366 /*
8367  * Called from CHECKSTRSPACE.
8368  */
8369
8370 char *
8371 makestrspace(size_t newlen, char *p)
8372 {
8373         size_t len = p - stacknxt;
8374         size_t size = stackblocksize();
8375
8376         for (;;) {
8377                 size_t nleft;
8378
8379                 size = stackblocksize();
8380                 nleft = size - len;
8381                 if (nleft >= newlen)
8382                         break;
8383                 growstackblock();
8384         }
8385         return stackblock() + len;
8386 }
8387
8388 char *
8389 stnputs(const char *s, size_t n, char *p)
8390 {
8391         p = makestrspace(n, p);
8392         p = mempcpy(p, s, n);
8393         return p;
8394 }
8395
8396 char *
8397 stputs(const char *s, char *p)
8398 {
8399         return stnputs(s, strlen(s), p);
8400 }
8401
8402 /*      $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $   */
8403
8404 /*
8405  * String functions.
8406  *
8407  *      number(s)               Convert a string of digits to an integer.
8408  *      is_number(s)            Return true if s is a string of digits.
8409  */
8410
8411 /*
8412  * prefix -- see if pfx is a prefix of string.
8413  */
8414
8415 char *
8416 prefix(const char *string, const char *pfx)
8417 {
8418         while (*pfx) {
8419                 if (*pfx++ != *string++)
8420                         return 0;
8421         }
8422         return (char *) string;
8423 }
8424
8425
8426 /*
8427  * Convert a string of digits to an integer, printing an error message on
8428  * failure.
8429  */
8430
8431 int
8432 number(const char *s)
8433 {
8434
8435         if (! is_number(s))
8436                 error(illnum, s);
8437         return atoi(s);
8438 }
8439
8440
8441 /*
8442  * Check for a valid number.  This should be elsewhere.
8443  */
8444
8445 int
8446 is_number(const char *p)
8447 {
8448         do {
8449                 if (! is_digit(*p))
8450                         return 0;
8451         } while (*++p != '\0');
8452         return 1;
8453 }
8454
8455
8456 /*
8457  * Produce a possibly single quoted string suitable as input to the shell.
8458  * The return string is allocated on the stack.
8459  */
8460
8461 char *
8462 single_quote(const char *s) {
8463         char *p;
8464
8465         STARTSTACKSTR(p);
8466
8467         do {
8468                 char *q;
8469                 size_t len;
8470
8471                 len = strchrnul(s, '\'') - s;
8472
8473                 q = p = makestrspace(len + 3, p);
8474
8475                 *q++ = '\'';
8476                 q = mempcpy(q, s, len);
8477                 *q++ = '\'';
8478                 s += len;
8479
8480                 STADJUST(q - p, p);
8481
8482                 len = strspn(s, "'");
8483                 if (!len)
8484                         break;
8485
8486                 q = p = makestrspace(len + 3, p);
8487
8488                 *q++ = '"';
8489                 q = mempcpy(q, s, len);
8490                 *q++ = '"';
8491                 s += len;
8492
8493                 STADJUST(q - p, p);
8494         } while (*s);
8495
8496         USTPUTC(0, p);
8497
8498         return stackblock();
8499 }
8500
8501 /*
8502  * Like strdup but works with the ash stack.
8503  */
8504
8505 char *
8506 sstrdup(const char *p)
8507 {
8508         size_t len = strlen(p) + 1;
8509         return memcpy(stalloc(len), p, len);
8510 }
8511
8512
8513 static void
8514 calcsize(union node *n)
8515 {
8516       if (n == NULL)
8517             return;
8518       funcblocksize += nodesize[n->type];
8519       switch (n->type) {
8520       case NCMD:
8521             calcsize(n->ncmd.redirect);
8522             calcsize(n->ncmd.args);
8523             calcsize(n->ncmd.assign);
8524             break;
8525       case NPIPE:
8526             sizenodelist(n->npipe.cmdlist);
8527             break;
8528       case NREDIR:
8529       case NBACKGND:
8530       case NSUBSHELL:
8531             calcsize(n->nredir.redirect);
8532             calcsize(n->nredir.n);
8533             break;
8534       case NAND:
8535       case NOR:
8536       case NSEMI:
8537       case NWHILE:
8538       case NUNTIL:
8539             calcsize(n->nbinary.ch2);
8540             calcsize(n->nbinary.ch1);
8541             break;
8542       case NIF:
8543             calcsize(n->nif.elsepart);
8544             calcsize(n->nif.ifpart);
8545             calcsize(n->nif.test);
8546             break;
8547       case NFOR:
8548             funcstringsize += strlen(n->nfor.var) + 1;
8549             calcsize(n->nfor.body);
8550             calcsize(n->nfor.args);
8551             break;
8552       case NCASE:
8553             calcsize(n->ncase.cases);
8554             calcsize(n->ncase.expr);
8555             break;
8556       case NCLIST:
8557             calcsize(n->nclist.body);
8558             calcsize(n->nclist.pattern);
8559             calcsize(n->nclist.next);
8560             break;
8561       case NDEFUN:
8562       case NARG:
8563             sizenodelist(n->narg.backquote);
8564             funcstringsize += strlen(n->narg.text) + 1;
8565             calcsize(n->narg.next);
8566             break;
8567       case NTO:
8568       case NCLOBBER:
8569       case NFROM:
8570       case NFROMTO:
8571       case NAPPEND:
8572             calcsize(n->nfile.fname);
8573             calcsize(n->nfile.next);
8574             break;
8575       case NTOFD:
8576       case NFROMFD:
8577             calcsize(n->ndup.vname);
8578             calcsize(n->ndup.next);
8579             break;
8580       case NHERE:
8581       case NXHERE:
8582             calcsize(n->nhere.doc);
8583             calcsize(n->nhere.next);
8584             break;
8585       case NNOT:
8586             calcsize(n->nnot.com);
8587             break;
8588       };
8589 }
8590
8591
8592 static void
8593 sizenodelist(struct nodelist *lp)
8594 {
8595         while (lp) {
8596                 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8597                 calcsize(lp->n);
8598                 lp = lp->next;
8599         }
8600 }
8601
8602
8603 static union node *
8604 copynode(union node *n)
8605 {
8606       union node *new;
8607
8608       if (n == NULL)
8609             return NULL;
8610       new = funcblock;
8611       funcblock = (char *) funcblock + nodesize[n->type];
8612       switch (n->type) {
8613       case NCMD:
8614             new->ncmd.redirect = copynode(n->ncmd.redirect);
8615             new->ncmd.args = copynode(n->ncmd.args);
8616             new->ncmd.assign = copynode(n->ncmd.assign);
8617             break;
8618       case NPIPE:
8619             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8620             new->npipe.backgnd = n->npipe.backgnd;
8621             break;
8622       case NREDIR:
8623       case NBACKGND:
8624       case NSUBSHELL:
8625             new->nredir.redirect = copynode(n->nredir.redirect);
8626             new->nredir.n = copynode(n->nredir.n);
8627             break;
8628       case NAND:
8629       case NOR:
8630       case NSEMI:
8631       case NWHILE:
8632       case NUNTIL:
8633             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8634             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8635             break;
8636       case NIF:
8637             new->nif.elsepart = copynode(n->nif.elsepart);
8638             new->nif.ifpart = copynode(n->nif.ifpart);
8639             new->nif.test = copynode(n->nif.test);
8640             break;
8641       case NFOR:
8642             new->nfor.var = nodesavestr(n->nfor.var);
8643             new->nfor.body = copynode(n->nfor.body);
8644             new->nfor.args = copynode(n->nfor.args);
8645             break;
8646       case NCASE:
8647             new->ncase.cases = copynode(n->ncase.cases);
8648             new->ncase.expr = copynode(n->ncase.expr);
8649             break;
8650       case NCLIST:
8651             new->nclist.body = copynode(n->nclist.body);
8652             new->nclist.pattern = copynode(n->nclist.pattern);
8653             new->nclist.next = copynode(n->nclist.next);
8654             break;
8655       case NDEFUN:
8656       case NARG:
8657             new->narg.backquote = copynodelist(n->narg.backquote);
8658             new->narg.text = nodesavestr(n->narg.text);
8659             new->narg.next = copynode(n->narg.next);
8660             break;
8661       case NTO:
8662       case NCLOBBER:
8663       case NFROM:
8664       case NFROMTO:
8665       case NAPPEND:
8666             new->nfile.fname = copynode(n->nfile.fname);
8667             new->nfile.fd = n->nfile.fd;
8668             new->nfile.next = copynode(n->nfile.next);
8669             break;
8670       case NTOFD:
8671       case NFROMFD:
8672             new->ndup.vname = copynode(n->ndup.vname);
8673             new->ndup.dupfd = n->ndup.dupfd;
8674             new->ndup.fd = n->ndup.fd;
8675             new->ndup.next = copynode(n->ndup.next);
8676             break;
8677       case NHERE:
8678       case NXHERE:
8679             new->nhere.doc = copynode(n->nhere.doc);
8680             new->nhere.fd = n->nhere.fd;
8681             new->nhere.next = copynode(n->nhere.next);
8682             break;
8683       case NNOT:
8684             new->nnot.com = copynode(n->nnot.com);
8685             break;
8686       };
8687       new->type = n->type;
8688         return new;
8689 }
8690
8691
8692 static struct nodelist *
8693 copynodelist(struct nodelist *lp)
8694 {
8695         struct nodelist *start;
8696         struct nodelist **lpp;
8697
8698         lpp = &start;
8699         while (lp) {
8700                 *lpp = funcblock;
8701                 funcblock = (char *) funcblock +
8702                     SHELL_ALIGN(sizeof(struct nodelist));
8703                 (*lpp)->n = copynode(lp->n);
8704                 lp = lp->next;
8705                 lpp = &(*lpp)->next;
8706         }
8707         *lpp = NULL;
8708         return start;
8709 }
8710
8711
8712 static char *
8713 nodesavestr(char   *s)
8714 {
8715         char   *rtn = funcstring;
8716
8717         funcstring = stpcpy(funcstring, s) + 1;
8718         return rtn;
8719 }
8720
8721
8722 /*
8723  * Free a parse tree.
8724  */
8725
8726 static void
8727 freefunc(struct funcnode *f)
8728 {
8729         if (f && --f->count < 0)
8730                 ckfree(f);
8731 }
8732
8733
8734 static void options(int);
8735 static void setoption(int, int);
8736
8737
8738 /*
8739  * Process the shell command line arguments.
8740  */
8741
8742 void
8743 procargs(int argc, char **argv)
8744 {
8745         int i;
8746         const char *xminusc;
8747         char **xargv;
8748
8749         xargv = argv;
8750         arg0 = xargv[0];
8751         if (argc > 0)
8752                 xargv++;
8753         for (i = 0; i < NOPTS; i++)
8754                 optlist[i] = 2;
8755         argptr = xargv;
8756         options(1);
8757         xargv = argptr;
8758         xminusc = minusc;
8759         if (*xargv == NULL) {
8760                 if (xminusc)
8761                         error("-c requires an argument");
8762                 sflag = 1;
8763         }
8764         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8765                 iflag = 1;
8766         if (mflag == 2)
8767                 mflag = iflag;
8768         for (i = 0; i < NOPTS; i++)
8769                 if (optlist[i] == 2)
8770                         optlist[i] = 0;
8771 #if DEBUG == 2
8772         debug = 1;
8773 #endif
8774         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8775         if (xminusc) {
8776                 minusc = *xargv++;
8777                 if (*xargv)
8778                         goto setarg0;
8779         } else if (!sflag) {
8780                 setinputfile(*xargv, 0);
8781 setarg0:
8782                 arg0 = *xargv++;
8783                 commandname = arg0;
8784         }
8785
8786         shellparam.p = xargv;
8787 #ifdef CONFIG_ASH_GETOPTS
8788         shellparam.optind = 1;
8789         shellparam.optoff = -1;
8790 #endif
8791         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8792         while (*xargv) {
8793                 shellparam.nparam++;
8794                 xargv++;
8795         }
8796         optschanged();
8797 }
8798
8799
8800 void
8801 optschanged(void)
8802 {
8803 #ifdef DEBUG
8804         opentrace();
8805 #endif
8806         setinteractive(iflag);
8807         setjobctl(mflag);
8808 }
8809
8810 static inline void
8811 minus_o(char *name, int val)
8812 {
8813         int i;
8814
8815         if (name == NULL) {
8816                 out1str("Current option settings\n");
8817                 for (i = 0; i < NOPTS; i++)
8818                         out1fmt("%-16s%s\n", optnames(i),
8819                                 optlist[i] ? "on" : "off");
8820         } else {
8821                 for (i = 0; i < NOPTS; i++)
8822                         if (equal(name, optnames(i))) {
8823                                 optlist[i] = val;
8824                                 return;
8825                         }
8826                 error("Illegal option -o %s", name);
8827         }
8828 }
8829
8830 /*
8831  * Process shell options.  The global variable argptr contains a pointer
8832  * to the argument list; we advance it past the options.
8833  */
8834
8835 static void
8836 options(int cmdline)
8837 {
8838         char *p;
8839         int val;
8840         int c;
8841
8842         if (cmdline)
8843                 minusc = NULL;
8844         while ((p = *argptr) != NULL) {
8845                 argptr++;
8846                 if ((c = *p++) == '-') {
8847                         val = 1;
8848                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8849                                 if (!cmdline) {
8850                                         /* "-" means turn off -x and -v */
8851                                         if (p[0] == '\0')
8852                                                 xflag = vflag = 0;
8853                                         /* "--" means reset params */
8854                                         else if (*argptr == NULL)
8855                                                 setparam(argptr);
8856                                 }
8857                                 break;    /* "-" or  "--" terminates options */
8858                         }
8859                 } else if (c == '+') {
8860                         val = 0;
8861                 } else {
8862                         argptr--;
8863                         break;
8864                 }
8865                 while ((c = *p++) != '\0') {
8866                         if (c == 'c' && cmdline) {
8867                                 minusc = p;     /* command is after shell args*/
8868                         } else if (c == 'o') {
8869                                 minus_o(*argptr, val);
8870                                 if (*argptr)
8871                                         argptr++;
8872                         } else if (cmdline && (c == '-')) {     // long options
8873                                 if (strcmp(p, "login") == 0)
8874                                         isloginsh = 1;
8875                                 break;
8876                         } else {
8877                                 setoption(c, val);
8878                         }
8879                 }
8880         }
8881 }
8882
8883
8884 static void
8885 setoption(int flag, int val)
8886 {
8887         int i;
8888
8889         for (i = 0; i < NOPTS; i++)
8890                 if (optletters(i) == flag) {
8891                         optlist[i] = val;
8892                         return;
8893                 }
8894         error("Illegal option -%c", flag);
8895         /* NOTREACHED */
8896 }
8897
8898
8899
8900 /*
8901  * Set the shell parameters.
8902  */
8903
8904 void
8905 setparam(char **argv)
8906 {
8907         char **newparam;
8908         char **ap;
8909         int nparam;
8910
8911         for (nparam = 0 ; argv[nparam] ; nparam++);
8912         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8913         while (*argv) {
8914                 *ap++ = savestr(*argv++);
8915         }
8916         *ap = NULL;
8917         freeparam(&shellparam);
8918         shellparam.malloc = 1;
8919         shellparam.nparam = nparam;
8920         shellparam.p = newparam;
8921 #ifdef CONFIG_ASH_GETOPTS
8922         shellparam.optind = 1;
8923         shellparam.optoff = -1;
8924 #endif
8925 }
8926
8927
8928 /*
8929  * Free the list of positional parameters.
8930  */
8931
8932 void
8933 freeparam(volatile struct shparam *param)
8934 {
8935         char **ap;
8936
8937         if (param->malloc) {
8938                 for (ap = param->p ; *ap ; ap++)
8939                         ckfree(*ap);
8940                 ckfree(param->p);
8941         }
8942 }
8943
8944
8945
8946 /*
8947  * The shift builtin command.
8948  */
8949
8950 int
8951 shiftcmd(int argc, char **argv)
8952 {
8953         int n;
8954         char **ap1, **ap2;
8955
8956         n = 1;
8957         if (argc > 1)
8958                 n = number(argv[1]);
8959         if (n > shellparam.nparam)
8960                 error("can't shift that many");
8961         INTOFF;
8962         shellparam.nparam -= n;
8963         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8964                 if (shellparam.malloc)
8965                         ckfree(*ap1);
8966         }
8967         ap2 = shellparam.p;
8968         while ((*ap2++ = *ap1++) != NULL);
8969 #ifdef CONFIG_ASH_GETOPTS
8970         shellparam.optind = 1;
8971         shellparam.optoff = -1;
8972 #endif
8973         INTON;
8974         return 0;
8975 }
8976
8977
8978
8979 /*
8980  * The set command builtin.
8981  */
8982
8983 int
8984 setcmd(int argc, char **argv)
8985 {
8986         if (argc == 1)
8987                 return showvars(nullstr, 0, VUNSET);
8988         INTOFF;
8989         options(0);
8990         optschanged();
8991         if (*argptr != NULL) {
8992                 setparam(argptr);
8993         }
8994         INTON;
8995         return 0;
8996 }
8997
8998
8999 #ifdef CONFIG_ASH_GETOPTS
9000 static void
9001 getoptsreset(value)
9002         const char *value;
9003 {
9004         shellparam.optind = number(value);
9005         shellparam.optoff = -1;
9006 }
9007 #endif
9008
9009 #ifdef CONFIG_LOCALE_SUPPORT
9010 static void change_lc_all(const char *value)
9011 {
9012         if (value != 0 && *value != 0)
9013                 setlocale(LC_ALL, value);
9014 }
9015
9016 static void change_lc_ctype(const char *value)
9017 {
9018         if (value != 0 && *value != 0)
9019                 setlocale(LC_CTYPE, value);
9020 }
9021
9022 #endif
9023
9024 #ifdef CONFIG_ASH_GETOPTS
9025 static int
9026 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9027 {
9028         char *p, *q;
9029         char c = '?';
9030         int done = 0;
9031         int err = 0;
9032         char s[12];
9033         char **optnext;
9034
9035         if(*param_optind < 1)
9036                 return 1;
9037         optnext = optfirst + *param_optind - 1;
9038
9039         if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9040                 p = NULL;
9041         else
9042                 p = optnext[-1] + *optoff;
9043         if (p == NULL || *p == '\0') {
9044                 /* Current word is done, advance */
9045                 p = *optnext;
9046                 if (p == NULL || *p != '-' || *++p == '\0') {
9047 atend:
9048                         p = NULL;
9049                         done = 1;
9050                         goto out;
9051                 }
9052                 optnext++;
9053                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9054                         goto atend;
9055         }
9056
9057         c = *p++;
9058         for (q = optstr; *q != c; ) {
9059                 if (*q == '\0') {
9060                         if (optstr[0] == ':') {
9061                                 s[0] = c;
9062                                 s[1] = '\0';
9063                                 err |= setvarsafe("OPTARG", s, 0);
9064                         } else {
9065                                 fprintf(stderr, "Illegal option -%c\n", c);
9066                                 (void) unsetvar("OPTARG");
9067                         }
9068                         c = '?';
9069                         goto out;
9070                 }
9071                 if (*++q == ':')
9072                         q++;
9073         }
9074
9075         if (*++q == ':') {
9076                 if (*p == '\0' && (p = *optnext) == NULL) {
9077                         if (optstr[0] == ':') {
9078                                 s[0] = c;
9079                                 s[1] = '\0';
9080                                 err |= setvarsafe("OPTARG", s, 0);
9081                                 c = ':';
9082                         } else {
9083                                 fprintf(stderr, "No arg for -%c option\n", c);
9084                                 (void) unsetvar("OPTARG");
9085                                 c = '?';
9086                         }
9087                         goto out;
9088                 }
9089
9090                 if (p == *optnext)
9091                         optnext++;
9092                 err |= setvarsafe("OPTARG", p, 0);
9093                 p = NULL;
9094         } else
9095                 err |= setvarsafe("OPTARG", nullstr, 0);
9096
9097 out:
9098         *optoff = p ? p - *(optnext - 1) : -1;
9099         *param_optind = optnext - optfirst + 1;
9100         fmtstr(s, sizeof(s), "%d", *param_optind);
9101         err |= setvarsafe("OPTIND", s, VNOFUNC);
9102         s[0] = c;
9103         s[1] = '\0';
9104         err |= setvarsafe(optvar, s, 0);
9105         if (err) {
9106                 *param_optind = 1;
9107                 *optoff = -1;
9108                 flushall();
9109                 exraise(EXERROR);
9110         }
9111         return done;
9112 }
9113
9114 /*
9115  * The getopts builtin.  Shellparam.optnext points to the next argument
9116  * to be processed.  Shellparam.optptr points to the next character to
9117  * be processed in the current argument.  If shellparam.optnext is NULL,
9118  * then it's the first time getopts has been called.
9119  */
9120
9121 int
9122 getoptscmd(int argc, char **argv)
9123 {
9124         char **optbase;
9125
9126         if (argc < 3)
9127                 error("Usage: getopts optstring var [arg]");
9128         else if (argc == 3) {
9129                 optbase = shellparam.p;
9130                 if (shellparam.optind > shellparam.nparam + 1) {
9131                         shellparam.optind = 1;
9132                         shellparam.optoff = -1;
9133                 }
9134         }
9135         else {
9136                 optbase = &argv[3];
9137                 if (shellparam.optind > argc - 2) {
9138                         shellparam.optind = 1;
9139                         shellparam.optoff = -1;
9140                 }
9141         }
9142
9143         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9144                        &shellparam.optoff);
9145 }
9146 #endif /* CONFIG_ASH_GETOPTS */
9147
9148 /*
9149  * XXX - should get rid of.  have all builtins use getopt(3).  the
9150  * library getopt must have the BSD extension static variable "optreset"
9151  * otherwise it can't be used within the shell safely.
9152  *
9153  * Standard option processing (a la getopt) for builtin routines.  The
9154  * only argument that is passed to nextopt is the option string; the
9155  * other arguments are unnecessary.  It return the character, or '\0' on
9156  * end of input.
9157  */
9158
9159 static int
9160 nextopt(const char *optstring)
9161 {
9162         char *p;
9163         const char *q;
9164         char c;
9165
9166         if ((p = optptr) == NULL || *p == '\0') {
9167                 p = *argptr;
9168                 if (p == NULL || *p != '-' || *++p == '\0')
9169                         return '\0';
9170                 argptr++;
9171                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9172                         return '\0';
9173         }
9174         c = *p++;
9175         for (q = optstring ; *q != c ; ) {
9176                 if (*q == '\0')
9177                         error("Illegal option -%c", c);
9178                 if (*++q == ':')
9179                         q++;
9180         }
9181         if (*++q == ':') {
9182                 if (*p == '\0' && (p = *argptr++) == NULL)
9183                         error("No arg for -%c option", c);
9184                 optionarg = p;
9185                 p = NULL;
9186         }
9187         optptr = p;
9188         return c;
9189 }
9190
9191
9192 /*      $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $     */
9193
9194 void
9195 outstr(const char *p, FILE *file)
9196 {
9197         INTOFF;
9198         fputs(p, file);
9199         INTON;
9200 }
9201
9202 void
9203 flushall(void)
9204 {
9205         INTOFF;
9206         fflush(stdout);
9207         fflush(stderr);
9208         INTON;
9209 }
9210
9211 void
9212 flushout(FILE *dest)
9213 {
9214         INTOFF;
9215         fflush(dest);
9216         INTON;
9217 }
9218
9219 static void
9220 outcslow(int c, FILE *dest)
9221 {
9222         INTOFF;
9223         putc(c, dest);
9224         fflush(dest);
9225         INTON;
9226 }
9227
9228
9229 static int
9230 out1fmt(const char *fmt, ...)
9231 {
9232         va_list ap;
9233         int r;
9234
9235         INTOFF;
9236         va_start(ap, fmt);
9237         r = vprintf(fmt, ap);
9238         va_end(ap);
9239         INTON;
9240         return r;
9241 }
9242
9243
9244 int
9245 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9246 {
9247         va_list ap;
9248         int ret;
9249
9250         va_start(ap, fmt);
9251         INTOFF;
9252         ret = vsnprintf(outbuf, length, fmt, ap);
9253         va_end(ap);
9254         INTON;
9255         return ret;
9256 }
9257
9258
9259 /*
9260  * Version of write which resumes after a signal is caught.
9261  */
9262
9263 static void
9264 xwrite(int fd, const void *p, size_t n)
9265 {
9266         ssize_t i;
9267
9268         do {
9269                 i = bb_full_write(fd, p, n);
9270         } while (i < 0 && errno == EINTR);
9271 }
9272
9273
9274 /*      $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $     */
9275
9276
9277 /*
9278  * Shell command parser.
9279  */
9280
9281 #define EOFMARKLEN 79
9282
9283
9284 struct heredoc {
9285         struct heredoc *next;   /* next here document in list */
9286         union node *here;               /* redirection node */
9287         char *eofmark;          /* string indicating end of input */
9288         int striptabs;          /* if set, strip leading tabs */
9289 };
9290
9291
9292
9293 static struct heredoc *heredoclist;    /* list of here documents to read */
9294
9295
9296 static union node *list(int);
9297 static union node *andor(void);
9298 static union node *pipeline(void);
9299 static union node *command(void);
9300 static union node *simplecmd(void);
9301 static union node *makename(void);
9302 static void parsefname(void);
9303 static void parseheredoc(void);
9304 static char peektoken(void);
9305 static int readtoken(void);
9306 static int xxreadtoken(void);
9307 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9308 static int noexpand(char *);
9309 static void synexpect(int) __attribute__((__noreturn__));
9310 static void synerror(const char *) __attribute__((__noreturn__));
9311 static void setprompt(int);
9312
9313
9314
9315 static inline int
9316 isassignment(const char *p)
9317 {
9318         const char *q = endofname(p);
9319         if (p == q)
9320                 return 0;
9321         return *q == '=';
9322 }
9323
9324
9325 /*
9326  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9327  * valid parse tree indicating a blank line.)
9328  */
9329
9330 union node *
9331 parsecmd(int interact)
9332 {
9333         int t;
9334
9335         tokpushback = 0;
9336         doprompt = interact;
9337         if (doprompt)
9338                 setprompt(doprompt);
9339         needprompt = 0;
9340         t = readtoken();
9341         if (t == TEOF)
9342                 return NEOF;
9343         if (t == TNL)
9344                 return NULL;
9345         tokpushback++;
9346         return list(1);
9347 }
9348
9349
9350 static union node *
9351 list(int nlflag)
9352 {
9353         union node *n1, *n2, *n3;
9354         int tok;
9355
9356         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9357         if (nlflag == 2 && peektoken())
9358                 return NULL;
9359         n1 = NULL;
9360         for (;;) {
9361                 n2 = andor();
9362                 tok = readtoken();
9363                 if (tok == TBACKGND) {
9364                         if (n2->type == NPIPE) {
9365                                 n2->npipe.backgnd = 1;
9366                         } else {
9367                                 if (n2->type != NREDIR) {
9368                                         n3 = stalloc(sizeof(struct nredir));
9369                                         n3->nredir.n = n2;
9370                                         n3->nredir.redirect = NULL;
9371                                         n2 = n3;
9372                                 }
9373                                 n2->type = NBACKGND;
9374                         }
9375                 }
9376                 if (n1 == NULL) {
9377                         n1 = n2;
9378                 }
9379                 else {
9380                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9381                         n3->type = NSEMI;
9382                         n3->nbinary.ch1 = n1;
9383                         n3->nbinary.ch2 = n2;
9384                         n1 = n3;
9385                 }
9386                 switch (tok) {
9387                 case TBACKGND:
9388                 case TSEMI:
9389                         tok = readtoken();
9390                         /* fall through */
9391                 case TNL:
9392                         if (tok == TNL) {
9393                                 parseheredoc();
9394                                 if (nlflag == 1)
9395                                         return n1;
9396                         } else {
9397                                 tokpushback++;
9398                         }
9399                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9400                         if (peektoken())
9401                                 return n1;
9402                         break;
9403                 case TEOF:
9404                         if (heredoclist)
9405                                 parseheredoc();
9406                         else
9407                                 pungetc();              /* push back EOF on input */
9408                         return n1;
9409                 default:
9410                         if (nlflag == 1)
9411                                 synexpect(-1);
9412                         tokpushback++;
9413                         return n1;
9414                 }
9415         }
9416 }
9417
9418
9419
9420 static union node *
9421 andor(void)
9422 {
9423         union node *n1, *n2, *n3;
9424         int t;
9425
9426         n1 = pipeline();
9427         for (;;) {
9428                 if ((t = readtoken()) == TAND) {
9429                         t = NAND;
9430                 } else if (t == TOR) {
9431                         t = NOR;
9432                 } else {
9433                         tokpushback++;
9434                         return n1;
9435                 }
9436                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9437                 n2 = pipeline();
9438                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9439                 n3->type = t;
9440                 n3->nbinary.ch1 = n1;
9441                 n3->nbinary.ch2 = n2;
9442                 n1 = n3;
9443         }
9444 }
9445
9446
9447
9448 static union node *
9449 pipeline(void)
9450 {
9451         union node *n1, *n2, *pipenode;
9452         struct nodelist *lp, *prev;
9453         int negate;
9454
9455         negate = 0;
9456         TRACE(("pipeline: entered\n"));
9457         if (readtoken() == TNOT) {
9458                 negate = !negate;
9459                 checkkwd = CHKKWD | CHKALIAS;
9460         } else
9461                 tokpushback++;
9462         n1 = command();
9463         if (readtoken() == TPIPE) {
9464                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9465                 pipenode->type = NPIPE;
9466                 pipenode->npipe.backgnd = 0;
9467                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9468                 pipenode->npipe.cmdlist = lp;
9469                 lp->n = n1;
9470                 do {
9471                         prev = lp;
9472                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9473                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9474                         lp->n = command();
9475                         prev->next = lp;
9476                 } while (readtoken() == TPIPE);
9477                 lp->next = NULL;
9478                 n1 = pipenode;
9479         }
9480         tokpushback++;
9481         if (negate) {
9482                 n2 = (union node *)stalloc(sizeof (struct nnot));
9483                 n2->type = NNOT;
9484                 n2->nnot.com = n1;
9485                 return n2;
9486         } else
9487                 return n1;
9488 }
9489
9490
9491
9492 static union node *
9493 command(void)
9494 {
9495         union node *n1, *n2;
9496         union node *ap, **app;
9497         union node *cp, **cpp;
9498         union node *redir, **rpp;
9499         union node **rpp2;
9500         int t;
9501
9502         redir = NULL;
9503         rpp2 = &redir;
9504
9505         switch (readtoken()) {
9506         default:
9507                 synexpect(-1);
9508                 /* NOTREACHED */
9509         case TIF:
9510                 n1 = (union node *)stalloc(sizeof (struct nif));
9511                 n1->type = NIF;
9512                 n1->nif.test = list(0);
9513                 if (readtoken() != TTHEN)
9514                         synexpect(TTHEN);
9515                 n1->nif.ifpart = list(0);
9516                 n2 = n1;
9517                 while (readtoken() == TELIF) {
9518                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9519                         n2 = n2->nif.elsepart;
9520                         n2->type = NIF;
9521                         n2->nif.test = list(0);
9522                         if (readtoken() != TTHEN)
9523                                 synexpect(TTHEN);
9524                         n2->nif.ifpart = list(0);
9525                 }
9526                 if (lasttoken == TELSE)
9527                         n2->nif.elsepart = list(0);
9528                 else {
9529                         n2->nif.elsepart = NULL;
9530                         tokpushback++;
9531                 }
9532                 t = TFI;
9533                 break;
9534         case TWHILE:
9535         case TUNTIL: {
9536                 int got;
9537                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9538                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9539                 n1->nbinary.ch1 = list(0);
9540                 if ((got=readtoken()) != TDO) {
9541 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9542                         synexpect(TDO);
9543                 }
9544                 n1->nbinary.ch2 = list(0);
9545                 t = TDONE;
9546                 break;
9547         }
9548         case TFOR:
9549                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9550                         synerror("Bad for loop variable");
9551                 n1 = (union node *)stalloc(sizeof (struct nfor));
9552                 n1->type = NFOR;
9553                 n1->nfor.var = wordtext;
9554                 checkkwd = CHKKWD | CHKALIAS;
9555                 if (readtoken() == TIN) {
9556                         app = &ap;
9557                         while (readtoken() == TWORD) {
9558                                 n2 = (union node *)stalloc(sizeof (struct narg));
9559                                 n2->type = NARG;
9560                                 n2->narg.text = wordtext;
9561                                 n2->narg.backquote = backquotelist;
9562                                 *app = n2;
9563                                 app = &n2->narg.next;
9564                         }
9565                         *app = NULL;
9566                         n1->nfor.args = ap;
9567                         if (lasttoken != TNL && lasttoken != TSEMI)
9568                                 synexpect(-1);
9569                 } else {
9570                         n2 = (union node *)stalloc(sizeof (struct narg));
9571                         n2->type = NARG;
9572                         n2->narg.text = (char *)dolatstr;
9573                         n2->narg.backquote = NULL;
9574                         n2->narg.next = NULL;
9575                         n1->nfor.args = n2;
9576                         /*
9577                          * Newline or semicolon here is optional (but note
9578                          * that the original Bourne shell only allowed NL).
9579                          */
9580                         if (lasttoken != TNL && lasttoken != TSEMI)
9581                                 tokpushback++;
9582                 }
9583                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9584                 if (readtoken() != TDO)
9585                         synexpect(TDO);
9586                 n1->nfor.body = list(0);
9587                 t = TDONE;
9588                 break;
9589         case TCASE:
9590                 n1 = (union node *)stalloc(sizeof (struct ncase));
9591                 n1->type = NCASE;
9592                 if (readtoken() != TWORD)
9593                         synexpect(TWORD);
9594                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9595                 n2->type = NARG;
9596                 n2->narg.text = wordtext;
9597                 n2->narg.backquote = backquotelist;
9598                 n2->narg.next = NULL;
9599                 do {
9600                         checkkwd = CHKKWD | CHKALIAS;
9601                 } while (readtoken() == TNL);
9602                 if (lasttoken != TIN)
9603                         synexpect(TIN);
9604                 cpp = &n1->ncase.cases;
9605 next_case:
9606                 checkkwd = CHKNL | CHKKWD;
9607                 t = readtoken();
9608                 while(t != TESAC) {
9609                         if (lasttoken == TLP)
9610                                 readtoken();
9611                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9612                         cp->type = NCLIST;
9613                         app = &cp->nclist.pattern;
9614                         for (;;) {
9615                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9616                                 ap->type = NARG;
9617                                 ap->narg.text = wordtext;
9618                                 ap->narg.backquote = backquotelist;
9619                                 if (readtoken() != TPIPE)
9620                                         break;
9621                                 app = &ap->narg.next;
9622                                 readtoken();
9623                         }
9624                         ap->narg.next = NULL;
9625                         if (lasttoken != TRP)
9626                                 synexpect(TRP);
9627                         cp->nclist.body = list(2);
9628
9629                         cpp = &cp->nclist.next;
9630
9631                         checkkwd = CHKNL | CHKKWD;
9632                         if ((t = readtoken()) != TESAC) {
9633                                 if (t != TENDCASE)
9634                                         synexpect(TENDCASE);
9635                                 else
9636                                         goto next_case;
9637                         }
9638                 }
9639                 *cpp = NULL;
9640                 goto redir;
9641         case TLP:
9642                 n1 = (union node *)stalloc(sizeof (struct nredir));
9643                 n1->type = NSUBSHELL;
9644                 n1->nredir.n = list(0);
9645                 n1->nredir.redirect = NULL;
9646                 t = TRP;
9647                 break;
9648         case TBEGIN:
9649                 n1 = list(0);
9650                 t = TEND;
9651                 break;
9652         case TWORD:
9653         case TREDIR:
9654                 tokpushback++;
9655                 return simplecmd();
9656         }
9657
9658         if (readtoken() != t)
9659                 synexpect(t);
9660
9661 redir:
9662         /* Now check for redirection which may follow command */
9663         checkkwd = CHKKWD | CHKALIAS;
9664         rpp = rpp2;
9665         while (readtoken() == TREDIR) {
9666                 *rpp = n2 = redirnode;
9667                 rpp = &n2->nfile.next;
9668                 parsefname();
9669         }
9670         tokpushback++;
9671         *rpp = NULL;
9672         if (redir) {
9673                 if (n1->type != NSUBSHELL) {
9674                         n2 = (union node *)stalloc(sizeof (struct nredir));
9675                         n2->type = NREDIR;
9676                         n2->nredir.n = n1;
9677                         n1 = n2;
9678                 }
9679                 n1->nredir.redirect = redir;
9680         }
9681
9682         return n1;
9683 }
9684
9685
9686 static union node *
9687 simplecmd(void) {
9688         union node *args, **app;
9689         union node *n = NULL;
9690         union node *vars, **vpp;
9691         union node **rpp, *redir;
9692         int savecheckkwd;
9693
9694         args = NULL;
9695         app = &args;
9696         vars = NULL;
9697         vpp = &vars;
9698         redir = NULL;
9699         rpp = &redir;
9700
9701         savecheckkwd = CHKALIAS;
9702         for (;;) {
9703                 checkkwd = savecheckkwd;
9704                 switch (readtoken()) {
9705                 case TWORD:
9706                         n = (union node *)stalloc(sizeof (struct narg));
9707                         n->type = NARG;
9708                         n->narg.text = wordtext;
9709                         n->narg.backquote = backquotelist;
9710                         if (savecheckkwd && isassignment(wordtext)) {
9711                                 *vpp = n;
9712                                 vpp = &n->narg.next;
9713                         } else {
9714                                 *app = n;
9715                                 app = &n->narg.next;
9716                                 savecheckkwd = 0;
9717                         }
9718                         break;
9719                 case TREDIR:
9720                         *rpp = n = redirnode;
9721                         rpp = &n->nfile.next;
9722                         parsefname();   /* read name of redirection file */
9723                         break;
9724                 case TLP:
9725                         if (
9726                                 args && app == &args->narg.next &&
9727                                 !vars && !redir
9728                         ) {
9729                                 struct builtincmd *bcmd;
9730                                 const char *name;
9731
9732                                 /* We have a function */
9733                                 if (readtoken() != TRP)
9734                                         synexpect(TRP);
9735                                 name = n->narg.text;
9736                                 if (
9737                                         !goodname(name) || (
9738                                                 (bcmd = find_builtin(name)) &&
9739                                                 IS_BUILTIN_SPECIAL(bcmd)
9740                                         )
9741                                 )
9742                                         synerror("Bad function name");
9743                                 n->type = NDEFUN;
9744                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9745                                 n->narg.next = command();
9746                                 return n;
9747                         }
9748                         /* fall through */
9749                 default:
9750                         tokpushback++;
9751                         goto out;
9752                 }
9753         }
9754 out:
9755         *app = NULL;
9756         *vpp = NULL;
9757         *rpp = NULL;
9758         n = (union node *)stalloc(sizeof (struct ncmd));
9759         n->type = NCMD;
9760         n->ncmd.args = args;
9761         n->ncmd.assign = vars;
9762         n->ncmd.redirect = redir;
9763         return n;
9764 }
9765
9766 static union node *
9767 makename(void)
9768 {
9769         union node *n;
9770
9771         n = (union node *)stalloc(sizeof (struct narg));
9772         n->type = NARG;
9773         n->narg.next = NULL;
9774         n->narg.text = wordtext;
9775         n->narg.backquote = backquotelist;
9776         return n;
9777 }
9778
9779 void fixredir(union node *n, const char *text, int err)
9780 {
9781         TRACE(("Fix redir %s %d\n", text, err));
9782         if (!err)
9783                 n->ndup.vname = NULL;
9784
9785         if (is_digit(text[0]) && text[1] == '\0')
9786                 n->ndup.dupfd = digit_val(text[0]);
9787         else if (text[0] == '-' && text[1] == '\0')
9788                 n->ndup.dupfd = -1;
9789         else {
9790
9791                 if (err)
9792                         synerror("Bad fd number");
9793                 else
9794                         n->ndup.vname = makename();
9795         }
9796 }
9797
9798
9799 static void
9800 parsefname(void)
9801 {
9802         union node *n = redirnode;
9803
9804         if (readtoken() != TWORD)
9805                 synexpect(-1);
9806         if (n->type == NHERE) {
9807                 struct heredoc *here = heredoc;
9808                 struct heredoc *p;
9809                 int i;
9810
9811                 if (quoteflag == 0)
9812                         n->type = NXHERE;
9813                 TRACE(("Here document %d\n", n->type));
9814                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9815                         synerror("Illegal eof marker for << redirection");
9816                 rmescapes(wordtext);
9817                 here->eofmark = wordtext;
9818                 here->next = NULL;
9819                 if (heredoclist == NULL)
9820                         heredoclist = here;
9821                 else {
9822                         for (p = heredoclist ; p->next ; p = p->next);
9823                         p->next = here;
9824                 }
9825         } else if (n->type == NTOFD || n->type == NFROMFD) {
9826                 fixredir(n, wordtext, 0);
9827         } else {
9828                 n->nfile.fname = makename();
9829         }
9830 }
9831
9832
9833 /*
9834  * Input any here documents.
9835  */
9836
9837 static void
9838 parseheredoc(void)
9839 {
9840         struct heredoc *here;
9841         union node *n;
9842
9843         here = heredoclist;
9844         heredoclist = 0;
9845
9846         while (here) {
9847                 if (needprompt) {
9848                         setprompt(2);
9849                         needprompt = 0;
9850                 }
9851                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9852                                 here->eofmark, here->striptabs);
9853                 n = (union node *)stalloc(sizeof (struct narg));
9854                 n->narg.type = NARG;
9855                 n->narg.next = NULL;
9856                 n->narg.text = wordtext;
9857                 n->narg.backquote = backquotelist;
9858                 here->here->nhere.doc = n;
9859                 here = here->next;
9860         }
9861 }
9862
9863 static char peektoken(void)
9864 {
9865         int t;
9866
9867         t = readtoken();
9868         tokpushback++;
9869         return tokname_array[t][0];
9870 }
9871
9872 static int
9873 readtoken(void)
9874 {
9875         int t;
9876 #ifdef DEBUG
9877         int alreadyseen = tokpushback;
9878 #endif
9879
9880 #ifdef CONFIG_ASH_ALIAS
9881 top:
9882 #endif
9883
9884         t = xxreadtoken();
9885
9886         /*
9887          * eat newlines
9888          */
9889         if (checkkwd & CHKNL) {
9890                 while (t == TNL) {
9891                         parseheredoc();
9892                         t = xxreadtoken();
9893                 }
9894         }
9895
9896         if (t != TWORD || quoteflag) {
9897                 goto out;
9898         }
9899
9900         /*
9901          * check for keywords
9902          */
9903         if (checkkwd & CHKKWD) {
9904                 const char *const *pp;
9905
9906                 if ((pp = findkwd(wordtext))) {
9907                         lasttoken = t = pp - tokname_array;
9908                         TRACE(("keyword %s recognized\n", tokname(t)));
9909                         goto out;
9910                 }
9911         }
9912
9913         if (checkkwd & CHKALIAS) {
9914 #ifdef CONFIG_ASH_ALIAS
9915                 struct alias *ap;
9916                 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9917                         if (*ap->val) {
9918                                 pushstring(ap->val, ap);
9919                         }
9920                         goto top;
9921                 }
9922 #endif
9923         }
9924 out:
9925         checkkwd = 0;
9926 #ifdef DEBUG
9927         if (!alreadyseen)
9928             TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9929         else
9930             TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9931 #endif
9932         return (t);
9933 }
9934
9935
9936 /*
9937  * Read the next input token.
9938  * If the token is a word, we set backquotelist to the list of cmds in
9939  *      backquotes.  We set quoteflag to true if any part of the word was
9940  *      quoted.
9941  * If the token is TREDIR, then we set redirnode to a structure containing
9942  *      the redirection.
9943  * In all cases, the variable startlinno is set to the number of the line
9944  *      on which the token starts.
9945  *
9946  * [Change comment:  here documents and internal procedures]
9947  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
9948  *  word parsing code into a separate routine.  In this case, readtoken
9949  *  doesn't need to have any internal procedures, but parseword does.
9950  *  We could also make parseoperator in essence the main routine, and
9951  *  have parseword (readtoken1?) handle both words and redirection.]
9952  */
9953
9954 #define NEW_xxreadtoken
9955 #ifdef NEW_xxreadtoken
9956
9957 /* singles must be first! */
9958 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9959
9960 static const char xxreadtoken_tokens[] = {
9961         TNL, TLP, TRP,          /* only single occurrence allowed */
9962         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9963         TEOF,                   /* corresponds to trailing nul */
9964         TAND, TOR, TENDCASE,    /* if double occurrence */
9965 };
9966
9967 #define xxreadtoken_doubles \
9968         (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9969 #define xxreadtoken_singles \
9970         (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9971
9972 static int xxreadtoken()
9973 {
9974         int c;
9975
9976         if (tokpushback) {
9977                 tokpushback = 0;
9978                 return lasttoken;
9979         }
9980         if (needprompt) {
9981                 setprompt(2);
9982                 needprompt = 0;
9983         }
9984         startlinno = plinno;
9985         for (;;) {                      /* until token or start of word found */
9986                 c = pgetc_macro();
9987
9988                 if ((c != ' ') && (c != '\t')
9989 #ifdef CONFIG_ASH_ALIAS
9990                         && (c != PEOA)
9991 #endif
9992                         ) {
9993                         if (c == '#') {
9994                                 while ((c = pgetc()) != '\n' && c != PEOF);
9995                                 pungetc();
9996                         } else if (c == '\\') {
9997                                 if (pgetc() != '\n') {
9998                                         pungetc();
9999                                         goto READTOKEN1;
10000                                 }
10001                                 startlinno = ++plinno;
10002                                 if (doprompt)
10003                                         setprompt(2);
10004                         } else {
10005                                 const char *p
10006                                         = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10007
10008                                 if (c != PEOF) {
10009                                         if (c == '\n') {
10010                                                 plinno++;
10011                                                 needprompt = doprompt;
10012                                         }
10013
10014                                         p = strchr(xxreadtoken_chars, c);
10015                                         if (p == NULL) {
10016                                           READTOKEN1:
10017                                                 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10018                                         }
10019
10020                                         if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10021                                                 if (pgetc() == *p) {    /* double occurrence? */
10022                                                         p += xxreadtoken_doubles + 1;
10023                                                 } else {
10024                                                         pungetc();
10025                                                 }
10026                                         }
10027                                 }
10028
10029                                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10030                         }
10031                 }
10032         }
10033 }
10034
10035
10036 #else
10037 #define RETURN(token)   return lasttoken = token
10038
10039 static int
10040 xxreadtoken(void)
10041 {
10042         int c;
10043
10044         if (tokpushback) {
10045                 tokpushback = 0;
10046                 return lasttoken;
10047         }
10048         if (needprompt) {
10049                 setprompt(2);
10050                 needprompt = 0;
10051         }
10052         startlinno = plinno;
10053         for (;;) {      /* until token or start of word found */
10054                 c = pgetc_macro();
10055                 switch (c) {
10056                 case ' ': case '\t':
10057 #ifdef CONFIG_ASH_ALIAS
10058                 case PEOA:
10059 #endif
10060                         continue;
10061                 case '#':
10062                         while ((c = pgetc()) != '\n' && c != PEOF);
10063                         pungetc();
10064                         continue;
10065                 case '\\':
10066                         if (pgetc() == '\n') {
10067                                 startlinno = ++plinno;
10068                                 if (doprompt)
10069                                         setprompt(2);
10070                                 continue;
10071                         }
10072                         pungetc();
10073                         goto breakloop;
10074                 case '\n':
10075                         plinno++;
10076                         needprompt = doprompt;
10077                         RETURN(TNL);
10078                 case PEOF:
10079                         RETURN(TEOF);
10080                 case '&':
10081                         if (pgetc() == '&')
10082                                 RETURN(TAND);
10083                         pungetc();
10084                         RETURN(TBACKGND);
10085                 case '|':
10086                         if (pgetc() == '|')
10087                                 RETURN(TOR);
10088                         pungetc();
10089                         RETURN(TPIPE);
10090                 case ';':
10091                         if (pgetc() == ';')
10092                                 RETURN(TENDCASE);
10093                         pungetc();
10094                         RETURN(TSEMI);
10095                 case '(':
10096                         RETURN(TLP);
10097                 case ')':
10098                         RETURN(TRP);
10099                 default:
10100                         goto breakloop;
10101                 }
10102         }
10103 breakloop:
10104         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10105 #undef RETURN
10106 }
10107 #endif /* NEW_xxreadtoken */
10108
10109
10110 /*
10111  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10112  * is not NULL, read a here document.  In the latter case, eofmark is the
10113  * word which marks the end of the document and striptabs is true if
10114  * leading tabs should be stripped from the document.  The argument firstc
10115  * is the first character of the input token or document.
10116  *
10117  * Because C does not have internal subroutines, I have simulated them
10118  * using goto's to implement the subroutine linkage.  The following macros
10119  * will run code that appears at the end of readtoken1.
10120  */
10121
10122 #define CHECKEND()      {goto checkend; checkend_return:;}
10123 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10124 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10125 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10126 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10127 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10128
10129 static int
10130 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10131 {
10132         int c = firstc;
10133         char *out;
10134         int len;
10135         char line[EOFMARKLEN + 1];
10136         struct nodelist *bqlist;
10137         int quotef;
10138         int dblquote;
10139         int varnest;    /* levels of variables expansion */
10140         int arinest;    /* levels of arithmetic expansion */
10141         int parenlevel; /* levels of parens in arithmetic */
10142         int dqvarnest;  /* levels of variables expansion within double quotes */
10143         int oldstyle;
10144         int prevsyntax; /* syntax before arithmetic */
10145 #if __GNUC__
10146         /* Avoid longjmp clobbering */
10147         (void) &out;
10148         (void) &quotef;
10149         (void) &dblquote;
10150         (void) &varnest;
10151         (void) &arinest;
10152         (void) &parenlevel;
10153         (void) &dqvarnest;
10154         (void) &oldstyle;
10155         (void) &prevsyntax;
10156         (void) &syntax;
10157 #endif
10158
10159         startlinno = plinno;
10160         dblquote = 0;
10161         if (syntax == DQSYNTAX)
10162                 dblquote = 1;
10163         quotef = 0;
10164         bqlist = NULL;
10165         varnest = 0;
10166         arinest = 0;
10167         parenlevel = 0;
10168         dqvarnest = 0;
10169
10170         STARTSTACKSTR(out);
10171         loop: { /* for each line, until end of word */
10172                 CHECKEND();     /* set c to PEOF if at end of here document */
10173                 for (;;) {      /* until end of line or end of word */
10174                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10175                         switch(SIT(c, syntax)) {
10176                         case CNL:       /* '\n' */
10177                                 if (syntax == BASESYNTAX)
10178                                         goto endword;   /* exit outer loop */
10179                                 USTPUTC(c, out);
10180                                 plinno++;
10181                                 if (doprompt)
10182                                         setprompt(2);
10183                                 c = pgetc();
10184                                 goto loop;              /* continue outer loop */
10185                         case CWORD:
10186                                 USTPUTC(c, out);
10187                                 break;
10188                         case CCTL:
10189                                 if (eofmark == NULL || dblquote)
10190                                         USTPUTC(CTLESC, out);
10191                                 USTPUTC(c, out);
10192                                 break;
10193                         case CBACK:     /* backslash */
10194                                 c = pgetc2();
10195                                 if (c == PEOF) {
10196                                         USTPUTC(CTLESC, out);
10197                                         USTPUTC('\\', out);
10198                                         pungetc();
10199                                 } else if (c == '\n') {
10200                                         if (doprompt)
10201                                                 setprompt(2);
10202                                 } else {
10203                                         if (
10204                                                 dblquote &&
10205                                                 c != '\\' && c != '`' &&
10206                                                 c != '$' && (
10207                                                         c != '"' ||
10208                                                         eofmark != NULL
10209                                                 )
10210                                         ) {
10211                                                 USTPUTC(CTLESC, out);
10212                                                 USTPUTC('\\', out);
10213                                         }
10214                                         if (SIT(c, SQSYNTAX) == CCTL)
10215                                                 USTPUTC(CTLESC, out);
10216                                         USTPUTC(c, out);
10217                                         quotef++;
10218                                 }
10219                                 break;
10220                         case CSQUOTE:
10221                                 syntax = SQSYNTAX;
10222 quotemark:
10223                                 if (eofmark == NULL) {
10224                                         USTPUTC(CTLQUOTEMARK, out);
10225                                 }
10226                                 break;
10227                         case CDQUOTE:
10228                                 syntax = DQSYNTAX;
10229                                 dblquote = 1;
10230                                 goto quotemark;
10231                         case CENDQUOTE:
10232                                 if (eofmark != NULL && arinest == 0 &&
10233                                     varnest == 0) {
10234                                         USTPUTC(c, out);
10235                                 } else {
10236                                         if (dqvarnest == 0) {
10237                                                 syntax = BASESYNTAX;
10238                                                 dblquote = 0;
10239                                         }
10240                                         quotef++;
10241                                         goto quotemark;
10242                                 }
10243                                 break;
10244                         case CVAR:      /* '$' */
10245                                 PARSESUB();             /* parse substitution */
10246                                 break;
10247                         case CENDVAR:   /* '}' */
10248                                 if (varnest > 0) {
10249                                         varnest--;
10250                                         if (dqvarnest > 0) {
10251                                                 dqvarnest--;
10252                                         }
10253                                         USTPUTC(CTLENDVAR, out);
10254                                 } else {
10255                                         USTPUTC(c, out);
10256                                 }
10257                                 break;
10258 #ifdef CONFIG_ASH_MATH_SUPPORT
10259                         case CLP:       /* '(' in arithmetic */
10260                                 parenlevel++;
10261                                 USTPUTC(c, out);
10262                                 break;
10263                         case CRP:       /* ')' in arithmetic */
10264                                 if (parenlevel > 0) {
10265                                         USTPUTC(c, out);
10266                                         --parenlevel;
10267                                 } else {
10268                                         if (pgetc() == ')') {
10269                                                 if (--arinest == 0) {
10270                                                         USTPUTC(CTLENDARI, out);
10271                                                         syntax = prevsyntax;
10272                                                         if (syntax == DQSYNTAX)
10273                                                                 dblquote = 1;
10274                                                         else
10275                                                                 dblquote = 0;
10276                                                 } else
10277                                                         USTPUTC(')', out);
10278                                         } else {
10279                                                 /*
10280                                                  * unbalanced parens
10281                                                  *  (don't 2nd guess - no error)
10282                                                  */
10283                                                 pungetc();
10284                                                 USTPUTC(')', out);
10285                                         }
10286                                 }
10287                                 break;
10288 #endif
10289                         case CBQUOTE:   /* '`' */
10290                                 PARSEBACKQOLD();
10291                                 break;
10292                         case CENDFILE:
10293                                 goto endword;           /* exit outer loop */
10294                         case CIGN:
10295                                 break;
10296                         default:
10297                                 if (varnest == 0)
10298                                         goto endword;   /* exit outer loop */
10299 #ifdef CONFIG_ASH_ALIAS
10300                                 if (c != PEOA)
10301 #endif
10302                                         USTPUTC(c, out);
10303
10304                         }
10305                         c = pgetc_macro();
10306                 }
10307         }
10308 endword:
10309 #ifdef CONFIG_ASH_MATH_SUPPORT
10310         if (syntax == ARISYNTAX)
10311                 synerror("Missing '))'");
10312 #endif
10313         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10314                 synerror("Unterminated quoted string");
10315         if (varnest != 0) {
10316                 startlinno = plinno;
10317                 /* { */
10318                 synerror("Missing '}'");
10319         }
10320         USTPUTC('\0', out);
10321         len = out - (char *)stackblock();
10322         out = stackblock();
10323         if (eofmark == NULL) {
10324                 if ((c == '>' || c == '<')
10325                  && quotef == 0
10326                  && len <= 2
10327                  && (*out == '\0' || is_digit(*out))) {
10328                         PARSEREDIR();
10329                         return lasttoken = TREDIR;
10330                 } else {
10331                         pungetc();
10332                 }
10333         }
10334         quoteflag = quotef;
10335         backquotelist = bqlist;
10336         grabstackblock(len);
10337         wordtext = out;
10338         return lasttoken = TWORD;
10339 /* end of readtoken routine */
10340
10341
10342
10343 /*
10344  * Check to see whether we are at the end of the here document.  When this
10345  * is called, c is set to the first character of the next input line.  If
10346  * we are at the end of the here document, this routine sets the c to PEOF.
10347  */
10348
10349 checkend: {
10350         if (eofmark) {
10351 #ifdef CONFIG_ASH_ALIAS
10352                 if (c == PEOA) {
10353                         c = pgetc2();
10354                 }
10355 #endif
10356                 if (striptabs) {
10357                         while (c == '\t') {
10358                                 c = pgetc2();
10359                         }
10360                 }
10361                 if (c == *eofmark) {
10362                         if (pfgets(line, sizeof line) != NULL) {
10363                                 char *p, *q;
10364
10365                                 p = line;
10366                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10367                                 if (*p == '\n' && *q == '\0') {
10368                                         c = PEOF;
10369                                         plinno++;
10370                                         needprompt = doprompt;
10371                                 } else {
10372                                         pushstring(line, NULL);
10373                                 }
10374                         }
10375                 }
10376         }
10377         goto checkend_return;
10378 }
10379
10380
10381 /*
10382  * Parse a redirection operator.  The variable "out" points to a string
10383  * specifying the fd to be redirected.  The variable "c" contains the
10384  * first character of the redirection operator.
10385  */
10386
10387 parseredir: {
10388         char fd = *out;
10389         union node *np;
10390
10391         np = (union node *)stalloc(sizeof (struct nfile));
10392         if (c == '>') {
10393                 np->nfile.fd = 1;
10394                 c = pgetc();
10395                 if (c == '>')
10396                         np->type = NAPPEND;
10397                 else if (c == '|')
10398                         np->type = NCLOBBER;
10399                 else if (c == '&')
10400                         np->type = NTOFD;
10401                 else {
10402                         np->type = NTO;
10403                         pungetc();
10404                 }
10405         } else {        /* c == '<' */
10406                 np->nfile.fd = 0;
10407                 switch (c = pgetc()) {
10408                 case '<':
10409                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10410                                 np = (union node *)stalloc(sizeof (struct nhere));
10411                                 np->nfile.fd = 0;
10412                         }
10413                         np->type = NHERE;
10414                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10415                         heredoc->here = np;
10416                         if ((c = pgetc()) == '-') {
10417                                 heredoc->striptabs = 1;
10418                         } else {
10419                                 heredoc->striptabs = 0;
10420                                 pungetc();
10421                         }
10422                         break;
10423
10424                 case '&':
10425                         np->type = NFROMFD;
10426                         break;
10427
10428                 case '>':
10429                         np->type = NFROMTO;
10430                         break;
10431
10432                 default:
10433                         np->type = NFROM;
10434                         pungetc();
10435                         break;
10436                 }
10437         }
10438         if (fd != '\0')
10439                 np->nfile.fd = digit_val(fd);
10440         redirnode = np;
10441         goto parseredir_return;
10442 }
10443
10444
10445 /*
10446  * Parse a substitution.  At this point, we have read the dollar sign
10447  * and nothing else.
10448  */
10449
10450 parsesub: {
10451         int subtype;
10452         int typeloc;
10453         int flags;
10454         char *p;
10455         static const char types[] = "}-+?=";
10456
10457         c = pgetc();
10458         if (
10459                 c <= PEOA_OR_PEOF  ||
10460                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10461         ) {
10462                 USTPUTC('$', out);
10463                 pungetc();
10464         } else if (c == '(') {  /* $(command) or $((arith)) */
10465                 if (pgetc() == '(') {
10466 #ifdef CONFIG_ASH_MATH_SUPPORT
10467                         PARSEARITH();
10468 #else
10469                         synerror("We unsupport $((arith))");
10470 #endif
10471                 } else {
10472                         pungetc();
10473                         PARSEBACKQNEW();
10474                 }
10475         } else {
10476                 USTPUTC(CTLVAR, out);
10477                 typeloc = out - (char *)stackblock();
10478                 USTPUTC(VSNORMAL, out);
10479                 subtype = VSNORMAL;
10480                 if (c == '{') {
10481                         c = pgetc();
10482                         if (c == '#') {
10483                                 if ((c = pgetc()) == '}')
10484                                         c = '#';
10485                                 else
10486                                         subtype = VSLENGTH;
10487                         }
10488                         else
10489                                 subtype = 0;
10490                 }
10491                 if (c > PEOA_OR_PEOF && is_name(c)) {
10492                         do {
10493                                 STPUTC(c, out);
10494                                 c = pgetc();
10495                         } while (c > PEOA_OR_PEOF && is_in_name(c));
10496                 } else if (is_digit(c)) {
10497                         do {
10498                                 STPUTC(c, out);
10499                                 c = pgetc();
10500                         } while (is_digit(c));
10501                 }
10502                 else if (is_special(c)) {
10503                         USTPUTC(c, out);
10504                         c = pgetc();
10505                 }
10506                 else
10507 badsub:                 synerror("Bad substitution");
10508
10509                 STPUTC('=', out);
10510                 flags = 0;
10511                 if (subtype == 0) {
10512                         switch (c) {
10513                         case ':':
10514                                 flags = VSNUL;
10515                                 c = pgetc();
10516                                 /*FALLTHROUGH*/
10517                         default:
10518                                 p = strchr(types, c);
10519                                 if (p == NULL)
10520                                         goto badsub;
10521                                 subtype = p - types + VSNORMAL;
10522                                 break;
10523                         case '%':
10524                         case '#':
10525                                 {
10526                                         int cc = c;
10527                                         subtype = c == '#' ? VSTRIMLEFT :
10528                                                              VSTRIMRIGHT;
10529                                         c = pgetc();
10530                                         if (c == cc)
10531                                                 subtype++;
10532                                         else
10533                                                 pungetc();
10534                                         break;
10535                                 }
10536                         }
10537                 } else {
10538                         pungetc();
10539                 }
10540                 if (dblquote || arinest)
10541                         flags |= VSQUOTE;
10542                 *((char *)stackblock() + typeloc) = subtype | flags;
10543                 if (subtype != VSNORMAL) {
10544                         varnest++;
10545                         if (dblquote || arinest) {
10546                                 dqvarnest++;
10547                         }
10548                 }
10549         }
10550         goto parsesub_return;
10551 }
10552
10553
10554 /*
10555  * Called to parse command substitutions.  Newstyle is set if the command
10556  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10557  * list of commands (passed by reference), and savelen is the number of
10558  * characters on the top of the stack which must be preserved.
10559  */
10560
10561 parsebackq: {
10562         struct nodelist **nlpp;
10563         int savepbq;
10564         union node *n;
10565         char *volatile str;
10566         struct jmploc jmploc;
10567         struct jmploc *volatile savehandler;
10568         size_t savelen;
10569         int saveprompt;
10570 #ifdef __GNUC__
10571         (void) &saveprompt;
10572 #endif
10573
10574         savepbq = parsebackquote;
10575         if (setjmp(jmploc.loc)) {
10576                 if (str)
10577                         ckfree(str);
10578                 parsebackquote = 0;
10579                 handler = savehandler;
10580                 longjmp(handler->loc, 1);
10581         }
10582         INTOFF;
10583         str = NULL;
10584         savelen = out - (char *)stackblock();
10585         if (savelen > 0) {
10586                 str = ckmalloc(savelen);
10587                 memcpy(str, stackblock(), savelen);
10588         }
10589         savehandler = handler;
10590         handler = &jmploc;
10591         INTON;
10592         if (oldstyle) {
10593                 /* We must read until the closing backquote, giving special
10594                    treatment to some slashes, and then push the string and
10595                    reread it as input, interpreting it normally.  */
10596                 char *pout;
10597                 int pc;
10598                 size_t psavelen;
10599                 char *pstr;
10600
10601
10602                 STARTSTACKSTR(pout);
10603                 for (;;) {
10604                         if (needprompt) {
10605                                 setprompt(2);
10606                                 needprompt = 0;
10607                         }
10608                         switch (pc = pgetc()) {
10609                         case '`':
10610                                 goto done;
10611
10612                         case '\\':
10613                                 if ((pc = pgetc()) == '\n') {
10614                                         plinno++;
10615                                         if (doprompt)
10616                                                 setprompt(2);
10617                                         /*
10618                                          * If eating a newline, avoid putting
10619                                          * the newline into the new character
10620                                          * stream (via the STPUTC after the
10621                                          * switch).
10622                                          */
10623                                         continue;
10624                                 }
10625                                 if (pc != '\\' && pc != '`' && pc != '$'
10626                                     && (!dblquote || pc != '"'))
10627                                         STPUTC('\\', pout);
10628                                 if (pc > PEOA_OR_PEOF) {
10629                                         break;
10630                                 }
10631                                 /* fall through */
10632
10633                         case PEOF:
10634 #ifdef CONFIG_ASH_ALIAS
10635                         case PEOA:
10636 #endif
10637                                 startlinno = plinno;
10638                                 synerror("EOF in backquote substitution");
10639
10640                         case '\n':
10641                                 plinno++;
10642                                 needprompt = doprompt;
10643                                 break;
10644
10645                         default:
10646                                 break;
10647                         }
10648                         STPUTC(pc, pout);
10649                 }
10650 done:
10651                 STPUTC('\0', pout);
10652                 psavelen = pout - (char *)stackblock();
10653                 if (psavelen > 0) {
10654                         pstr = grabstackstr(pout);
10655                         setinputstring(pstr);
10656                 }
10657         }
10658         nlpp = &bqlist;
10659         while (*nlpp)
10660                 nlpp = &(*nlpp)->next;
10661         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10662         (*nlpp)->next = NULL;
10663         parsebackquote = oldstyle;
10664
10665         if (oldstyle) {
10666                 saveprompt = doprompt;
10667                 doprompt = 0;
10668         }
10669
10670         n = list(2);
10671
10672         if (oldstyle)
10673                 doprompt = saveprompt;
10674         else {
10675                 if (readtoken() != TRP)
10676                         synexpect(TRP);
10677         }
10678
10679         (*nlpp)->n = n;
10680         if (oldstyle) {
10681                 /*
10682                  * Start reading from old file again, ignoring any pushed back
10683                  * tokens left from the backquote parsing
10684                  */
10685                 popfile();
10686                 tokpushback = 0;
10687         }
10688         while (stackblocksize() <= savelen)
10689                 growstackblock();
10690         STARTSTACKSTR(out);
10691         if (str) {
10692                 memcpy(out, str, savelen);
10693                 STADJUST(savelen, out);
10694                 INTOFF;
10695                 ckfree(str);
10696                 str = NULL;
10697                 INTON;
10698         }
10699         parsebackquote = savepbq;
10700         handler = savehandler;
10701         if (arinest || dblquote)
10702                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10703         else
10704                 USTPUTC(CTLBACKQ, out);
10705         if (oldstyle)
10706                 goto parsebackq_oldreturn;
10707         else
10708                 goto parsebackq_newreturn;
10709 }
10710
10711 #ifdef CONFIG_ASH_MATH_SUPPORT
10712 /*
10713  * Parse an arithmetic expansion (indicate start of one and set state)
10714  */
10715 parsearith: {
10716
10717         if (++arinest == 1) {
10718                 prevsyntax = syntax;
10719                 syntax = ARISYNTAX;
10720                 USTPUTC(CTLARI, out);
10721                 if (dblquote)
10722                         USTPUTC('"',out);
10723                 else
10724                         USTPUTC(' ',out);
10725         } else {
10726                 /*
10727                  * we collapse embedded arithmetic expansion to
10728                  * parenthesis, which should be equivalent
10729                  */
10730                 USTPUTC('(', out);
10731         }
10732         goto parsearith_return;
10733 }
10734 #endif
10735
10736 } /* end of readtoken */
10737
10738
10739
10740 /*
10741  * Returns true if the text contains nothing to expand (no dollar signs
10742  * or backquotes).
10743  */
10744
10745 static int
10746 noexpand(char *text)
10747 {
10748         char *p;
10749         char c;
10750
10751         p = text;
10752         while ((c = *p++) != '\0') {
10753                 if (c == CTLQUOTEMARK)
10754                         continue;
10755                 if (c == CTLESC)
10756                         p++;
10757                 else if (SIT(c, BASESYNTAX) == CCTL)
10758                         return 0;
10759         }
10760         return 1;
10761 }
10762
10763
10764 /*
10765  * Return of a legal variable name (a letter or underscore followed by zero or
10766  * more letters, underscores, and digits).
10767  */
10768
10769 static char *
10770 endofname(const char *name)
10771 {
10772         char *p;
10773
10774         p = (char *) name;
10775         if (! is_name(*p))
10776                 return p;
10777         while (*++p) {
10778                 if (! is_in_name(*p))
10779                         break;
10780         }
10781         return p;
10782 }
10783
10784
10785 /*
10786  * Called when an unexpected token is read during the parse.  The argument
10787  * is the token that is expected, or -1 if more than one type of token can
10788  * occur at this point.
10789  */
10790
10791 static void synexpect(int token)
10792 {
10793         char msg[64];
10794         int l;
10795
10796         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10797         if (token >= 0)
10798                 sprintf(msg + l, " (expecting %s)", tokname(token));
10799         synerror(msg);
10800         /* NOTREACHED */
10801 }
10802
10803 static void
10804 synerror(const char *msg)
10805 {
10806         error("Syntax error: %s", msg);
10807         /* NOTREACHED */
10808 }
10809
10810
10811 /*
10812  * called by editline -- any expansions to the prompt
10813  *    should be added here.
10814  */
10815
10816 static void setprompt(int whichprompt)
10817 {
10818         const char *prompt;
10819
10820         switch (whichprompt) {
10821         case 1:
10822                 prompt = ps1val();
10823                 break;
10824         case 2:
10825                 prompt = ps2val();
10826                 break;
10827         default:                        /* 0 */
10828                 prompt = nullstr;
10829         }
10830         putprompt(prompt);
10831 }
10832
10833
10834 static const char *const *findkwd(const char *s)
10835 {
10836         return bsearch(s, tokname_array + KWDOFFSET,
10837                        (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10838                                    sizeof(const char *), pstrcmp);
10839 }
10840
10841 /*      $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $      */
10842
10843 /*
10844  * Code for dealing with input/output redirection.
10845  */
10846
10847 #define EMPTY -2                /* marks an unused slot in redirtab */
10848 #ifndef PIPE_BUF
10849 # define PIPESIZE 4096          /* amount of buffering in a pipe */
10850 #else
10851 # define PIPESIZE PIPE_BUF
10852 #endif
10853
10854 /*
10855  * Open a file in noclobber mode.
10856  * The code was copied from bash.
10857  */
10858 static inline int
10859 noclobberopen(const char *fname)
10860 {
10861         int r, fd;
10862         struct stat finfo, finfo2;
10863
10864         /*
10865          * If the file exists and is a regular file, return an error
10866          * immediately.
10867          */
10868         r = stat(fname, &finfo);
10869         if (r == 0 && S_ISREG(finfo.st_mode)) {
10870                 errno = EEXIST;
10871                 return -1;
10872         }
10873
10874         /*
10875          * If the file was not present (r != 0), make sure we open it
10876          * exclusively so that if it is created before we open it, our open
10877          * will fail.  Make sure that we do not truncate an existing file.
10878          * Note that we don't turn on O_EXCL unless the stat failed -- if the
10879          * file was not a regular file, we leave O_EXCL off.
10880          */
10881         if (r != 0)
10882                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10883         fd = open(fname, O_WRONLY|O_CREAT, 0666);
10884
10885         /* If the open failed, return the file descriptor right away. */
10886         if (fd < 0)
10887                 return fd;
10888
10889         /*
10890          * OK, the open succeeded, but the file may have been changed from a
10891          * non-regular file to a regular file between the stat and the open.
10892          * We are assuming that the O_EXCL open handles the case where FILENAME
10893          * did not exist and is symlinked to an existing file between the stat
10894          * and open.
10895          */
10896
10897         /*
10898          * If we can open it and fstat the file descriptor, and neither check
10899          * revealed that it was a regular file, and the file has not been
10900          * replaced, return the file descriptor.
10901          */
10902          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10903              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10904                 return fd;
10905
10906         /* The file has been replaced.  badness. */
10907         close(fd);
10908         errno = EEXIST;
10909         return -1;
10910 }
10911
10912 /*
10913  * Handle here documents.  Normally we fork off a process to write the
10914  * data to a pipe.  If the document is short, we can stuff the data in
10915  * the pipe without forking.
10916  */
10917
10918 static inline int
10919 openhere(union node *redir)
10920 {
10921         int pip[2];
10922         size_t len = 0;
10923
10924         if (pipe(pip) < 0)
10925                 error("Pipe call failed");
10926         if (redir->type == NHERE) {
10927                 len = strlen(redir->nhere.doc->narg.text);
10928                 if (len <= PIPESIZE) {
10929                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
10930                         goto out;
10931                 }
10932         }
10933         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10934                 close(pip[0]);
10935                 signal(SIGINT, SIG_IGN);
10936                 signal(SIGQUIT, SIG_IGN);
10937                 signal(SIGHUP, SIG_IGN);
10938 #ifdef SIGTSTP
10939                 signal(SIGTSTP, SIG_IGN);
10940 #endif
10941                 signal(SIGPIPE, SIG_DFL);
10942                 if (redir->type == NHERE)
10943                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
10944                 else
10945                         expandhere(redir->nhere.doc, pip[1]);
10946                 _exit(0);
10947         }
10948 out:
10949         close(pip[1]);
10950         return pip[0];
10951 }
10952
10953 static int
10954 openredirect(union node *redir)
10955 {
10956         char *fname;
10957         int f;
10958
10959         switch (redir->nfile.type) {
10960         case NFROM:
10961                 fname = redir->nfile.expfname;
10962                 if ((f = open(fname, O_RDONLY)) < 0)
10963                         goto eopen;
10964                 break;
10965         case NFROMTO:
10966                 fname = redir->nfile.expfname;
10967                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10968                         goto ecreate;
10969                 break;
10970         case NTO:
10971                 /* Take care of noclobber mode. */
10972                 if (Cflag) {
10973                         fname = redir->nfile.expfname;
10974                         if ((f = noclobberopen(fname)) < 0)
10975                                 goto ecreate;
10976                         break;
10977                 }
10978                 /* FALLTHROUGH */
10979         case NCLOBBER:
10980                 fname = redir->nfile.expfname;
10981                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10982                         goto ecreate;
10983                 break;
10984         case NAPPEND:
10985                 fname = redir->nfile.expfname;
10986                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10987                         goto ecreate;
10988                 break;
10989         default:
10990 #ifdef DEBUG
10991                 abort();
10992 #endif
10993                 /* Fall through to eliminate warning. */
10994         case NTOFD:
10995         case NFROMFD:
10996                 f = -1;
10997                 break;
10998         case NHERE:
10999         case NXHERE:
11000                 f = openhere(redir);
11001                 break;
11002         }
11003
11004         return f;
11005 ecreate:
11006         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11007 eopen:
11008         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11009 }
11010
11011 static inline void
11012 dupredirect(union node *redir, int f)
11013 {
11014         int fd = redir->nfile.fd;
11015
11016         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11017                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11018                                 copyfd(redir->ndup.dupfd, fd);
11019                 }
11020                 return;
11021         }
11022
11023         if (f != fd) {
11024                 copyfd(f, fd);
11025                 close(f);
11026         }
11027         return;
11028 }
11029
11030 /*
11031  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
11032  * old file descriptors are stashed away so that the redirection can be
11033  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
11034  * standard output, and the standard error if it becomes a duplicate of
11035  * stdout, is saved in memory.
11036  */
11037
11038 static void
11039 redirect(union node *redir, int flags)
11040 {
11041         union node *n;
11042         struct redirtab *sv;
11043         int i;
11044         int fd;
11045         int newfd;
11046         int *p;
11047         nullredirs++;
11048         if (!redir) {
11049                 return;
11050         }
11051         sv = NULL;
11052         INTOFF;
11053         if (flags & REDIR_PUSH) {
11054                 struct redirtab *q;
11055                 q = ckmalloc(sizeof (struct redirtab));
11056                 q->next = redirlist;
11057                 redirlist = q;
11058                 q->nullredirs = nullredirs - 1;
11059                 for (i = 0 ; i < 10 ; i++)
11060                         q->renamed[i] = EMPTY;
11061                 nullredirs = 0;
11062                 sv = q;
11063         }
11064         n = redir;
11065         do {
11066                 fd = n->nfile.fd;
11067                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11068                     n->ndup.dupfd == fd)
11069                         continue; /* redirect from/to same file descriptor */
11070
11071                 newfd = openredirect(n);
11072                 if (fd == newfd)
11073                         continue;
11074                 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11075                         i = fcntl(fd, F_DUPFD, 10);
11076
11077                         if (i == -1) {
11078                                 i = errno;
11079                                 if (i != EBADF) {
11080                                         close(newfd);
11081                                         errno = i;
11082                                         error("%d: %m", fd);
11083                                         /* NOTREACHED */
11084                                 }
11085                         } else {
11086                                 *p = i;
11087                                 close(fd);
11088                         }
11089                 } else {
11090                         close(fd);
11091                 }
11092                 dupredirect(n, newfd);
11093         } while ((n = n->nfile.next));
11094         INTON;
11095         if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11096                 preverrout_fd = sv->renamed[2];
11097 }
11098
11099
11100 /*
11101  * Undo the effects of the last redirection.
11102  */
11103
11104 void
11105 popredir(int drop)
11106 {
11107         struct redirtab *rp;
11108         int i;
11109
11110         if (--nullredirs >= 0)
11111                 return;
11112         INTOFF;
11113         rp = redirlist;
11114         for (i = 0 ; i < 10 ; i++) {
11115                 if (rp->renamed[i] != EMPTY) {
11116                         if (!drop) {
11117                                 close(i);
11118                                 copyfd(rp->renamed[i], i);
11119                         }
11120                         close(rp->renamed[i]);
11121                 }
11122         }
11123         redirlist = rp->next;
11124         nullredirs = rp->nullredirs;
11125         ckfree(rp);
11126         INTON;
11127 }
11128
11129 /*
11130  * Undo all redirections.  Called on error or interrupt.
11131  */
11132
11133 /*
11134  * Discard all saved file descriptors.
11135  */
11136
11137 void
11138 clearredir(int drop)
11139 {
11140         for (;;) {
11141                 nullredirs = 0;
11142                 if (!redirlist)
11143                         break;
11144                 popredir(drop);
11145         }
11146 }
11147
11148
11149 /*
11150  * Copy a file descriptor to be >= to.  Returns -1
11151  * if the source file descriptor is closed, EMPTY if there are no unused
11152  * file descriptors left.
11153  */
11154
11155 int
11156 copyfd(int from, int to)
11157 {
11158         int newfd;
11159
11160         newfd = fcntl(from, F_DUPFD, to);
11161         if (newfd < 0) {
11162                 if (errno == EMFILE)
11163                         return EMPTY;
11164                 else
11165                         error("%d: %m", from);
11166         }
11167         return newfd;
11168 }
11169
11170
11171 int
11172 redirectsafe(union node *redir, int flags)
11173 {
11174         int err;
11175         volatile int saveint;
11176         struct jmploc *volatile savehandler = handler;
11177         struct jmploc jmploc;
11178
11179         SAVEINT(saveint);
11180         if (!(err = setjmp(jmploc.loc) * 2)) {
11181                 handler = &jmploc;
11182                 redirect(redir, flags);
11183         }
11184         handler = savehandler;
11185         if (err && exception != EXERROR)
11186                 longjmp(handler->loc, 1);
11187         RESTOREINT(saveint);
11188         return err;
11189 }
11190
11191 /*      $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $    */
11192
11193 #ifdef DEBUG
11194 static void shtree(union node *, int, char *, FILE*);
11195 static void shcmd(union node *, FILE *);
11196 static void sharg(union node *, FILE *);
11197 static void indent(int, char *, FILE *);
11198 static void trstring(char *);
11199
11200
11201 void
11202 showtree(union node *n)
11203 {
11204         trputs("showtree called\n");
11205         shtree(n, 1, NULL, stdout);
11206 }
11207
11208
11209 static void
11210 shtree(union node *n, int ind, char *pfx, FILE *fp)
11211 {
11212         struct nodelist *lp;
11213         const char *s;
11214
11215         if (n == NULL)
11216                 return;
11217
11218         indent(ind, pfx, fp);
11219         switch(n->type) {
11220         case NSEMI:
11221                 s = "; ";
11222                 goto binop;
11223         case NAND:
11224                 s = " && ";
11225                 goto binop;
11226         case NOR:
11227                 s = " || ";
11228 binop:
11229                 shtree(n->nbinary.ch1, ind, NULL, fp);
11230            /*    if (ind < 0) */
11231                         fputs(s, fp);
11232                 shtree(n->nbinary.ch2, ind, NULL, fp);
11233                 break;
11234         case NCMD:
11235                 shcmd(n, fp);
11236                 if (ind >= 0)
11237                         putc('\n', fp);
11238                 break;
11239         case NPIPE:
11240                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11241                         shcmd(lp->n, fp);
11242                         if (lp->next)
11243                                 fputs(" | ", fp);
11244                 }
11245                 if (n->npipe.backgnd)
11246                         fputs(" &", fp);
11247                 if (ind >= 0)
11248                         putc('\n', fp);
11249                 break;
11250         default:
11251                 fprintf(fp, "<node type %d>", n->type);
11252                 if (ind >= 0)
11253                         putc('\n', fp);
11254                 break;
11255         }
11256 }
11257
11258
11259 static void
11260 shcmd(union node *cmd, FILE *fp)
11261 {
11262         union node *np;
11263         int first;
11264         const char *s;
11265         int dftfd;
11266
11267         first = 1;
11268         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11269                 if (! first)
11270                         putchar(' ');
11271                 sharg(np, fp);
11272                 first = 0;
11273         }
11274         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11275                 if (! first)
11276                         putchar(' ');
11277                 switch (np->nfile.type) {
11278                         case NTO:       s = ">";  dftfd = 1; break;
11279                         case NCLOBBER:  s = ">|"; dftfd = 1; break;
11280                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11281                         case NTOFD:     s = ">&"; dftfd = 1; break;
11282                         case NFROM:     s = "<";  dftfd = 0; break;
11283                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11284                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11285                         default:        s = "*error*"; dftfd = 0; break;
11286                 }
11287                 if (np->nfile.fd != dftfd)
11288                         fprintf(fp, "%d", np->nfile.fd);
11289                 fputs(s, fp);
11290                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11291                         fprintf(fp, "%d", np->ndup.dupfd);
11292                 } else {
11293                         sharg(np->nfile.fname, fp);
11294                 }
11295                 first = 0;
11296         }
11297 }
11298
11299
11300
11301 static void
11302 sharg(union node *arg, FILE *fp)
11303 {
11304         char *p;
11305         struct nodelist *bqlist;
11306         int subtype;
11307
11308         if (arg->type != NARG) {
11309                 out1fmt("<node type %d>\n", arg->type);
11310                 abort();
11311         }
11312         bqlist = arg->narg.backquote;
11313         for (p = arg->narg.text ; *p ; p++) {
11314                 switch (*p) {
11315                 case CTLESC:
11316                         putc(*++p, fp);
11317                         break;
11318                 case CTLVAR:
11319                         putc('$', fp);
11320                         putc('{', fp);
11321                         subtype = *++p;
11322                         if (subtype == VSLENGTH)
11323                                 putc('#', fp);
11324
11325                         while (*p != '=')
11326                                 putc(*p++, fp);
11327
11328                         if (subtype & VSNUL)
11329                                 putc(':', fp);
11330
11331                         switch (subtype & VSTYPE) {
11332                         case VSNORMAL:
11333                                 putc('}', fp);
11334                                 break;
11335                         case VSMINUS:
11336                                 putc('-', fp);
11337                                 break;
11338                         case VSPLUS:
11339                                 putc('+', fp);
11340                                 break;
11341                         case VSQUESTION:
11342                                 putc('?', fp);
11343                                 break;
11344                         case VSASSIGN:
11345                                 putc('=', fp);
11346                                 break;
11347                         case VSTRIMLEFT:
11348                                 putc('#', fp);
11349                                 break;
11350                         case VSTRIMLEFTMAX:
11351                                 putc('#', fp);
11352                                 putc('#', fp);
11353                                 break;
11354                         case VSTRIMRIGHT:
11355                                 putc('%', fp);
11356                                 break;
11357                         case VSTRIMRIGHTMAX:
11358                                 putc('%', fp);
11359                                 putc('%', fp);
11360                                 break;
11361                         case VSLENGTH:
11362                                 break;
11363                         default:
11364                                 out1fmt("<subtype %d>", subtype);
11365                         }
11366                         break;
11367                 case CTLENDVAR:
11368                      putc('}', fp);
11369                      break;
11370                 case CTLBACKQ:
11371                 case CTLBACKQ|CTLQUOTE:
11372                         putc('$', fp);
11373                         putc('(', fp);
11374                         shtree(bqlist->n, -1, NULL, fp);
11375                         putc(')', fp);
11376                         break;
11377                 default:
11378                         putc(*p, fp);
11379                         break;
11380                 }
11381         }
11382 }
11383
11384
11385 static void
11386 indent(int amount, char *pfx, FILE *fp)
11387 {
11388         int i;
11389
11390         for (i = 0 ; i < amount ; i++) {
11391                 if (pfx && i == amount - 1)
11392                         fputs(pfx, fp);
11393                 putc('\t', fp);
11394         }
11395 }
11396
11397
11398
11399 /*
11400  * Debugging stuff.
11401  */
11402
11403
11404 FILE *tracefile;
11405
11406
11407 void
11408 trputc(int c)
11409 {
11410         if (debug != 1)
11411                 return;
11412         putc(c, tracefile);
11413 }
11414
11415 void
11416 trace(const char *fmt, ...)
11417 {
11418         va_list va;
11419
11420         if (debug != 1)
11421                 return;
11422         va_start(va, fmt);
11423         (void) vfprintf(tracefile, fmt, va);
11424         va_end(va);
11425 }
11426
11427 void
11428 tracev(const char *fmt, va_list va)
11429 {
11430         if (debug != 1)
11431                 return;
11432         (void) vfprintf(tracefile, fmt, va);
11433 }
11434
11435
11436 void
11437 trputs(const char *s)
11438 {
11439         if (debug != 1)
11440                 return;
11441         fputs(s, tracefile);
11442 }
11443
11444
11445 static void
11446 trstring(char *s)
11447 {
11448         char *p;
11449         char c;
11450
11451         if (debug != 1)
11452                 return;
11453         putc('"', tracefile);
11454         for (p = s ; *p ; p++) {
11455                 switch (*p) {
11456                 case '\n':  c = 'n';  goto backslash;
11457                 case '\t':  c = 't';  goto backslash;
11458                 case '\r':  c = 'r';  goto backslash;
11459                 case '"':  c = '"';  goto backslash;
11460                 case '\\':  c = '\\';  goto backslash;
11461                 case CTLESC:  c = 'e';  goto backslash;
11462                 case CTLVAR:  c = 'v';  goto backslash;
11463                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11464                 case CTLBACKQ:  c = 'q';  goto backslash;
11465                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11466 backslash:        putc('\\', tracefile);
11467                         putc(c, tracefile);
11468                         break;
11469                 default:
11470                         if (*p >= ' ' && *p <= '~')
11471                                 putc(*p, tracefile);
11472                         else {
11473                                 putc('\\', tracefile);
11474                                 putc(*p >> 6 & 03, tracefile);
11475                                 putc(*p >> 3 & 07, tracefile);
11476                                 putc(*p & 07, tracefile);
11477                         }
11478                         break;
11479                 }
11480         }
11481         putc('"', tracefile);
11482 }
11483
11484
11485 void
11486 trargs(char **ap)
11487 {
11488         if (debug != 1)
11489                 return;
11490         while (*ap) {
11491                 trstring(*ap++);
11492                 if (*ap)
11493                         putc(' ', tracefile);
11494                 else
11495                         putc('\n', tracefile);
11496         }
11497 }
11498
11499
11500 void
11501 opentrace(void)
11502 {
11503         char s[100];
11504 #ifdef O_APPEND
11505         int flags;
11506 #endif
11507
11508         if (debug != 1) {
11509                 if (tracefile)
11510                         fflush(tracefile);
11511                 /* leave open because libedit might be using it */
11512                 return;
11513         }
11514         scopy("./trace", s);
11515         if (tracefile) {
11516                 if (!freopen(s, "a", tracefile)) {
11517                         fprintf(stderr, "Can't re-open %s\n", s);
11518                         debug = 0;
11519                         return;
11520                 }
11521         } else {
11522                 if ((tracefile = fopen(s, "a")) == NULL) {
11523                         fprintf(stderr, "Can't open %s\n", s);
11524                         debug = 0;
11525                         return;
11526                 }
11527         }
11528 #ifdef O_APPEND
11529         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11530                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11531 #endif
11532         setlinebuf(tracefile);
11533         fputs("\nTracing started.\n", tracefile);
11534 }
11535 #endif /* DEBUG */
11536
11537
11538 /*      $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $       */
11539
11540 /*
11541  * Sigmode records the current value of the signal handlers for the various
11542  * modes.  A value of zero means that the current handler is not known.
11543  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11544  */
11545
11546 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
11547 #define S_CATCH 2               /* signal is caught */
11548 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
11549 #define S_HARD_IGN 4            /* signal is ignored permenantly */
11550 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
11551
11552
11553
11554 /*
11555  * The trap builtin.
11556  */
11557
11558 int
11559 trapcmd(int argc, char **argv)
11560 {
11561         char *action;
11562         char **ap;
11563         int signo;
11564
11565         nextopt(nullstr);
11566         ap = argptr;
11567         if (!*ap) {
11568                 for (signo = 0 ; signo < NSIG ; signo++) {
11569                         if (trap[signo] != NULL) {
11570                                 const char *sn;
11571
11572                                 sn = u_signal_names(0, &signo, 0);
11573                                 if (sn == NULL)
11574                                         sn = "???";
11575                                 out1fmt("trap -- %s %s\n",
11576                                         single_quote(trap[signo]), sn);
11577                         }
11578                 }
11579                 return 0;
11580         }
11581         if (!ap[1])
11582                 action = NULL;
11583         else
11584                 action = *ap++;
11585         while (*ap) {
11586                 if ((signo = decode_signal(*ap, 0)) < 0)
11587                         error("%s: bad trap", *ap);
11588                 INTOFF;
11589                 if (action) {
11590                         if (action[0] == '-' && action[1] == '\0')
11591                                 action = NULL;
11592                         else
11593                                 action = savestr(action);
11594                 }
11595                 if (trap[signo])
11596                         ckfree(trap[signo]);
11597                 trap[signo] = action;
11598                 if (signo != 0)
11599                         setsignal(signo);
11600                 INTON;
11601                 ap++;
11602         }
11603         return 0;
11604 }
11605
11606
11607 /*
11608  * Clear traps on a fork.
11609  */
11610
11611 void
11612 clear_traps(void)
11613 {
11614         char **tp;
11615
11616         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11617                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
11618                         INTOFF;
11619                         ckfree(*tp);
11620                         *tp = NULL;
11621                         if (tp != &trap[0])
11622                                 setsignal(tp - trap);
11623                         INTON;
11624                 }
11625         }
11626 }
11627
11628
11629 /*
11630  * Set the signal handler for the specified signal.  The routine figures
11631  * out what it should be set to.
11632  */
11633
11634 void
11635 setsignal(int signo)
11636 {
11637         int action;
11638         char *t, tsig;
11639         struct sigaction act;
11640
11641         if ((t = trap[signo]) == NULL)
11642                 action = S_DFL;
11643         else if (*t != '\0')
11644                 action = S_CATCH;
11645         else
11646                 action = S_IGN;
11647         if (rootshell && action == S_DFL) {
11648                 switch (signo) {
11649                 case SIGINT:
11650                         if (iflag || minusc || sflag == 0)
11651                                 action = S_CATCH;
11652                         break;
11653                 case SIGQUIT:
11654 #ifdef DEBUG
11655                         if (debug)
11656                                 break;
11657 #endif
11658                         /* FALLTHROUGH */
11659                 case SIGTERM:
11660                         if (iflag)
11661                                 action = S_IGN;
11662                         break;
11663 #if JOBS
11664                 case SIGTSTP:
11665                 case SIGTTOU:
11666                         if (mflag)
11667                                 action = S_IGN;
11668                         break;
11669 #endif
11670                 }
11671         }
11672
11673         t = &sigmode[signo - 1];
11674         tsig = *t;
11675         if (tsig == 0) {
11676                 /*
11677                  * current setting unknown
11678                  */
11679                 if (sigaction(signo, 0, &act) == -1) {
11680                         /*
11681                          * Pretend it worked; maybe we should give a warning
11682                          * here, but other shells don't. We don't alter
11683                          * sigmode, so that we retry every time.
11684                          */
11685                         return;
11686                 }
11687                 if (act.sa_handler == SIG_IGN) {
11688                         if (mflag && (signo == SIGTSTP ||
11689                              signo == SIGTTIN || signo == SIGTTOU)) {
11690                                 tsig = S_IGN;   /* don't hard ignore these */
11691                         } else
11692                                 tsig = S_HARD_IGN;
11693                 } else {
11694                         tsig = S_RESET; /* force to be set */
11695                 }
11696         }
11697         if (tsig == S_HARD_IGN || tsig == action)
11698                 return;
11699         switch (action) {
11700         case S_CATCH:
11701                 act.sa_handler = onsig;
11702                 break;
11703         case S_IGN:
11704                 act.sa_handler = SIG_IGN;
11705                 break;
11706         default:
11707                 act.sa_handler = SIG_DFL;
11708         }
11709         *t = action;
11710         act.sa_flags = 0;
11711         sigfillset(&act.sa_mask);
11712         sigaction(signo, &act, 0);
11713 }
11714
11715 /*
11716  * Ignore a signal.
11717  */
11718
11719 void
11720 ignoresig(int signo)
11721 {
11722         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11723                 signal(signo, SIG_IGN);
11724         }
11725         sigmode[signo - 1] = S_HARD_IGN;
11726 }
11727
11728
11729 /*
11730  * Signal handler.
11731  */
11732
11733 void
11734 onsig(int signo)
11735 {
11736         gotsig[signo - 1] = 1;
11737         pendingsigs = signo;
11738
11739         if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11740                 if (!suppressint)
11741                         onint();
11742                 intpending = 1;
11743         }
11744 }
11745
11746
11747 /*
11748  * Called to execute a trap.  Perhaps we should avoid entering new trap
11749  * handlers while we are executing a trap handler.
11750  */
11751
11752 void
11753 dotrap(void)
11754 {
11755         char *p;
11756         char *q;
11757         int savestatus;
11758
11759         savestatus = exitstatus;
11760         q = gotsig;
11761         while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11762                 *p = 0;
11763                 p = trap[p - q + 1];
11764                 if (!p)
11765                         continue;
11766                 evalstring(p);
11767                 exitstatus = savestatus;
11768         }
11769 }
11770
11771
11772 /*
11773  * Controls whether the shell is interactive or not.
11774  */
11775
11776 void
11777 setinteractive(int on)
11778 {
11779         static int is_interactive;
11780
11781         if (++on == is_interactive)
11782                 return;
11783         is_interactive = on;
11784         setsignal(SIGINT);
11785         setsignal(SIGQUIT);
11786         setsignal(SIGTERM);
11787 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11788                 if(is_interactive > 1) {
11789                         /* Looks like they want an interactive shell */
11790                         static int do_banner;
11791
11792                                 if(!do_banner) {
11793                                         out1fmt(
11794                         "\n\n" BB_BANNER " Built-in shell (ash)\n"
11795                         "Enter 'help' for a list of built-in commands.\n\n");
11796                                         do_banner++;
11797                                 }
11798                 }
11799 #endif
11800 }
11801
11802
11803 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11804 /*** List the available builtins ***/
11805
11806 static int helpcmd(int argc, char **argv)
11807 {
11808         int col, i;
11809
11810         out1fmt("\nBuilt-in commands:\n-------------------\n");
11811         for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11812                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11813                                           builtincmd[i].name + 1);
11814                 if (col > 60) {
11815                         out1fmt("\n");
11816                         col = 0;
11817                 }
11818         }
11819 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11820         {
11821                 extern const struct BB_applet applets[];
11822                 extern const size_t NUM_APPLETS;
11823
11824                 for (i = 0; i < NUM_APPLETS; i++) {
11825
11826                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11827                         if (col > 60) {
11828                                 out1fmt("\n");
11829                                 col = 0;
11830                         }
11831                 }
11832         }
11833 #endif
11834         out1fmt("\n\n");
11835         return EXIT_SUCCESS;
11836 }
11837 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11838
11839 /*
11840  * Called to exit the shell.
11841  */
11842
11843 void
11844 exitshell(void)
11845 {
11846         struct jmploc loc;
11847         char *p;
11848         int status;
11849         int jmp;
11850
11851         jmp = setjmp(loc.loc);
11852         status = exitstatus;
11853         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11854         if (jmp)
11855                 goto out;
11856         handler = &loc;
11857         if ((p = trap[0]) != NULL && *p != '\0') {
11858                 trap[0] = NULL;
11859                 evalstring(p);
11860         }
11861         flushall();
11862 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11863         if (iflag && rootshell) {
11864                 const char *hp = lookupvar("HISTFILE");
11865
11866                 if(hp != NULL )
11867                         save_history ( hp );
11868         }
11869 #endif
11870 out:
11871         _exit(status);
11872         /* NOTREACHED */
11873 }
11874
11875 static int decode_signal(const char *string, int minsig)
11876 {
11877         int signo;
11878         const char *name = u_signal_names(string, &signo, minsig);
11879
11880         return name ? signo : -1;
11881 }
11882
11883 /*      $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $     */
11884
11885 static struct var *vartab[VTABSIZE];
11886
11887 static int vpcmp(const void *, const void *);
11888 static struct var **findvar(struct var **, const char *);
11889
11890 /*
11891  * Initialize the varable symbol tables and import the environment
11892  */
11893
11894
11895 #ifdef CONFIG_ASH_GETOPTS
11896 /*
11897  * Safe version of setvar, returns 1 on success 0 on failure.
11898  */
11899
11900 int
11901 setvarsafe(const char *name, const char *val, int flags)
11902 {
11903         int err;
11904         volatile int saveint;
11905         struct jmploc *volatile savehandler = handler;
11906         struct jmploc jmploc;
11907
11908         SAVEINT(saveint);
11909         if (setjmp(jmploc.loc))
11910                 err = 1;
11911         else {
11912                 handler = &jmploc;
11913                 setvar(name, val, flags);
11914                 err = 0;
11915         }
11916         handler = savehandler;
11917         RESTOREINT(saveint);
11918         return err;
11919 }
11920 #endif
11921
11922 /*
11923  * Set the value of a variable.  The flags argument is ored with the
11924  * flags of the variable.  If val is NULL, the variable is unset.
11925  */
11926
11927 static void
11928 setvar(const char *name, const char *val, int flags)
11929 {
11930         char *p, *q;
11931         size_t namelen;
11932         char *nameeq;
11933         size_t vallen;
11934
11935         q = endofname(name);
11936         p = strchrnul(q, '=');
11937         namelen = p - name;
11938         if (!namelen || p != q)
11939                 error("%.*s: bad variable name", namelen, name);
11940         vallen = 0;
11941         if (val == NULL) {
11942                 flags |= VUNSET;
11943         } else {
11944                 vallen = strlen(val);
11945         }
11946         INTOFF;
11947         p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11948         *p++ = '\0';
11949         if (vallen) {
11950                 p[-1] = '=';
11951                 p = mempcpy(p, val, vallen);
11952         }
11953         *p = '\0';
11954         setvareq(nameeq, flags | VNOSAVE);
11955         INTON;
11956 }
11957
11958
11959 /*
11960  * Same as setvar except that the variable and value are passed in
11961  * the first argument as name=value.  Since the first argument will
11962  * be actually stored in the table, it should not be a string that
11963  * will go away.
11964  * Called with interrupts off.
11965  */
11966
11967 void
11968 setvareq(char *s, int flags)
11969 {
11970         struct var *vp, **vpp;
11971
11972         vpp = hashvar(s);
11973         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11974         vp = *findvar(vpp, s);
11975         if (vp) {
11976                 if (vp->flags & VREADONLY) {
11977                         if (flags & VNOSAVE)
11978                                 free(s);
11979                         error("%.*s: is read only", strchrnul(s, '=') - s, s);
11980                 }
11981
11982                 if (flags & VNOSET)
11983                         return;
11984
11985                 if (vp->func && (flags & VNOFUNC) == 0)
11986                         (*vp->func)(strchrnul(s, '=') + 1);
11987
11988                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11989                         ckfree(vp->text);
11990
11991                 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11992         } else {
11993                 if (flags & VNOSET)
11994                         return;
11995                 /* not found */
11996                 vp = ckmalloc(sizeof (*vp));
11997                 vp->next = *vpp;
11998                 vp->func = NULL;
11999                 *vpp = vp;
12000         }
12001         if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12002                 s = savestr(s);
12003         vp->text = s;
12004         vp->flags = flags;
12005 }
12006
12007
12008 /*
12009  * Process a linked list of variable assignments.
12010  */
12011
12012 static void
12013 listsetvar(struct strlist *list_set_var, int flags)
12014 {
12015         struct strlist *lp = list_set_var;
12016
12017         if (!lp)
12018                 return;
12019         INTOFF;
12020         do {
12021                 setvareq(lp->text, flags);
12022         } while ((lp = lp->next));
12023         INTON;
12024 }
12025
12026
12027 /*
12028  * Find the value of a variable.  Returns NULL if not set.
12029  */
12030
12031 static char *
12032 lookupvar(const char *name)
12033 {
12034         struct var *v;
12035
12036         if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12037                 return strchrnul(v->text, '=') + 1;
12038         }
12039         return NULL;
12040 }
12041
12042
12043 /*
12044  * Search the environment of a builtin command.
12045  */
12046
12047 static char *
12048 bltinlookup(const char *name)
12049 {
12050         struct strlist *sp;
12051
12052         for (sp = cmdenviron ; sp ; sp = sp->next) {
12053                 if (varequal(sp->text, name))
12054                         return strchrnul(sp->text, '=') + 1;
12055         }
12056         return lookupvar(name);
12057 }
12058
12059
12060 /*
12061  * Generate a list of variables satisfying the given conditions.
12062  */
12063
12064 static char **
12065 listvars(int on, int off, char ***end)
12066 {
12067         struct var **vpp;
12068         struct var *vp;
12069         char **ep;
12070         int mask;
12071
12072         STARTSTACKSTR(ep);
12073         vpp = vartab;
12074         mask = on | off;
12075         do {
12076                 for (vp = *vpp ; vp ; vp = vp->next)
12077                         if ((vp->flags & mask) == on) {
12078                                 if (ep == stackstrend())
12079                                         ep = growstackstr();
12080                                 *ep++ = (char *) vp->text;
12081                         }
12082         } while (++vpp < vartab + VTABSIZE);
12083         if (ep == stackstrend())
12084                 ep = growstackstr();
12085         if (end)
12086                 *end = ep;
12087         *ep++ = NULL;
12088         return grabstackstr(ep);
12089 }
12090
12091
12092 /*
12093  * POSIX requires that 'set' (but not export or readonly) output the
12094  * variables in lexicographic order - by the locale's collating order (sigh).
12095  * Maybe we could keep them in an ordered balanced binary tree
12096  * instead of hashed lists.
12097  * For now just roll 'em through qsort for printing...
12098  */
12099
12100 static int
12101 showvars(const char *sep_prefix, int on, int off)
12102 {
12103         const char *sep;
12104         char **ep, **epend;
12105
12106         ep = listvars(on, off, &epend);
12107         qsort(ep, epend - ep, sizeof(char *), vpcmp);
12108
12109         sep = *sep_prefix ? spcstr : sep_prefix;
12110
12111         for (; ep < epend; ep++) {
12112                 const char *p;
12113                 const char *q;
12114
12115                 p = strchrnul(*ep, '=');
12116                 q = nullstr;
12117                 if (*p)
12118                         q = single_quote(++p);
12119
12120                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12121         }
12122
12123         return 0;
12124 }
12125
12126
12127
12128 /*
12129  * The export and readonly commands.
12130  */
12131
12132 static int
12133 exportcmd(int argc, char **argv)
12134 {
12135         struct var *vp;
12136         char *name;
12137         const char *p;
12138         char **aptr;
12139         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12140         int notp;
12141
12142         notp = nextopt("p") - 'p';
12143         if (notp && ((name = *(aptr = argptr)))) {
12144                 do {
12145                         if ((p = strchr(name, '=')) != NULL) {
12146                                 p++;
12147                         } else {
12148                                 if ((vp = *findvar(hashvar(name), name))) {
12149                                         vp->flags |= flag;
12150                                         continue;
12151                                 }
12152                         }
12153                         setvar(name, p, flag);
12154                 } while ((name = *++aptr) != NULL);
12155         } else {
12156                 showvars(argv[0], flag, 0);
12157         }
12158         return 0;
12159 }
12160
12161
12162 /*
12163  * Make a variable a local variable.  When a variable is made local, it's
12164  * value and flags are saved in a localvar structure.  The saved values
12165  * will be restored when the shell function returns.  We handle the name
12166  * "-" as a special case.
12167  */
12168
12169 static inline void
12170 mklocal(char *name)
12171 {
12172         struct localvar *lvp;
12173         struct var **vpp;
12174         struct var *vp;
12175
12176         INTOFF;
12177         lvp = ckmalloc(sizeof (struct localvar));
12178         if (name[0] == '-' && name[1] == '\0') {
12179                 char *p;
12180                 p = ckmalloc(sizeof(optlist));
12181                 lvp->text = memcpy(p, optlist, sizeof(optlist));
12182                 vp = NULL;
12183         } else {
12184                 char *eq;
12185
12186                 vpp = hashvar(name);
12187                 vp = *findvar(vpp, name);
12188                 eq = strchr(name, '=');
12189                 if (vp == NULL) {
12190                         if (eq)
12191                                 setvareq(name, VSTRFIXED);
12192                         else
12193                                 setvar(name, NULL, VSTRFIXED);
12194                         vp = *vpp;      /* the new variable */
12195                         lvp->flags = VUNSET;
12196                 } else {
12197                         lvp->text = vp->text;
12198                         lvp->flags = vp->flags;
12199                         vp->flags |= VSTRFIXED|VTEXTFIXED;
12200                         if (eq)
12201                                 setvareq(name, 0);
12202                 }
12203         }
12204         lvp->vp = vp;
12205         lvp->next = localvars;
12206         localvars = lvp;
12207         INTON;
12208 }
12209
12210 /*
12211  * The "local" command.
12212  */
12213
12214 static int
12215 localcmd(int argc, char **argv)
12216 {
12217         char *name;
12218
12219         argv = argptr;
12220         while ((name = *argv++) != NULL) {
12221                 mklocal(name);
12222         }
12223         return 0;
12224 }
12225
12226
12227 /*
12228  * Called after a function returns.
12229  * Interrupts must be off.
12230  */
12231
12232 static void
12233 poplocalvars(void)
12234 {
12235         struct localvar *lvp;
12236         struct var *vp;
12237
12238         while ((lvp = localvars) != NULL) {
12239                 localvars = lvp->next;
12240                 vp = lvp->vp;
12241                 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12242                 if (vp == NULL) {       /* $- saved */
12243                         memcpy(optlist, lvp->text, sizeof(optlist));
12244                         ckfree(lvp->text);
12245                         optschanged();
12246                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12247                         unsetvar(vp->text);
12248                 } else {
12249                         if (vp->func)
12250                                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12251                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12252                                 ckfree(vp->text);
12253                         vp->flags = lvp->flags;
12254                         vp->text = lvp->text;
12255                 }
12256                 ckfree(lvp);
12257         }
12258 }
12259
12260
12261 /*
12262  * The unset builtin command.  We unset the function before we unset the
12263  * variable to allow a function to be unset when there is a readonly variable
12264  * with the same name.
12265  */
12266
12267 int
12268 unsetcmd(int argc, char **argv)
12269 {
12270         char **ap;
12271         int i;
12272         int flag = 0;
12273         int ret = 0;
12274
12275         while ((i = nextopt("vf")) != '\0') {
12276                 flag = i;
12277         }
12278
12279         for (ap = argptr; *ap ; ap++) {
12280                 if (flag != 'f') {
12281                         i = unsetvar(*ap);
12282                         ret |= i;
12283                         if (!(i & 2))
12284                                 continue;
12285                 }
12286                 if (flag != 'v')
12287                         unsetfunc(*ap);
12288         }
12289         return ret & 1;
12290 }
12291
12292
12293 /*
12294  * Unset the specified variable.
12295  */
12296
12297 int
12298 unsetvar(const char *s)
12299 {
12300         struct var **vpp;
12301         struct var *vp;
12302         int retval;
12303
12304         vpp = findvar(hashvar(s), s);
12305         vp = *vpp;
12306         retval = 2;
12307         if (vp) {
12308                 int flags = vp->flags;
12309
12310                 retval = 1;
12311                 if (flags & VREADONLY)
12312                         goto out;
12313                 if (flags & VUNSET)
12314                         goto ok;
12315                 if ((flags & VSTRFIXED) == 0) {
12316                         INTOFF;
12317                         if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12318                                 ckfree(vp->text);
12319                         *vpp = vp->next;
12320                         ckfree(vp);
12321                         INTON;
12322                 } else {
12323                         setvar(s, 0, 0);
12324                         vp->flags &= ~VEXPORT;
12325                 }
12326 ok:
12327                 retval = 0;
12328         }
12329
12330 out:
12331         return retval;
12332 }
12333
12334
12335
12336 /*
12337  * Find the appropriate entry in the hash table from the name.
12338  */
12339
12340 static struct var **
12341 hashvar(const char *p)
12342 {
12343         unsigned int hashval;
12344
12345         hashval = ((unsigned char) *p) << 4;
12346         while (*p && *p != '=')
12347                 hashval += (unsigned char) *p++;
12348         return &vartab[hashval % VTABSIZE];
12349 }
12350
12351
12352
12353 /*
12354  * Compares two strings up to the first = or '\0'.  The first
12355  * string must be terminated by '='; the second may be terminated by
12356  * either '=' or '\0'.
12357  */
12358
12359 int
12360 varcmp(const char *p, const char *q)
12361 {
12362         int c, d;
12363
12364         while ((c = *p) == (d = *q)) {
12365                 if (!c || c == '=')
12366                         goto out;
12367                 p++;
12368                 q++;
12369         }
12370         if (c == '=')
12371                 c = 0;
12372         if (d == '=')
12373                 d = 0;
12374 out:
12375         return c - d;
12376 }
12377
12378 static int
12379 vpcmp(const void *a, const void *b)
12380 {
12381         return varcmp(*(const char **)a, *(const char **)b);
12382 }
12383
12384 static struct var **
12385 findvar(struct var **vpp, const char *name)
12386 {
12387         for (; *vpp; vpp = &(*vpp)->next) {
12388                 if (varequal((*vpp)->text, name)) {
12389                         break;
12390                 }
12391         }
12392         return vpp;
12393 }
12394 /*      $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $      */
12395
12396 #include <sys/times.h>
12397
12398 static const unsigned char timescmd_str[] = {
12399         ' ',  offsetof(struct tms, tms_utime),
12400         '\n', offsetof(struct tms, tms_stime),
12401         ' ',  offsetof(struct tms, tms_cutime),
12402         '\n', offsetof(struct tms, tms_cstime),
12403         0
12404 };
12405
12406 static int timescmd(int ac, char **av)
12407 {
12408         long int clk_tck, s, t;
12409         const unsigned char *p;
12410         struct tms buf;
12411
12412         clk_tck = sysconf(_SC_CLK_TCK);
12413         times(&buf);
12414
12415         p = timescmd_str;
12416         do {
12417                 t = *(clock_t *)(((char *) &buf) + p[1]);
12418                 s = t / clk_tck;
12419                 out1fmt("%ldm%ld.%.3lds%c",
12420                         s/60, s%60,
12421                         ((t - s * clk_tck) * 1000) / clk_tck,
12422                         p[0]);
12423         } while (*(p += 2));
12424
12425         return 0;
12426 }
12427
12428 #ifdef CONFIG_ASH_MATH_SUPPORT
12429 static int
12430 dash_arith(const char *s)
12431 {
12432         long result;
12433         int errcode = 0;
12434
12435         INTOFF;
12436         result = arith(s, &errcode);
12437         if (errcode < 0) {
12438                 if (errcode == -3)
12439                         error("exponent less than 0");
12440                 else if (errcode == -2)
12441                         error("divide by zero");
12442                 else if (errcode == -5)
12443                         error("expression recursion loop detected");
12444                 else
12445                         synerror(s);
12446         }
12447         INTON;
12448
12449         return (result);
12450 }
12451
12452
12453 /*
12454  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12455  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12456  *
12457  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12458  */
12459
12460 static int
12461 letcmd(int argc, char **argv)
12462 {
12463         char **ap;
12464         long i;
12465
12466         ap = argv + 1;
12467         if(!*ap)
12468                 error("expression expected");
12469         for (ap = argv + 1; *ap; ap++) {
12470                 i = dash_arith(*ap);
12471         }
12472
12473         return (!i);
12474 }
12475 #endif /* CONFIG_ASH_MATH_SUPPORT */
12476
12477 /*      $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $  */
12478
12479 /*
12480  * Miscelaneous builtins.
12481  */
12482
12483 #undef rflag
12484
12485 #ifdef __GLIBC__
12486 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12487 typedef enum __rlimit_resource rlim_t;
12488 #endif
12489 #endif
12490
12491
12492 /*
12493  * The read builtin.  The -e option causes backslashes to escape the
12494  * following character.
12495  *
12496  * This uses unbuffered input, which may be avoidable in some cases.
12497  */
12498
12499 static int
12500 readcmd(int argc, char **argv)
12501 {
12502         char **ap;
12503         int backslash;
12504         char c;
12505         int rflag;
12506         char *prompt;
12507         const char *ifs;
12508         char *p;
12509         int startword;
12510         int status;
12511         int i;
12512
12513         rflag = 0;
12514         prompt = NULL;
12515         while ((i = nextopt("p:r")) != '\0') {
12516                 if (i == 'p')
12517                         prompt = optionarg;
12518                 else
12519                         rflag = 1;
12520         }
12521         if (prompt && isatty(0)) {
12522                 out2str(prompt);
12523         }
12524         if (*(ap = argptr) == NULL)
12525                 error("arg count");
12526         if ((ifs = bltinlookup("IFS")) == NULL)
12527                 ifs = defifs;
12528         status = 0;
12529         startword = 1;
12530         backslash = 0;
12531         STARTSTACKSTR(p);
12532         for (;;) {
12533                 if (read(0, &c, 1) != 1) {
12534                         status = 1;
12535                         break;
12536                 }
12537                 if (c == '\0')
12538                         continue;
12539                 if (backslash) {
12540                         backslash = 0;
12541                         if (c != '\n')
12542                                 goto put;
12543                         continue;
12544                 }
12545                 if (!rflag && c == '\\') {
12546                         backslash++;
12547                         continue;
12548                 }
12549                 if (c == '\n')
12550                         break;
12551                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12552                         continue;
12553                 }
12554                 startword = 0;
12555                 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12556                         STACKSTRNUL(p);
12557                         setvar(*ap, stackblock(), 0);
12558                         ap++;
12559                         startword = 1;
12560                         STARTSTACKSTR(p);
12561                 } else {
12562 put:
12563                         STPUTC(c, p);
12564                 }
12565         }
12566         STACKSTRNUL(p);
12567         /* Remove trailing blanks */
12568         while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12569                 *p = '\0';
12570         setvar(*ap, stackblock(), 0);
12571         while (*++ap != NULL)
12572                 setvar(*ap, nullstr, 0);
12573         return status;
12574 }
12575
12576
12577 static int umaskcmd(int argc, char **argv)
12578 {
12579         static const char permuser[3] = "ugo";
12580         static const char permmode[3] = "rwx";
12581         static const short int permmask[] = {
12582                 S_IRUSR, S_IWUSR, S_IXUSR,
12583                 S_IRGRP, S_IWGRP, S_IXGRP,
12584                 S_IROTH, S_IWOTH, S_IXOTH
12585         };
12586
12587         char *ap;
12588         mode_t mask;
12589         int i;
12590         int symbolic_mode = 0;
12591
12592         while (nextopt("S") != '\0') {
12593                 symbolic_mode = 1;
12594         }
12595
12596         INTOFF;
12597         mask = umask(0);
12598         umask(mask);
12599         INTON;
12600
12601         if ((ap = *argptr) == NULL) {
12602                 if (symbolic_mode) {
12603                         char buf[18];
12604                         char *p = buf;
12605
12606                         for (i = 0; i < 3; i++) {
12607                                 int j;
12608
12609                                 *p++ = permuser[i];
12610                                 *p++ = '=';
12611                                 for (j = 0; j < 3; j++) {
12612                                         if ((mask & permmask[3 * i + j]) == 0) {
12613                                                 *p++ = permmode[j];
12614                                         }
12615                                 }
12616                                 *p++ = ',';
12617                         }
12618                         *--p = 0;
12619                         puts(buf);
12620                 } else {
12621                         out1fmt("%.4o\n", mask);
12622                 }
12623         } else {
12624                 if (is_digit((unsigned char) *ap)) {
12625                         mask = 0;
12626                         do {
12627                                 if (*ap >= '8' || *ap < '0')
12628                                         error(illnum, argv[1]);
12629                                 mask = (mask << 3) + (*ap - '0');
12630                         } while (*++ap != '\0');
12631                         umask(mask);
12632                 } else {
12633                         mask = ~mask & 0777;
12634                         if (!bb_parse_mode(ap, &mask)) {
12635                                 error("Illegal mode: %s", ap);
12636                         }
12637                         umask(~mask & 0777);
12638                 }
12639         }
12640         return 0;
12641 }
12642
12643 /*
12644  * ulimit builtin
12645  *
12646  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12647  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12648  * ash by J.T. Conklin.
12649  *
12650  * Public domain.
12651  */
12652
12653 struct limits {
12654         const char *name;
12655         int     cmd;
12656         int     factor; /* multiply by to get rlim_{cur,max} values */
12657         char    option;
12658 };
12659
12660 static const struct limits limits[] = {
12661 #ifdef RLIMIT_CPU
12662         { "time(seconds)",              RLIMIT_CPU,        1, 't' },
12663 #endif
12664 #ifdef RLIMIT_FSIZE
12665         { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
12666 #endif
12667 #ifdef RLIMIT_DATA
12668         { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
12669 #endif
12670 #ifdef RLIMIT_STACK
12671         { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
12672 #endif
12673 #ifdef  RLIMIT_CORE
12674         { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
12675 #endif
12676 #ifdef RLIMIT_RSS
12677         { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
12678 #endif
12679 #ifdef RLIMIT_MEMLOCK
12680         { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
12681 #endif
12682 #ifdef RLIMIT_NPROC
12683         { "process",                    RLIMIT_NPROC,      1, 'p' },
12684 #endif
12685 #ifdef RLIMIT_NOFILE
12686         { "nofiles",                    RLIMIT_NOFILE,     1, 'n' },
12687 #endif
12688 #ifdef RLIMIT_AS
12689         { "vmemory(kbytes)",            RLIMIT_AS,      1024, 'v' },
12690 #endif
12691 #ifdef RLIMIT_LOCKS
12692         { "locks",                      RLIMIT_LOCKS,      1, 'w' },
12693 #endif
12694         { (char *) 0,                   0,                 0,  '\0' }
12695 };
12696
12697 enum limtype { SOFT = 0x1, HARD = 0x2 };
12698
12699 static void printlim(enum limtype how, const struct rlimit *limit,
12700                         const struct limits *l)
12701 {
12702         rlim_t val;
12703
12704         val = limit->rlim_max;
12705         if (how & SOFT)
12706                 val = limit->rlim_cur;
12707
12708         if (val == RLIM_INFINITY)
12709                 out1fmt("unlimited\n");
12710         else {
12711                 val /= l->factor;
12712                 out1fmt("%lld\n", (long long) val);
12713         }
12714 }
12715
12716 int
12717 ulimitcmd(int argc, char **argv)
12718 {
12719         int     c;
12720         rlim_t val = 0;
12721         enum limtype how = SOFT | HARD;
12722         const struct limits     *l;
12723         int             set, all = 0;
12724         int             optc, what;
12725         struct rlimit   limit;
12726
12727         what = 'f';
12728         while ((optc = nextopt("HSa"
12729 #ifdef RLIMIT_CPU
12730                                 "t"
12731 #endif
12732 #ifdef RLIMIT_FSIZE
12733                                 "f"
12734 #endif
12735 #ifdef RLIMIT_DATA
12736                                 "d"
12737 #endif
12738 #ifdef RLIMIT_STACK
12739                                 "s"
12740 #endif
12741 #ifdef RLIMIT_CORE
12742                                 "c"
12743 #endif
12744 #ifdef RLIMIT_RSS
12745                                 "m"
12746 #endif
12747 #ifdef RLIMIT_MEMLOCK
12748                                 "l"
12749 #endif
12750 #ifdef RLIMIT_NPROC
12751                                 "p"
12752 #endif
12753 #ifdef RLIMIT_NOFILE
12754                                 "n"
12755 #endif
12756 #ifdef RLIMIT_AS
12757                                 "v"
12758 #endif
12759 #ifdef RLIMIT_LOCKS
12760                                 "w"
12761 #endif
12762                                                 )) != '\0')
12763                 switch (optc) {
12764                 case 'H':
12765                         how = HARD;
12766                         break;
12767                 case 'S':
12768                         how = SOFT;
12769                         break;
12770                 case 'a':
12771                         all = 1;
12772                         break;
12773                 default:
12774                         what = optc;
12775                 }
12776
12777         for (l = limits; l->option != what; l++)
12778                 ;
12779
12780         set = *argptr ? 1 : 0;
12781         if (set) {
12782                 char *p = *argptr;
12783
12784                 if (all || argptr[1])
12785                         error("too many arguments");
12786                 if (strncmp(p, "unlimited\n", 9) == 0)
12787                         val = RLIM_INFINITY;
12788                 else {
12789                         val = (rlim_t) 0;
12790
12791                         while ((c = *p++) >= '0' && c <= '9')
12792                         {
12793                                 val = (val * 10) + (long)(c - '0');
12794                                 if (val < (rlim_t) 0)
12795                                         break;
12796                         }
12797                         if (c)
12798                                 error("bad number");
12799                         val *= l->factor;
12800                 }
12801         }
12802         if (all) {
12803                 for (l = limits; l->name; l++) {
12804                         getrlimit(l->cmd, &limit);
12805                         out1fmt("%-20s ", l->name);
12806                         printlim(how, &limit, l);
12807                 }
12808                 return 0;
12809         }
12810
12811         getrlimit(l->cmd, &limit);
12812         if (set) {
12813                 if (how & HARD)
12814                         limit.rlim_max = val;
12815                 if (how & SOFT)
12816                         limit.rlim_cur = val;
12817                 if (setrlimit(l->cmd, &limit) < 0)
12818                         error("error setting limit (%m)");
12819         } else {
12820                 printlim(how, &limit, l);
12821         }
12822         return 0;
12823 }
12824
12825
12826 #ifdef CONFIG_ASH_MATH_SUPPORT
12827
12828 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12829
12830    Permission is hereby granted, free of charge, to any person obtaining
12831    a copy of this software and associated documentation files (the
12832    "Software"), to deal in the Software without restriction, including
12833    without limitation the rights to use, copy, modify, merge, publish,
12834    distribute, sublicense, and/or sell copies of the Software, and to
12835    permit persons to whom the Software is furnished to do so, subject to
12836    the following conditions:
12837
12838    The above copyright notice and this permission notice shall be
12839    included in all copies or substantial portions of the Software.
12840
12841    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12842    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12843    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12844    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12845    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12846    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12847    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12848 */
12849
12850 /* This is my infix parser/evaluator. It is optimized for size, intended
12851  * as a replacement for yacc-based parsers. However, it may well be faster
12852  * than a comparable parser writen in yacc. The supported operators are
12853  * listed in #defines below. Parens, order of operations, and error handling
12854  * are supported. This code is threadsafe. The exact expression format should
12855  * be that which POSIX specifies for shells. */
12856
12857 /* The code uses a simple two-stack algorithm. See
12858  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12859  * for a detailed explaination of the infix-to-postfix algorithm on which
12860  * this is based (this code differs in that it applies operators immediately
12861  * to the stack instead of adding them to a queue to end up with an
12862  * expression). */
12863
12864 /* To use the routine, call it with an expression string and error return
12865  * pointer */
12866
12867 /*
12868  * Aug 24, 2001              Manuel Novoa III
12869  *
12870  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12871  *
12872  * 1) In arith_apply():
12873  *    a) Cached values of *numptr and &(numptr[-1]).
12874  *    b) Removed redundant test for zero denominator.
12875  *
12876  * 2) In arith():
12877  *    a) Eliminated redundant code for processing operator tokens by moving
12878  *       to a table-based implementation.  Also folded handling of parens
12879  *       into the table.
12880  *    b) Combined all 3 loops which called arith_apply to reduce generated
12881  *       code size at the cost of speed.
12882  *
12883  * 3) The following expressions were treated as valid by the original code:
12884  *       1()  ,    0!  ,    1 ( *3 )   .
12885  *    These bugs have been fixed by internally enclosing the expression in
12886  *    parens and then checking that all binary ops and right parens are
12887  *    preceded by a valid expression (NUM_TOKEN).
12888  *
12889  * Note: It may be desireable to replace Aaron's test for whitespace with
12890  * ctype's isspace() if it is used by another busybox applet or if additional
12891  * whitespace chars should be considered.  Look below the "#include"s for a
12892  * precompiler test.
12893  */
12894
12895 /*
12896  * Aug 26, 2001              Manuel Novoa III
12897  *
12898  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
12899  *
12900  * Merge in Aaron's comments previously posted to the busybox list,
12901  * modified slightly to take account of my changes to the code.
12902  *
12903  */
12904
12905 /*
12906  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12907  *
12908  * - allow access to variable,
12909  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12910  * - realize assign syntax (VAR=expr, +=, *= etc)
12911  * - realize exponentiation (** operator)
12912  * - realize comma separated - expr, expr
12913  * - realise ++expr --expr expr++ expr--
12914  * - realise expr ? expr : expr (but, second expr calculate always)
12915  * - allow hexdecimal and octal numbers
12916  * - was restored loses XOR operator
12917  * - remove one goto label, added three ;-)
12918  * - protect $((num num)) as true zero expr (Manuel`s error)
12919  * - always use special isspace(), see comment from bash ;-)
12920  */
12921
12922
12923 #define arith_isspace(arithval) \
12924         (arithval == ' ' || arithval == '\n' || arithval == '\t')
12925
12926
12927 typedef unsigned char operator;
12928
12929 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12930  * precedence, and 3 high bits are an ID unique accross operators of that
12931  * precedence. The ID portion is so that multiple operators can have the
12932  * same precedence, ensuring that the leftmost one is evaluated first.
12933  * Consider * and /. */
12934
12935 #define tok_decl(prec,id) (((id)<<5)|(prec))
12936 #define PREC(op) ((op) & 0x1F)
12937
12938 #define TOK_LPAREN tok_decl(0,0)
12939
12940 #define TOK_COMMA tok_decl(1,0)
12941
12942 #define TOK_ASSIGN tok_decl(2,0)
12943 #define TOK_AND_ASSIGN tok_decl(2,1)
12944 #define TOK_OR_ASSIGN tok_decl(2,2)
12945 #define TOK_XOR_ASSIGN tok_decl(2,3)
12946 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12947 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12948 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12949 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12950
12951 #define TOK_MUL_ASSIGN tok_decl(3,0)
12952 #define TOK_DIV_ASSIGN tok_decl(3,1)
12953 #define TOK_REM_ASSIGN tok_decl(3,2)
12954
12955 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12956 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12957
12958 /* conditional is right associativity too */
12959 #define TOK_CONDITIONAL tok_decl(4,0)
12960 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12961
12962 #define TOK_OR tok_decl(5,0)
12963
12964 #define TOK_AND tok_decl(6,0)
12965
12966 #define TOK_BOR tok_decl(7,0)
12967
12968 #define TOK_BXOR tok_decl(8,0)
12969
12970 #define TOK_BAND tok_decl(9,0)
12971
12972 #define TOK_EQ tok_decl(10,0)
12973 #define TOK_NE tok_decl(10,1)
12974
12975 #define TOK_LT tok_decl(11,0)
12976 #define TOK_GT tok_decl(11,1)
12977 #define TOK_GE tok_decl(11,2)
12978 #define TOK_LE tok_decl(11,3)
12979
12980 #define TOK_LSHIFT tok_decl(12,0)
12981 #define TOK_RSHIFT tok_decl(12,1)
12982
12983 #define TOK_ADD tok_decl(13,0)
12984 #define TOK_SUB tok_decl(13,1)
12985
12986 #define TOK_MUL tok_decl(14,0)
12987 #define TOK_DIV tok_decl(14,1)
12988 #define TOK_REM tok_decl(14,2)
12989
12990 /* exponent is right associativity */
12991 #define TOK_EXPONENT tok_decl(15,1)
12992
12993 /* For now unary operators. */
12994 #define UNARYPREC 16
12995 #define TOK_BNOT tok_decl(UNARYPREC,0)
12996 #define TOK_NOT tok_decl(UNARYPREC,1)
12997
12998 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12999 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13000
13001 #define PREC_PRE (UNARYPREC+2)
13002
13003 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13004 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13005
13006 #define PREC_POST (UNARYPREC+3)
13007
13008 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13009 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13010
13011 #define SPEC_PREC (UNARYPREC+4)
13012
13013 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13014 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13015
13016 #define NUMPTR (*numstackptr)
13017
13018 static inline int tok_have_assign(operator op)
13019 {
13020         operator prec = PREC(op);
13021
13022         convert_prec_is_assing(prec);
13023         return (prec == PREC(TOK_ASSIGN) ||
13024                         prec == PREC_PRE || prec == PREC_POST);
13025 }
13026
13027 static inline int is_right_associativity(operator prec)
13028 {
13029     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13030             prec == PREC(TOK_CONDITIONAL));
13031 }
13032
13033
13034 typedef struct ARITCH_VAR_NUM {
13035         long val;
13036         long contidional_second_val;
13037         char contidional_second_val_initialized;
13038         char *var;      /* if NULL then is regular number,
13039                            else is varable name */
13040 } v_n_t;
13041
13042
13043 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13044         const char *var;
13045         struct CHK_VAR_RECURSIVE_LOOPED *next;
13046 } chk_var_recursive_looped_t;
13047
13048 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13049
13050
13051 static int arith_lookup_val(v_n_t *t)
13052 {
13053     if(t->var) {
13054         const char * p = lookupvar(t->var);
13055
13056         if(p) {
13057             int errcode;
13058
13059             /* recursive try as expression */
13060             chk_var_recursive_looped_t *cur;
13061             chk_var_recursive_looped_t cur_save;
13062
13063             for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13064                 if(strcmp(cur->var, t->var) == 0) {
13065                     /* expression recursion loop detected */
13066                     return -5;
13067                 }
13068             }
13069             /* save current lookuped var name */
13070             cur = prev_chk_var_recursive;
13071             cur_save.var = t->var;
13072             cur_save.next = cur;
13073             prev_chk_var_recursive = &cur_save;
13074
13075             t->val = arith (p, &errcode);
13076             /* restore previous ptr after recursiving */
13077             prev_chk_var_recursive = cur;
13078             return errcode;
13079         } else {
13080             /* allow undefined var as 0 */
13081             t->val = 0;
13082         }
13083     }
13084     return 0;
13085 }
13086
13087 /* "applying" a token means performing it on the top elements on the integer
13088  * stack. For a unary operator it will only change the top element, but a
13089  * binary operator will pop two arguments and push a result */
13090 static inline int
13091 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13092 {
13093         long numptr_val;
13094         v_n_t *numptr_m1;
13095         long rez;
13096         int ret_arith_lookup_val;
13097
13098         if (NUMPTR == numstack) goto err; /* There is no operator that can work
13099                                                                                  without arguments */
13100         numptr_m1 = NUMPTR - 1;
13101
13102         /* check operand is var with noninteger value */
13103         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13104         if(ret_arith_lookup_val)
13105                 return ret_arith_lookup_val;
13106
13107         rez = numptr_m1->val;
13108         if (op == TOK_UMINUS)
13109                 rez *= -1;
13110         else if (op == TOK_NOT)
13111                 rez = !rez;
13112         else if (op == TOK_BNOT)
13113                 rez = ~rez;
13114         else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13115                 rez++;
13116         else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13117                 rez--;
13118         else if (op != TOK_UPLUS) {
13119                 /* Binary operators */
13120
13121             /* check and binary operators need two arguments */
13122             if (numptr_m1 == numstack) goto err;
13123
13124             /* ... and they pop one */
13125             --NUMPTR;
13126             numptr_val = rez;
13127             if (op == TOK_CONDITIONAL) {
13128                 if(! numptr_m1->contidional_second_val_initialized) {
13129                     /* protect $((expr1 ? expr2)) without ": expr" */
13130                     goto err;
13131                 }
13132                 rez = numptr_m1->contidional_second_val;
13133             } else if(numptr_m1->contidional_second_val_initialized) {
13134                     /* protect $((expr1 : expr2)) without "expr ? " */
13135                     goto err;
13136             }
13137             numptr_m1 = NUMPTR - 1;
13138             if(op != TOK_ASSIGN) {
13139                 /* check operand is var with noninteger value for not '=' */
13140                 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13141                 if(ret_arith_lookup_val)
13142                     return ret_arith_lookup_val;
13143             }
13144             if (op == TOK_CONDITIONAL) {
13145                     numptr_m1->contidional_second_val = rez;
13146             }
13147             rez = numptr_m1->val;
13148             if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13149                         rez |= numptr_val;
13150             else if (op == TOK_OR)
13151                         rez = numptr_val || rez;
13152             else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13153                         rez &= numptr_val;
13154             else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13155                         rez ^= numptr_val;
13156             else if (op == TOK_AND)
13157                         rez = rez && numptr_val;
13158             else if (op == TOK_EQ)
13159                         rez = (rez == numptr_val);
13160             else if (op == TOK_NE)
13161                         rez = (rez != numptr_val);
13162             else if (op == TOK_GE)
13163                         rez = (rez >= numptr_val);
13164             else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13165                         rez >>= numptr_val;
13166             else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13167                         rez <<= numptr_val;
13168             else if (op == TOK_GT)
13169                         rez = (rez > numptr_val);
13170             else if (op == TOK_LT)
13171                         rez = (rez < numptr_val);
13172             else if (op == TOK_LE)
13173                         rez = (rez <= numptr_val);
13174             else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13175                         rez *= numptr_val;
13176             else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13177                         rez += numptr_val;
13178             else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13179                         rez -= numptr_val;
13180             else if (op == TOK_ASSIGN || op == TOK_COMMA)
13181                         rez = numptr_val;
13182             else if (op == TOK_CONDITIONAL_SEP) {
13183                         if (numptr_m1 == numstack) {
13184                             /* protect $((expr : expr)) without "expr ? " */
13185                             goto err;
13186                         }
13187                         numptr_m1->contidional_second_val_initialized = op;
13188                         numptr_m1->contidional_second_val = numptr_val;
13189             }
13190             else if (op == TOK_CONDITIONAL) {
13191                         rez = rez ?
13192                               numptr_val : numptr_m1->contidional_second_val;
13193             }
13194             else if(op == TOK_EXPONENT) {
13195                         if(numptr_val < 0)
13196                                 return -3;      /* exponent less than 0 */
13197                         else {
13198                                 long c = 1;
13199
13200                                 if(numptr_val)
13201                                         while(numptr_val--)
13202                                                 c *= rez;
13203                                 rez = c;
13204                         }
13205             }
13206             else if(numptr_val==0)          /* zero divisor check */
13207                         return -2;
13208             else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13209                         rez /= numptr_val;
13210             else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13211                         rez %= numptr_val;
13212         }
13213         if(tok_have_assign(op)) {
13214                 char buf[32];
13215
13216                 if(numptr_m1->var == NULL) {
13217                         /* Hmm, 1=2 ? */
13218                         goto err;
13219                 }
13220                 /* save to shell variable */
13221                 sprintf(buf, "%ld", rez);
13222                 setvar(numptr_m1->var, buf, 0);
13223                 /* after saving, make previous value for v++ or v-- */
13224                 if(op == TOK_POST_INC)
13225                         rez--;
13226                 else if(op == TOK_POST_DEC)
13227                         rez++;
13228         }
13229         numptr_m1->val = rez;
13230         /* protect geting var value, is number now */
13231         numptr_m1->var = NULL;
13232         return 0;
13233 err: return(-1);
13234 }
13235
13236 /* longest must first */
13237 static const char op_tokens[] = {
13238         '<','<','=',0, TOK_LSHIFT_ASSIGN,
13239         '>','>','=',0, TOK_RSHIFT_ASSIGN,
13240         '<','<',    0, TOK_LSHIFT,
13241         '>','>',    0, TOK_RSHIFT,
13242         '|','|',    0, TOK_OR,
13243         '&','&',    0, TOK_AND,
13244         '!','=',    0, TOK_NE,
13245         '<','=',    0, TOK_LE,
13246         '>','=',    0, TOK_GE,
13247         '=','=',    0, TOK_EQ,
13248         '|','=',    0, TOK_OR_ASSIGN,
13249         '&','=',    0, TOK_AND_ASSIGN,
13250         '*','=',    0, TOK_MUL_ASSIGN,
13251         '/','=',    0, TOK_DIV_ASSIGN,
13252         '%','=',    0, TOK_REM_ASSIGN,
13253         '+','=',    0, TOK_PLUS_ASSIGN,
13254         '-','=',    0, TOK_MINUS_ASSIGN,
13255         '-','-',    0, TOK_POST_DEC,
13256         '^','=',    0, TOK_XOR_ASSIGN,
13257         '+','+',    0, TOK_POST_INC,
13258         '*','*',    0, TOK_EXPONENT,
13259         '!',        0, TOK_NOT,
13260         '<',        0, TOK_LT,
13261         '>',        0, TOK_GT,
13262         '=',        0, TOK_ASSIGN,
13263         '|',        0, TOK_BOR,
13264         '&',        0, TOK_BAND,
13265         '*',        0, TOK_MUL,
13266         '/',        0, TOK_DIV,
13267         '%',        0, TOK_REM,
13268         '+',        0, TOK_ADD,
13269         '-',        0, TOK_SUB,
13270         '^',        0, TOK_BXOR,
13271         /* uniq */
13272         '~',        0, TOK_BNOT,
13273         ',',        0, TOK_COMMA,
13274         '?',        0, TOK_CONDITIONAL,
13275         ':',        0, TOK_CONDITIONAL_SEP,
13276         ')',        0, TOK_RPAREN,
13277         '(',        0, TOK_LPAREN,
13278         0
13279 };
13280 /* ptr to ")" */
13281 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13282
13283
13284 extern long arith (const char *expr, int *perrcode)
13285 {
13286     register char arithval; /* Current character under analysis */
13287     operator lasttok, op;
13288     operator prec;
13289
13290     const char *p = endexpression;
13291     int errcode;
13292
13293     size_t datasizes = strlen(expr) + 2;
13294
13295     /* Stack of integers */
13296     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13297      * in any given correct or incorrect expression is left as an excersize to
13298      * the reader. */
13299     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13300             *numstackptr = numstack;
13301     /* Stack of operator tokens */
13302     operator *stack = alloca((datasizes) * sizeof(operator)),
13303             *stackptr = stack;
13304
13305     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
13306     *perrcode = errcode = 0;
13307
13308     while(1) {
13309         if ((arithval = *expr) == 0) {
13310                 if (p == endexpression) {
13311                         /* Null expression. */
13312                         return 0;
13313                 }
13314
13315                 /* This is only reached after all tokens have been extracted from the
13316                  * input stream. If there are still tokens on the operator stack, they
13317                  * are to be applied in order. At the end, there should be a final
13318                  * result on the integer stack */
13319
13320                 if (expr != endexpression + 1) {
13321                         /* If we haven't done so already, */
13322                         /* append a closing right paren */
13323                         expr = endexpression;
13324                         /* and let the loop process it. */
13325                         continue;
13326                 }
13327                 /* At this point, we're done with the expression. */
13328                 if (numstackptr != numstack+1) {
13329                         /* ... but if there isn't, it's bad */
13330                   err:
13331                         return (*perrcode = -1);
13332                 }
13333                 if(numstack->var) {
13334                     /* expression is $((var)) only, lookup now */
13335                     errcode = arith_lookup_val(numstack);
13336                 }
13337         ret:
13338                 *perrcode = errcode;
13339                 return numstack->val;
13340         } else {
13341                 /* Continue processing the expression. */
13342                 if (arith_isspace(arithval)) {
13343                         /* Skip whitespace */
13344                         goto prologue;
13345                 }
13346                 if((p = endofname(expr)) != expr) {
13347                         int var_name_size = (p-expr) + 1;  /* trailing zero */
13348
13349                         numstackptr->var = alloca(var_name_size);
13350                         safe_strncpy(numstackptr->var, expr, var_name_size);
13351                         expr = p;
13352                 num:
13353                         numstackptr->contidional_second_val_initialized = 0;
13354                         numstackptr++;
13355                         lasttok = TOK_NUM;
13356                         continue;
13357                 } else if (is_digit(arithval)) {
13358                         numstackptr->var = NULL;
13359                         numstackptr->val = strtol(expr, (char **) &expr, 0);
13360                         goto num;
13361                 }
13362                 for(p = op_tokens; ; p++) {
13363                         const char *o;
13364
13365                         if(*p == 0) {
13366                                 /* strange operator not found */
13367                                 goto err;
13368                         }
13369                         for(o = expr; *p && *o == *p; p++)
13370                                 o++;
13371                         if(! *p) {
13372                                 /* found */
13373                                 expr = o - 1;
13374                                 break;
13375                         }
13376                         /* skip tail uncompared token */
13377                         while(*p)
13378                                 p++;
13379                         /* skip zero delim */
13380                         p++;
13381                 }
13382                 op = p[1];
13383
13384                 /* post grammar: a++ reduce to num */
13385                 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13386                     lasttok = TOK_NUM;
13387
13388                 /* Plus and minus are binary (not unary) _only_ if the last
13389                  * token was as number, or a right paren (which pretends to be
13390                  * a number, since it evaluates to one). Think about it.
13391                  * It makes sense. */
13392                 if (lasttok != TOK_NUM) {
13393                         switch(op) {
13394                                 case TOK_ADD:
13395                                     op = TOK_UPLUS;
13396                                     break;
13397                                 case TOK_SUB:
13398                                     op = TOK_UMINUS;
13399                                     break;
13400                                 case TOK_POST_INC:
13401                                     op = TOK_PRE_INC;
13402                                     break;
13403                                 case TOK_POST_DEC:
13404                                     op = TOK_PRE_DEC;
13405                                     break;
13406                         }
13407                 }
13408                 /* We don't want a unary operator to cause recursive descent on the
13409                  * stack, because there can be many in a row and it could cause an
13410                  * operator to be evaluated before its argument is pushed onto the
13411                  * integer stack. */
13412                 /* But for binary operators, "apply" everything on the operator
13413                  * stack until we find an operator with a lesser priority than the
13414                  * one we have just extracted. */
13415                 /* Left paren is given the lowest priority so it will never be
13416                  * "applied" in this way.
13417                  * if associativity is right and priority eq, applied also skip
13418                  */
13419                 prec = PREC(op);
13420                 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13421                         /* not left paren or unary */
13422                         if (lasttok != TOK_NUM) {
13423                                 /* binary op must be preceded by a num */
13424                                 goto err;
13425                         }
13426                         while (stackptr != stack) {
13427                             if (op == TOK_RPAREN) {
13428                                 /* The algorithm employed here is simple: while we don't
13429                                  * hit an open paren nor the bottom of the stack, pop
13430                                  * tokens and apply them */
13431                                 if (stackptr[-1] == TOK_LPAREN) {
13432                                     --stackptr;
13433                                     /* Any operator directly after a */
13434                                     lasttok = TOK_NUM;
13435                                     /* close paren should consider itself binary */
13436                                     goto prologue;
13437                                 }
13438                             } else {
13439                                 operator prev_prec = PREC(stackptr[-1]);
13440
13441                                 convert_prec_is_assing(prec);
13442                                 convert_prec_is_assing(prev_prec);
13443                                 if (prev_prec < prec)
13444                                         break;
13445                                 /* check right assoc */
13446                                 if(prev_prec == prec && is_right_associativity(prec))
13447                                         break;
13448                             }
13449                             errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13450                             if(errcode) goto ret;
13451                         }
13452                         if (op == TOK_RPAREN) {
13453                                 goto err;
13454                         }
13455                 }
13456
13457                 /* Push this operator to the stack and remember it. */
13458                 *stackptr++ = lasttok = op;
13459
13460           prologue:
13461                 ++expr;
13462         }
13463     }
13464 }
13465 #endif /* CONFIG_ASH_MATH_SUPPORT */
13466
13467
13468 #ifdef DEBUG
13469 const char *bb_applet_name = "debug stuff usage";
13470 int main(int argc, char **argv)
13471 {
13472         return ash_main(argc, argv);
13473 }
13474 #endif
13475
13476 /*-
13477  * Copyright (c) 1989, 1991, 1993, 1994
13478  *      The Regents of the University of California.  All rights reserved.
13479  *
13480  * This code is derived from software contributed to Berkeley by
13481  * Kenneth Almquist.
13482  *
13483  * Redistribution and use in source and binary forms, with or without
13484  * modification, are permitted provided that the following conditions
13485  * are met:
13486  * 1. Redistributions of source code must retain the above copyright
13487  *    notice, this list of conditions and the following disclaimer.
13488  * 2. Redistributions in binary form must reproduce the above copyright
13489  *    notice, this list of conditions and the following disclaimer in the
13490  *    documentation and/or other materials provided with the distribution.
13491  *
13492  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13493  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13494  *
13495  * 4. Neither the name of the University nor the names of its contributors
13496  *    may be used to endorse or promote products derived from this software
13497  *    without specific prior written permission.
13498  *
13499  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13500  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13501  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13502  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13503  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13504  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13505  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13506  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13507  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13508  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13509  * SUCH DAMAGE.
13510  */