Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/shell/ash.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 2  Line 2 
2  /*  /*
3   * ash shell port for busybox   * ash shell port for busybox
4   *   *
5     * This code is derived from software contributed to Berkeley by
6     * Kenneth Almquist.
7     *
8     * Original BSD copyright notice is retained at the end of this file.
9     *
10   * Copyright (c) 1989, 1991, 1993, 1994   * Copyright (c) 1989, 1991, 1993, 1994
11   *      The Regents of the University of California.  All rights reserved.   *      The Regents of the University of California.  All rights reserved.
12   *   *
13   * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>   * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14   * was re-ported from NetBSD and debianized.   * was re-ported from NetBSD and debianized.
15   *   *
  * This code is derived from software contributed to Berkeley by  
  * Kenneth Almquist.  
  *  
16   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  *  
  * Original BSD copyright notice is retained at the end of this file.  
  */  
   
 /*  
  * rewrite arith.y to micro stack based cryptic algorithm by  
  * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>  
  *  
  * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support  
  * dynamic variables.  
  *  
  * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be  
  * used in busybox and size optimizations,  
  * rewrote arith (see notes to this), added locale support,  
  * rewrote dynamic variables.  
17   */   */
18    
19  /*  /*
# Line 47  Line 34 
34    
35  #define PROFILE 0  #define PROFILE 0
36    
 #define IFS_BROKEN  
   
37  #define JOBS ENABLE_ASH_JOB_CONTROL  #define JOBS ENABLE_ASH_JOB_CONTROL
38    
39  #if DEBUG  #if DEBUG
# Line 61  Line 46 
46  #include <paths.h>  #include <paths.h>
47  #include <setjmp.h>  #include <setjmp.h>
48  #include <fnmatch.h>  #include <fnmatch.h>
49  #if JOBS || ENABLE_ASH_READ_NCHARS  
50  # include <termios.h>  #include "shell_common.h"
51    #include "builtin_read.h"
52    #include "math.h"
53    #if ENABLE_ASH_RANDOM_SUPPORT
54    # include "random.h"
55    #else
56    # define CLEAR_RANDOM_T(rnd) ((void)0)
57    #endif
58    
59    #define SKIP_definitions 1
60    #include "applet_tables.h"
61    #undef SKIP_definitions
62    #if NUM_APPLETS == 1
63    /* STANDALONE does not make sense, and won't compile */
64    # undef CONFIG_FEATURE_SH_STANDALONE
65    # undef ENABLE_FEATURE_SH_STANDALONE
66    # undef IF_FEATURE_SH_STANDALONE
67    # undef IF_NOT_FEATURE_SH_STANDALONE
68    # define ENABLE_FEATURE_SH_STANDALONE 0
69    # define IF_FEATURE_SH_STANDALONE(...)
70    # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
71  #endif  #endif
72    
73  #ifndef PIPE_BUF  #ifndef PIPE_BUF
# Line 70  Line 75 
75  #endif  #endif
76    
77  #if defined(__uClinux__)  #if defined(__uClinux__)
78  # error "Do not even bother, ash will not run on uClinux"  # error "Do not even bother, ash will not run on NOMMU machine"
79  #endif  #endif
80    
81    
# Line 98  static const char *const optletters_optn Line 103  static const char *const optletters_optn
103   "b"   "notify",   "b"   "notify",
104   "u"   "nounset",   "u"   "nounset",
105   "\0"  "vi"   "\0"  "vi"
106    #if ENABLE_ASH_BASH_COMPAT
107     ,"\0"  "pipefail"
108    #endif
109  #if DEBUG  #if DEBUG
110   ,"\0"  "nolog"   ,"\0"  "nolog"
111   ,"\0"  "debug"   ,"\0"  "debug"
112  #endif  #endif
113  };  };
114    
115  #define optletters(n) optletters_optnames[(n)][0]  #define optletters(n)  optletters_optnames[n][0]
116  #define optnames(n) (&optletters_optnames[(n)][1])  #define optnames(n)   (optletters_optnames[n] + 1)
117    
118  enum { NOPTS = ARRAY_SIZE(optletters_optnames) };  enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
119    
# Line 114  enum { NOPTS = ARRAY_SIZE(optletters_opt Line 122  enum { NOPTS = ARRAY_SIZE(optletters_opt
122    
123  static const char homestr[] ALIGN1 = "HOME";  static const char homestr[] ALIGN1 = "HOME";
124  static const char snlfmt[] ALIGN1 = "%s\n";  static const char snlfmt[] ALIGN1 = "%s\n";
125  static const char illnum[] ALIGN1 = "Illegal number: %s";  static const char msg_illnum[] ALIGN1 = "Illegal number: %s";
126    
127  /*  /*
128   * We enclose jmp_buf in a structure so that we can declare pointers to   * We enclose jmp_buf in a structure so that we can declare pointers to
129   * jump locations.  The global variable handler contains the location to   * jump locations.  The global variable handler contains the location to
130   * jump to when an exception occurs, and the global variable exception   * jump to when an exception occurs, and the global variable exception_type
131   * contains a code identifying the exception.  To implement nested   * contains a code identifying the exception.  To implement nested
132   * exception handlers, the user should save the value of handler on entry   * exception handlers, the user should save the value of handler on entry
133   * to an inner scope, set handler to point to a jmploc structure for the   * to an inner scope, set handler to point to a jmploc structure for the
# Line 144  struct globals_misc { Line 152  struct globals_misc {
152    
153   struct jmploc *exception_handler;   struct jmploc *exception_handler;
154    
155  // disabled by vda: cannot understand how it was supposed to work -   volatile int suppress_int; /* counter */
156  // cannot fix bugs. That's why you have to explain your non-trivial designs!   volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
 // /* do we generate EXSIG events */  
 // int exsig; /* counter */  
  volatile int suppressint; /* counter */  
  volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */  
157   /* last pending signal */   /* last pending signal */
158   volatile /*sig_atomic_t*/ smallint pendingsig;   volatile /*sig_atomic_t*/ smallint pending_sig;
159   smallint exception; /* kind of exception (0..5) */   smallint exception_type; /* kind of exception (0..5) */
160   /* exceptions */   /* exceptions */
161  #define EXINT 0         /* SIGINT received */  #define EXINT 0         /* SIGINT received */
162  #define EXERROR 1       /* a generic error */  #define EXERROR 1       /* a generic error */
# Line 179  struct globals_misc { Line 183  struct globals_misc {
183  #define bflag optlist[11]  #define bflag optlist[11]
184  #define uflag optlist[12]  #define uflag optlist[12]
185  #define viflag optlist[13]  #define viflag optlist[13]
186    #if ENABLE_ASH_BASH_COMPAT
187    # define pipefail optlist[14]
188    #else
189    # define pipefail 0
190    #endif
191  #if DEBUG  #if DEBUG
192  #define nolog optlist[14]  # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
193  #define debug optlist[15]  # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
194  #endif  #endif
195    
196   /* trap handler commands */   /* trap handler commands */
197   /*   /*
198   * Sigmode records the current value of the signal handlers for the various   * Sigmode records the current value of the signal handlers for the various
199   * modes.  A value of zero means that the current handler is not known.   * modes.  A value of zero means that the current handler is not known.
200   * S_HARD_IGN indicates that the signal was ignored on entry to the shell,   * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
201   */   */
202   char sigmode[NSIG - 1];   char sigmode[NSIG - 1];
203  #define S_DFL 1                 /* default signal handling (SIG_DFL) */  #define S_DFL      1            /* default signal handling (SIG_DFL) */
204  #define S_CATCH 2               /* signal is caught */  #define S_CATCH    2            /* signal is caught */
205  #define S_IGN 3                 /* signal is ignored (SIG_IGN) */  #define S_IGN      3            /* signal is ignored (SIG_IGN) */
206  #define S_HARD_IGN 4            /* signal is ignored permenantly */  #define S_HARD_IGN 4            /* signal is ignored permenantly */
 #define S_RESET 5               /* temporary - to reset a hard ignored sig */  
207    
208   /* indicates specified signal received */   /* indicates specified signal received */
209   char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */   uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
210   char *trap[NSIG];   char *trap[NSIG];
211     char **trap_ptr;        /* used only by "trap hack" */
212    
213   /* Rarely referenced stuff */   /* Rarely referenced stuff */
214  #if ENABLE_ASH_RANDOM_SUPPORT  #if ENABLE_ASH_RANDOM_SUPPORT
215   /* Random number generators */   random_t random_gen;
  int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */  
  uint32_t random_LCG;        /* LCG (fast but weak) */  
216  #endif  #endif
217   pid_t backgndpid;        /* pid of last background process */   pid_t backgndpid;        /* pid of last background process */
218   smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */   smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */
# Line 219  extern struct globals_misc *const ash_pt Line 226  extern struct globals_misc *const ash_pt
226  #define physdir     (G_misc.physdir    )  #define physdir     (G_misc.physdir    )
227  #define arg0        (G_misc.arg0       )  #define arg0        (G_misc.arg0       )
228  #define exception_handler (G_misc.exception_handler)  #define exception_handler (G_misc.exception_handler)
229  #define exception         (G_misc.exception        )  #define exception_type    (G_misc.exception_type   )
230  #define suppressint       (G_misc.suppressint      )  #define suppress_int      (G_misc.suppress_int     )
231  #define intpending        (G_misc.intpending       )  #define pending_int       (G_misc.pending_int      )
232  //#define exsig             (G_misc.exsig            )  #define pending_sig       (G_misc.pending_sig      )
 #define pendingsig        (G_misc.pendingsig       )  
233  #define isloginsh   (G_misc.isloginsh  )  #define isloginsh   (G_misc.isloginsh  )
234  #define nullstr     (G_misc.nullstr    )  #define nullstr     (G_misc.nullstr    )
235  #define optlist     (G_misc.optlist    )  #define optlist     (G_misc.optlist    )
236  #define sigmode     (G_misc.sigmode    )  #define sigmode     (G_misc.sigmode    )
237  #define gotsig      (G_misc.gotsig     )  #define gotsig      (G_misc.gotsig     )
238  #define trap        (G_misc.trap       )  #define trap        (G_misc.trap       )
239  #define random_galois_LFSR (G_misc.random_galois_LFSR)  #define trap_ptr    (G_misc.trap_ptr   )
240  #define random_LCG         (G_misc.random_LCG        )  #define random_gen  (G_misc.random_gen )
241  #define backgndpid  (G_misc.backgndpid )  #define backgndpid  (G_misc.backgndpid )
242  #define job_warning (G_misc.job_warning)  #define job_warning (G_misc.job_warning)
243  #define INIT_G_misc() do { \  #define INIT_G_misc() do { \
# Line 239  extern struct globals_misc *const ash_pt Line 245  extern struct globals_misc *const ash_pt
245   barrier(); \   barrier(); \
246   curdir = nullstr; \   curdir = nullstr; \
247   physdir = nullstr; \   physdir = nullstr; \
248     trap_ptr = trap; \
249  } while (0)  } while (0)
250    
251    
# Line 248  static void trace_printf(const char *fmt Line 255  static void trace_printf(const char *fmt
255  static void trace_vprintf(const char *fmt, va_list va);  static void trace_vprintf(const char *fmt, va_list va);
256  # define TRACE(param)    trace_printf param  # define TRACE(param)    trace_printf param
257  # define TRACEV(param)   trace_vprintf param  # define TRACEV(param)   trace_vprintf param
258  # define close(f) do { \  # define close(fd) do { \
259   int dfd = (f); \   int dfd = (fd); \
260   if (close(dfd) < 0) \   if (close(dfd) < 0) \
261   bb_error_msg("bug on %d: closing %d(%x)", \   bb_error_msg("bug on %d: closing %d(0x%x)", \
262   __LINE__, dfd, dfd); \   __LINE__, dfd, dfd); \
263  } while (0)  } while (0)
264  #else  #else
# Line 263  static void trace_vprintf(const char *fm Line 270  static void trace_vprintf(const char *fm
270  /* ============ Utility functions */  /* ============ Utility functions */
271  #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)  #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
272    
 /* C99 say: "char" declaration may be signed or unsigned by default */  
 #define signed_char2int(sc) ((int)(signed char)(sc))  
   
273  static int isdigit_str9(const char *str)  static int isdigit_str9(const char *str)
274  {  {
275   int maxlen = 9 + 1; /* max 9 digits: 999999999 */   int maxlen = 9 + 1; /* max 9 digits: 999999999 */
# Line 283  static int isdigit_str9(const char *str) Line 287  static int isdigit_str9(const char *str)
287   * more fun than worrying about efficiency and portability. :-))   * more fun than worrying about efficiency and portability. :-))
288   */   */
289  #define INT_OFF do { \  #define INT_OFF do { \
290   suppressint++; \   suppress_int++; \
291   xbarrier(); \   xbarrier(); \
292  } while (0)  } while (0)
293    
294  /*  /*
295   * Called to raise an exception.  Since C doesn't include exceptions, we   * Called to raise an exception.  Since C doesn't include exceptions, we
296   * just do a longjmp to the exception handler.  The type of exception is   * just do a longjmp to the exception handler.  The type of exception is
297   * stored in the global variable "exception".   * stored in the global variable "exception_type".
298   */   */
299  static void raise_exception(int) NORETURN;  static void raise_exception(int) NORETURN;
300  static void  static void
# Line 301  raise_exception(int e) Line 305  raise_exception(int e)
305   abort();   abort();
306  #endif  #endif
307   INT_OFF;   INT_OFF;
308   exception = e;   exception_type = e;
309   longjmp(exception_handler->loc, 1);   longjmp(exception_handler->loc, 1);
310  }  }
311  #if DEBUG  #if DEBUG
# Line 322  static void raise_interrupt(void) NORETU Line 326  static void raise_interrupt(void) NORETU
326  static void  static void
327  raise_interrupt(void)  raise_interrupt(void)
328  {  {
329   int i;   int ex_type;
330    
331   intpending = 0;   pending_int = 0;
332   /* Signal is not automatically unmasked after it is raised,   /* Signal is not automatically unmasked after it is raised,
333   * do it ourself - unmask all signals */   * do it ourself - unmask all signals */
334   sigprocmask_allsigs(SIG_UNBLOCK);   sigprocmask_allsigs(SIG_UNBLOCK);
335   /* pendingsig = 0; - now done in onsig() */   /* pending_sig = 0; - now done in onsig() */
336    
337   i = EXSIG;   ex_type = EXSIG;
338   if (gotsig[SIGINT - 1] && !trap[SIGINT]) {   if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
339   if (!(rootshell && iflag)) {   if (!(rootshell && iflag)) {
340   /* Kill ourself with SIGINT */   /* Kill ourself with SIGINT */
341   signal(SIGINT, SIG_DFL);   signal(SIGINT, SIG_DFL);
342   raise(SIGINT);   raise(SIGINT);
343   }   }
344   i = EXINT;   ex_type = EXINT;
345   }   }
346   raise_exception(i);   raise_exception(ex_type);
347   /* NOTREACHED */   /* NOTREACHED */
348  }  }
349  #if DEBUG  #if DEBUG
# Line 349  raise_interrupt(void) Line 353  raise_interrupt(void)
353  } while (0)  } while (0)
354  #endif  #endif
355    
356  #if ENABLE_ASH_OPTIMIZE_FOR_SIZE  static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 static void  
357  int_on(void)  int_on(void)
358  {  {
359   if (--suppressint == 0 && intpending) {   xbarrier();
360     if (--suppress_int == 0 && pending_int) {
361   raise_interrupt();   raise_interrupt();
362   }   }
363  }  }
364  #define INT_ON int_on()  #define INT_ON int_on()
365  static void  static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
366  force_int_on(void)  force_int_on(void)
367  {  {
368   suppressint = 0;   xbarrier();
369   if (intpending)   suppress_int = 0;
370     if (pending_int)
371   raise_interrupt();   raise_interrupt();
372  }  }
373  #define FORCE_INT_ON force_int_on()  #define FORCE_INT_ON force_int_on()
374    
375  #else /* !ASH_OPTIMIZE_FOR_SIZE */  #define SAVE_INT(v) ((v) = suppress_int)
   
 #define INT_ON do { \  
  xbarrier(); \  
  if (--suppressint == 0 && intpending) \  
  raise_interrupt(); \  
 } while (0)  
 #define FORCE_INT_ON do { \  
  xbarrier(); \  
  suppressint = 0; \  
  if (intpending) \  
  raise_interrupt(); \  
 } while (0)  
 #endif /* !ASH_OPTIMIZE_FOR_SIZE */  
   
 #define SAVE_INT(v) ((v) = suppressint)  
376    
377  #define RESTORE_INT(v) do { \  #define RESTORE_INT(v) do { \
378   xbarrier(); \   xbarrier(); \
379   suppressint = (v); \   suppress_int = (v); \
380   if (suppressint == 0 && intpending) \   if (suppress_int == 0 && pending_int) \
381   raise_interrupt(); \   raise_interrupt(); \
382  } while (0)  } while (0)
383    
 /*  
  * Ignore a signal. Only one usage site - in forkchild()  
  */  
 static void  
 ignoresig(int signo)  
 {  
  if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {  
  signal(signo, SIG_IGN);  
  }  
  sigmode[signo - 1] = S_HARD_IGN;  
 }  
   
 /*  
  * Signal handler. Only one usage site - in setsignal()  
  */  
 static void  
 onsig(int signo)  
 {  
  gotsig[signo - 1] = 1;  
   
  if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {  
  if (!suppressint) {  
  pendingsig = 0;  
  raise_interrupt(); /* does not return */  
  }  
  intpending = 1;  
  } else {  
  pendingsig = signo;  
  }  
 }  
   
384    
385  /* ============ Stdout/stderr output */  /* ============ Stdout/stderr output */
386    
# Line 437  static void Line 396  static void
396  flush_stdout_stderr(void)  flush_stdout_stderr(void)
397  {  {
398   INT_OFF;   INT_OFF;
399   fflush(stdout);   fflush_all();
  fflush(stderr);  
  INT_ON;  
 }  
   
 static void  
 flush_stderr(void)  
 {  
  INT_OFF;  
  fflush(stderr);  
400   INT_ON;   INT_ON;
401  }  }
402    
# Line 499  static void Line 449  static void
449  out2str(const char *p)  out2str(const char *p)
450  {  {
451   outstr(p, stderr);   outstr(p, stderr);
452   flush_stderr();   flush_stdout_stderr();
453  }  }
454    
455    
456  /* ============ Parser structures */  /* ============ Parser structures */
457    
458  /* control characters in argument strings */  /* control characters in argument strings */
459  #define CTLESC '\201'           /* escape next character */  #define CTL_FIRST CTLESC
460  #define CTLVAR '\202'           /* variable defn */  #define CTLESC       ((unsigned char)'\201')    /* escape next character */
461  #define CTLENDVAR '\203'  #define CTLVAR       ((unsigned char)'\202')    /* variable defn */
462  #define CTLBACKQ '\204'  #define CTLENDVAR    ((unsigned char)'\203')
463    #define CTLBACKQ     ((unsigned char)'\204')
464  #define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */  #define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
465  /*      CTLBACKQ | CTLQUOTE == '\205' */  /*      CTLBACKQ | CTLQUOTE == '\205' */
466  #define CTLARI  '\206'          /* arithmetic expression */  #define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
467  #define CTLENDARI '\207'  #define CTLENDARI    ((unsigned char)'\207')
468  #define CTLQUOTEMARK '\210'  #define CTLQUOTEMARK ((unsigned char)'\210')
469    #define CTL_LAST CTLQUOTEMARK
470    
471  /* variable substitution byte (follows CTLVAR) */  /* variable substitution byte (follows CTLVAR) */
472  #define VSTYPE  0x0f            /* type of variable substitution */  #define VSTYPE  0x0f            /* type of variable substitution */
# Line 685  union node { Line 637  union node {
637   struct nnot nnot;   struct nnot nnot;
638  };  };
639    
640    /*
641     * NODE_EOF is returned by parsecmd when it encounters an end of file.
642     * It must be distinct from NULL.
643     */
644    #define NODE_EOF ((union node *) -1L)
645    
646  struct nodelist {  struct nodelist {
647   struct nodelist *next;   struct nodelist *next;
648   union node *n;   union node *n;
# Line 724  trace_printf(const char *fmt, ...) Line 682  trace_printf(const char *fmt, ...)
682   if (DEBUG_PID)   if (DEBUG_PID)
683   fprintf(tracefile, "[%u] ", (int) getpid());   fprintf(tracefile, "[%u] ", (int) getpid());
684   if (DEBUG_SIG)   if (DEBUG_SIG)
685   fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);   fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
686   va_start(va, fmt);   va_start(va, fmt);
687   vfprintf(tracefile, fmt, va);   vfprintf(tracefile, fmt, va);
688   va_end(va);   va_end(va);
# Line 740  trace_vprintf(const char *fmt, va_list v Line 698  trace_vprintf(const char *fmt, va_list v
698   if (DEBUG_PID)   if (DEBUG_PID)
699   fprintf(tracefile, "[%u] ", (int) getpid());   fprintf(tracefile, "[%u] ", (int) getpid());
700   if (DEBUG_SIG)   if (DEBUG_SIG)
701   fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);   fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
702   vfprintf(tracefile, fmt, va);   vfprintf(tracefile, fmt, va);
703  }  }
704    
# Line 762  trace_puts_quoted(char *s) Line 720  trace_puts_quoted(char *s)
720   return;   return;
721   putc('"', tracefile);   putc('"', tracefile);
722   for (p = s; *p; p++) {   for (p = s; *p; p++) {
723   switch (*p) {   switch ((unsigned char)*p) {
724   case '\n':  c = 'n';  goto backslash;   case '\n': c = 'n'; goto backslash;
725   case '\t':  c = 't';  goto backslash;   case '\t': c = 't'; goto backslash;
726   case '\r':  c = 'r';  goto backslash;   case '\r': c = 'r'; goto backslash;
727   case '"':  c = '"';  goto backslash;   case '\"': c = '\"'; goto backslash;
728   case '\\':  c = '\\';  goto backslash;   case '\\': c = '\\'; goto backslash;
729   case CTLESC:  c = 'e';  goto backslash;   case CTLESC: c = 'e'; goto backslash;
730   case CTLVAR:  c = 'v';  goto backslash;   case CTLVAR: c = 'v'; goto backslash;
731   case CTLVAR+CTLQUOTE:  c = 'V'; goto backslash;   case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
732   case CTLBACKQ:  c = 'q';  goto backslash;   case CTLBACKQ: c = 'q'; goto backslash;
733   case CTLBACKQ+CTLQUOTE:  c = 'Q'; goto backslash;   case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
734   backslash:   backslash:
735   putc('\\', tracefile);   putc('\\', tracefile);
736   putc(c, tracefile);   putc(c, tracefile);
# Line 782  trace_puts_quoted(char *s) Line 740  trace_puts_quoted(char *s)
740   putc(*p, tracefile);   putc(*p, tracefile);
741   else {   else {
742   putc('\\', tracefile);   putc('\\', tracefile);
743   putc(*p >> 6 & 03, tracefile);   putc((*p >> 6) & 03, tracefile);
744   putc(*p >> 3 & 07, tracefile);   putc((*p >> 3) & 07, tracefile);
745   putc(*p & 07, tracefile);   putc(*p & 07, tracefile);
746   }   }
747   break;   break;
# Line 867  sharg(union node *arg, FILE *fp) Line 825  sharg(union node *arg, FILE *fp)
825  {  {
826   char *p;   char *p;
827   struct nodelist *bqlist;   struct nodelist *bqlist;
828   int subtype;   unsigned char subtype;
829    
830   if (arg->type != NARG) {   if (arg->type != NARG) {
831   out1fmt("<node type %d>\n", arg->type);   out1fmt("<node type %d>\n", arg->type);
# Line 875  sharg(union node *arg, FILE *fp) Line 833  sharg(union node *arg, FILE *fp)
833   }   }
834   bqlist = arg->narg.backquote;   bqlist = arg->narg.backquote;
835   for (p = arg->narg.text; *p; p++) {   for (p = arg->narg.text; *p; p++) {
836   switch (*p) {   switch ((unsigned char)*p) {
837   case CTLESC:   case CTLESC:
838   putc(*++p, fp);   putc(*++p, fp);
839   break;   break;
# Line 999  shtree(union node *n, int ind, char *pfx Line 957  shtree(union node *n, int ind, char *pfx
957   return;   return;
958    
959   indent(ind, pfx, fp);   indent(ind, pfx, fp);
960    
961     if (n == NODE_EOF) {
962     fputs("<EOF>", fp);
963     return;
964     }
965    
966   switch (n->type) {   switch (n->type) {
967   case NSEMI:   case NSEMI:
968   s = "; ";   s = "; ";
# Line 1021  shtree(union node *n, int ind, char *pfx Line 985  shtree(union node *n, int ind, char *pfx
985   break;   break;
986   case NPIPE:   case NPIPE:
987   for (lp = n->npipe.cmdlist; lp; lp = lp->next) {   for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
988   shcmd(lp->n, fp);   shtree(lp->n, 0, NULL, fp);
989   if (lp->next)   if (lp->next)
990   fputs(" | ", fp);   fputs(" | ", fp);
991   }   }
# Line 1042  static void Line 1006  static void
1006  showtree(union node *n)  showtree(union node *n)
1007  {  {
1008   trace_puts("showtree called\n");   trace_puts("showtree called\n");
1009   shtree(n, 1, NULL, stdout);   shtree(n, 1, NULL, stderr);
1010  }  }
1011    
1012  #endif /* DEBUG */  #endif /* DEBUG */
# Line 1062  struct alias; Line 1026  struct alias;
1026    
1027  struct strpush {  struct strpush {
1028   struct strpush *prev;   /* preceding string on stack */   struct strpush *prev;   /* preceding string on stack */
1029   char *prevstring;   char *prev_string;
1030   int prevnleft;   int prev_left_in_line;
1031  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
1032   struct alias *ap;       /* if push was associated with an alias */   struct alias *ap;       /* if push was associated with an alias */
1033  #endif  #endif
# Line 1074  struct parsefile { Line 1038  struct parsefile {
1038   struct parsefile *prev; /* preceding file on stack */   struct parsefile *prev; /* preceding file on stack */
1039   int linno;              /* current line */   int linno;              /* current line */
1040   int fd;                 /* file descriptor (or -1 if string) */   int fd;                 /* file descriptor (or -1 if string) */
1041   int nleft;              /* number of chars left in this line */   int left_in_line;       /* number of chars left in this line */
1042   int lleft;              /* number of chars left in this buffer */   int left_in_buffer;     /* number of chars left in this buffer past the line */
1043   char *nextc;            /* next char in buffer */   char *next_to_pgetc;    /* next char in buffer */
1044   char *buf;              /* input buffer */   char *buf;              /* input buffer */
1045   struct strpush *strpush; /* for pushing strings at this level */   struct strpush *strpush; /* for pushing strings at this level */
1046   struct strpush basestrpush; /* so pushing one is fast */   struct strpush basestrpush; /* so pushing one is fast */
# Line 1143  ash_msg_and_raise_error(const char *msg, Line 1107  ash_msg_and_raise_error(const char *msg,
1107   va_end(ap);   va_end(ap);
1108  }  }
1109    
1110    static void raise_error_syntax(const char *) NORETURN;
1111    static void
1112    raise_error_syntax(const char *msg)
1113    {
1114     ash_msg_and_raise_error("syntax error: %s", msg);
1115     /* NOTREACHED */
1116    }
1117    
1118  static void ash_msg_and_raise(int, const char *, ...) NORETURN;  static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1119  static void  static void
1120  ash_msg_and_raise(int cond, const char *msg, ...)  ash_msg_and_raise(int cond, const char *msg, ...)
# Line 1185  errmsg(int e, const char *em) Line 1157  errmsg(int e, const char *em)
1157    
1158  /* ============ Memory allocation */  /* ============ Memory allocation */
1159    
1160    #if 0
1161    /* I consider these wrappers nearly useless:
1162     * ok, they return you to nearest exception handler, but
1163     * how much memory do you leak in the process, making
1164     * memory starvation worse?
1165     */
1166    static void *
1167    ckrealloc(void * p, size_t nbytes)
1168    {
1169     p = realloc(p, nbytes);
1170     if (!p)
1171     ash_msg_and_raise_error(bb_msg_memory_exhausted);
1172     return p;
1173    }
1174    
1175    static void *
1176    ckmalloc(size_t nbytes)
1177    {
1178     return ckrealloc(NULL, nbytes);
1179    }
1180    
1181    static void *
1182    ckzalloc(size_t nbytes)
1183    {
1184     return memset(ckmalloc(nbytes), 0, nbytes);
1185    }
1186    
1187    static char *
1188    ckstrdup(const char *s)
1189    {
1190     char *p = strdup(s);
1191     if (!p)
1192     ash_msg_and_raise_error(bb_msg_memory_exhausted);
1193     return p;
1194    }
1195    #else
1196    /* Using bbox equivalents. They exit if out of memory */
1197    # define ckrealloc xrealloc
1198    # define ckmalloc  xmalloc
1199    # define ckzalloc  xzalloc
1200    # define ckstrdup  xstrdup
1201    #endif
1202    
1203  /*  /*
1204   * It appears that grabstackstr() will barf with such alignments   * It appears that grabstackstr() will barf with such alignments
1205   * because stalloc() will return a string allocated in a new stackblock.   * because stalloc() will return a string allocated in a new stackblock.
# Line 1194  enum { Line 1209  enum {
1209   /* Most machines require the value returned from malloc to be aligned   /* Most machines require the value returned from malloc to be aligned
1210   * in some way.  The following macro will get this right   * in some way.  The following macro will get this right
1211   * on many machines.  */   * on many machines.  */
1212   SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,   SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1213   /* Minimum size of a block */   /* Minimum size of a block */
1214   MINSIZE = SHELL_ALIGN(504),   MINSIZE = SHELL_ALIGN(504),
1215  };  };
# Line 1240  extern struct globals_memstack *const as Line 1255  extern struct globals_memstack *const as
1255   herefd = -1; \   herefd = -1; \
1256  } while (0)  } while (0)
1257    
1258    
1259  #define stackblock()     ((void *)g_stacknxt)  #define stackblock()     ((void *)g_stacknxt)
1260  #define stackblocksize() g_stacknleft  #define stackblocksize() g_stacknleft
1261    
   
 static void *  
 ckrealloc(void * p, size_t nbytes)  
 {  
  p = realloc(p, nbytes);  
  if (!p)  
  ash_msg_and_raise_error(bb_msg_memory_exhausted);  
  return p;  
 }  
   
 static void *  
 ckmalloc(size_t nbytes)  
 {  
  return ckrealloc(NULL, nbytes);  
 }  
   
 static void *  
 ckzalloc(size_t nbytes)  
 {  
  return memset(ckmalloc(nbytes), 0, nbytes);  
 }  
   
 /*  
  * Make a copy of a string in safe storage.  
  */  
 static char *  
 ckstrdup(const char *s)  
 {  
  char *p = strdup(s);  
  if (!p)  
  ash_msg_and_raise_error(bb_msg_memory_exhausted);  
  return p;  
 }  
   
1262  /*  /*
1263   * Parse trees for commands are allocated in lifo order, so we use a stack   * Parse trees for commands are allocated in lifo order, so we use a stack
1264   * to make this more efficient, and also to avoid all sorts of exception   * to make this more efficient, and also to avoid all sorts of exception
# Line 1581  static int Line 1563  static int
1563  number(const char *s)  number(const char *s)
1564  {  {
1565   if (!is_number(s))   if (!is_number(s))
1566   ash_msg_and_raise_error(illnum, s);   ash_msg_and_raise_error(msg_illnum, s);
1567   return atoi(s);   return atoi(s);
1568  }  }
1569    
# Line 1611  single_quote(const char *s) Line 1593  single_quote(const char *s)
1593    
1594   STADJUST(q - p, p);   STADJUST(q - p, p);
1595    
1596   len = strspn(s, "'");   if (*s != '\'')
  if (!len)  
1597   break;   break;
1598     len = 0;
1599     do len++; while (*++s == '\'');
1600    
1601   q = p = makestrspace(len + 3, p);   q = p = makestrspace(len + 3, p);
1602    
1603   *q++ = '"';   *q++ = '"';
1604   q = (char *)memcpy(q, s, len) + len;   q = (char *)memcpy(q, s - len, len) + len;
1605   *q++ = '"';   *q++ = '"';
  s += len;  
1606    
1607   STADJUST(q - p, p);   STADJUST(q - p, p);
1608   } while (*s);   } while (*s);
1609    
1610   USTPUTC(0, p);   USTPUTC('\0', p);
1611    
1612   return stackblock();   return stackblock();
1613  }  }
# Line 1723  freeparam(volatile struct shparam *param Line 1705  freeparam(volatile struct shparam *param
1705  }  }
1706    
1707  #if ENABLE_ASH_GETOPTS  #if ENABLE_ASH_GETOPTS
1708  static void getoptsreset(const char *value);  static void FAST_FUNC getoptsreset(const char *value);
1709  #endif  #endif
1710    
1711  struct var {  struct var {
1712   struct var *next;               /* next entry in hash list */   struct var *next;               /* next entry in hash list */
1713   int flags;                      /* flags are defined above */   int flags;                      /* flags are defined above */
1714   const char *text;               /* name=value */   const char *text;               /* name=value */
1715   void (*func)(const char *);     /* function to be called when  */   void (*func)(const char *) FAST_FUNC; /* function to be called when  */
1716   /* the variable gets set/unset */   /* the variable gets set/unset */
1717  };  };
1718    
# Line 1757  struct localvar { Line 1739  struct localvar {
1739  # define VDYNAMIC       0  # define VDYNAMIC       0
1740  #endif  #endif
1741    
 #ifdef IFS_BROKEN  
 static const char defifsvar[] ALIGN1 = "IFS= \t\n";  
 #define defifs (defifsvar + 4)  
 #else  
 static const char defifs[] ALIGN1 = " \t\n";  
 #endif  
   
1742    
1743  /* Need to be before varinit_data[] */  /* Need to be before varinit_data[] */
1744  #if ENABLE_LOCALE_SUPPORT  #if ENABLE_LOCALE_SUPPORT
1745  static void  static void FAST_FUNC
1746  change_lc_all(const char *value)  change_lc_all(const char *value)
1747  {  {
1748   if (value && *value != '\0')   if (value && *value != '\0')
1749   setlocale(LC_ALL, value);   setlocale(LC_ALL, value);
1750  }  }
1751  static void  static void FAST_FUNC
1752  change_lc_ctype(const char *value)  change_lc_ctype(const char *value)
1753  {  {
1754   if (value && *value != '\0')   if (value && *value != '\0')
# Line 1782  change_lc_ctype(const char *value) Line 1757  change_lc_ctype(const char *value)
1757  #endif  #endif
1758  #if ENABLE_ASH_MAIL  #if ENABLE_ASH_MAIL
1759  static void chkmail(void);  static void chkmail(void);
1760  static void changemail(const char *);  static void changemail(const char *) FAST_FUNC;
1761  #endif  #endif
1762  static void changepath(const char *);  static void changepath(const char *) FAST_FUNC;
1763  #if ENABLE_ASH_RANDOM_SUPPORT  #if ENABLE_ASH_RANDOM_SUPPORT
1764  static void change_random(const char *);  static void change_random(const char *) FAST_FUNC;
1765  #endif  #endif
1766    
1767  static const struct {  static const struct {
1768   int flags;   int flags;
1769   const char *text;   const char *text;
1770   void (*func)(const char *);   void (*func)(const char *) FAST_FUNC;
1771  } varinit_data[] = {  } varinit_data[] = {
 #ifdef IFS_BROKEN  
1772   { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },   { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
 #else  
  { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0"     , NULL            },  
 #endif  
1773  #if ENABLE_ASH_MAIL  #if ENABLE_ASH_MAIL
1774   { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0"    , changemail      },   { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0"    , changemail      },
1775   { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail      },   { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail      },
# Line 1898  extern struct globals_var *const ash_ptr Line 1869  extern struct globals_var *const ash_ptr
1869  #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))  #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
1870    
1871  #if ENABLE_ASH_GETOPTS  #if ENABLE_ASH_GETOPTS
1872  static void  static void FAST_FUNC
1873  getoptsreset(const char *value)  getoptsreset(const char *value)
1874  {  {
1875   shellparam.optind = number(value);   shellparam.optind = number(value);
# Line 1910  getoptsreset(const char *value) Line 1881  getoptsreset(const char *value)
1881   * Return of a legal variable name (a letter or underscore followed by zero or   * Return of a legal variable name (a letter or underscore followed by zero or
1882   * more letters, underscores, and digits).   * more letters, underscores, and digits).
1883   */   */
1884  static char *  static char* FAST_FUNC
1885  endofname(const char *name)  endofname(const char *name)
1886  {  {
1887   char *p;   char *p;
# Line 2017  findvar(struct var **vpp, const char *na Line 1988  findvar(struct var **vpp, const char *na
1988  /*  /*
1989   * Find the value of a variable.  Returns NULL if not set.   * Find the value of a variable.  Returns NULL if not set.
1990   */   */
1991  static char *  static const char* FAST_FUNC
1992  lookupvar(const char *name)  lookupvar(const char *name)
1993  {  {
1994   struct var *v;   struct var *v;
# Line 2043  lookupvar(const char *name) Line 2014  lookupvar(const char *name)
2014  /*  /*
2015   * Search the environment of a builtin command.   * Search the environment of a builtin command.
2016   */   */
2017  static char *  static const char *
2018  bltinlookup(const char *name)  bltinlookup(const char *name)
2019  {  {
2020   struct strlist *sp;   struct strlist *sp;
# Line 2140  setvar(const char *name, const char *val Line 2111  setvar(const char *name, const char *val
2111   INT_ON;   INT_ON;
2112  }  }
2113    
2114    static void FAST_FUNC
2115    setvar2(const char *name, const char *val)
2116    {
2117     setvar(name, val, 0);
2118    }
2119    
2120  #if ENABLE_ASH_GETOPTS  #if ENABLE_ASH_GETOPTS
2121  /*  /*
2122   * Safe version of setvar, returns 1 on success 0 on failure.   * Safe version of setvar, returns 1 on success 0 on failure.
# Line 2261  listvars(int on, int off, char ***end) Line 2238  listvars(int on, int off, char ***end)
2238  /* ============ Path search helper  /* ============ Path search helper
2239   *   *
2240   * The variable path (passed by reference) should be set to the start   * The variable path (passed by reference) should be set to the start
2241   * of the path before the first call; padvance will update   * of the path before the first call; path_advance will update
2242   * this value as it proceeds.  Successive calls to padvance will return   * this value as it proceeds.  Successive calls to path_advance will return
2243   * the possible path expansions in sequence.  If an option (indicated by   * the possible path expansions in sequence.  If an option (indicated by
2244   * a percent sign) appears in the path entry then the global variable   * a percent sign) appears in the path entry then the global variable
2245   * pathopt will be set to point to it; otherwise pathopt will be set to   * pathopt will be set to point to it; otherwise pathopt will be set to
2246   * NULL.   * NULL.
2247   */   */
2248  static const char *pathopt;     /* set by padvance */  static const char *pathopt;     /* set by path_advance */
2249    
2250  static char *  static char *
2251  padvance(const char **path, const char *name)  path_advance(const char **path, const char *name)
2252  {  {
2253   const char *p;   const char *p;
2254   char *q;   char *q;
# Line 2376  setprompt(int whichprompt) Line 2353  setprompt(int whichprompt)
2353  #define CD_PHYSICAL 1  #define CD_PHYSICAL 1
2354  #define CD_PRINT 2  #define CD_PRINT 2
2355    
 static int docd(const char *, int);  
   
2356  static int  static int
2357  cdopt(void)  cdopt(void)
2358  {  {
# Line 2385  cdopt(void) Line 2360  cdopt(void)
2360   int i, j;   int i, j;
2361    
2362   j = 'L';   j = 'L';
2363   while ((i = nextopt("LP"))) {   while ((i = nextopt("LP")) != '\0') {
2364   if (i != j) {   if (i != j) {
2365   flags ^= CD_PHYSICAL;   flags ^= CD_PHYSICAL;
2366   j = i;   j = i;
# Line 2529  docd(const char *dest, int flags) Line 2504  docd(const char *dest, int flags)
2504   return err;   return err;
2505  }  }
2506    
2507  static int  static int FAST_FUNC
2508  cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2509  {  {
2510   const char *dest;   const char *dest;
# Line 2575  cdcmd(int argc UNUSED_PARAM, char **argv Line 2550  cdcmd(int argc UNUSED_PARAM, char **argv
2550   }   }
2551   do {   do {
2552   c = *path;   c = *path;
2553   p = padvance(&path, dest);   p = path_advance(&path, dest);
2554   if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {   if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2555   if (c && c != ':')   if (c && c != ':')
2556   flags |= CD_PRINT;   flags |= CD_PRINT;
# Line 2593  cdcmd(int argc UNUSED_PARAM, char **argv Line 2568  cdcmd(int argc UNUSED_PARAM, char **argv
2568   return 0;   return 0;
2569  }  }
2570    
2571  static int  static int FAST_FUNC
2572  pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2573  {  {
2574   int flags;   int flags;
# Line 2634  pwdcmd(int argc UNUSED_PARAM, char **arg Line 2609  pwdcmd(int argc UNUSED_PARAM, char **arg
2609  #define CSPCL    13             /* these terminate a word */  #define CSPCL    13             /* these terminate a word */
2610  #define CIGN     14             /* character should be ignored */  #define CIGN     14             /* character should be ignored */
2611    
2612    #define PEOF     256
2613  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
2614  #define SYNBASE       130  # define PEOA    257
 #define PEOF         -130  
 #define PEOA         -129  
 #define PEOA_OR_PEOF PEOA  
 #else  
 #define SYNBASE       129  
 #define PEOF         -129  
 #define PEOA_OR_PEOF PEOF  
2615  #endif  #endif
2616    
2617  /* number syntax index */  #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
 #define BASESYNTAX 0    /* not in quotes */  
 #define DQSYNTAX   1    /* in double quotes */  
 #define SQSYNTAX   2    /* in single quotes */  
 #define ARISYNTAX  3    /* in arithmetic */  
 #define PSSYNTAX   4    /* prompt */  
2618    
2619  #if ENABLE_ASH_OPTIMIZE_FOR_SIZE  #if ENABLE_SH_MATH_SUPPORT
2620  #define USE_SIT_FUNCTION  # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2621    #else
2622    # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2623  #endif  #endif
2624    static const uint16_t S_I_T[] = {
 #if ENABLE_ASH_MATH_SUPPORT  
 static const char S_I_T[][4] = {  
2625  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
2626   { CSPCL, CIGN, CIGN, CIGN },            /* 0, PEOA */   SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
2627  #endif  #endif
2628   { CSPCL, CWORD, CWORD, CWORD },         /* 1, ' ' */   SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
2629   { CNL, CNL, CNL, CNL },                 /* 2, \n */   SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
2630   { CWORD, CCTL, CCTL, CWORD },           /* 3, !*-/:=?[]~ */   SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
2631   { CDQUOTE, CENDQUOTE, CWORD, CWORD },   /* 4, '"' */   SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
2632   { CVAR, CVAR, CWORD, CVAR },            /* 5, $ */   SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
2633   { CSQUOTE, CWORD, CENDQUOTE, CWORD },   /* 6, "'" */   SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
2634   { CSPCL, CWORD, CWORD, CLP },           /* 7, ( */   SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
2635   { CSPCL, CWORD, CWORD, CRP },           /* 8, ) */   SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
2636   { CBACK, CBACK, CCTL, CBACK },          /* 9, \ */   SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
2637   { CBQUOTE, CBQUOTE, CWORD, CBQUOTE },   /* 10, ` */   SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
2638   { CENDVAR, CENDVAR, CWORD, CENDVAR },   /* 11, } */   SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
2639  #ifndef USE_SIT_FUNCTION  #if !USE_SIT_FUNCTION
2640   { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */   SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2641   { CWORD, CWORD, CWORD, CWORD },         /* 13, 0-9A-Za-z */   SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
2642   { CCTL, CCTL, CCTL, CCTL }              /* 14, CTLESC ... */   SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
2643  #endif  #endif
2644    #undef SIT_ITEM
2645  };  };
2646  #else  /* Constants below must match table above */
2647  static const char S_I_T[][3] = {  enum {
2648  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
2649   { CSPCL, CIGN, CIGN },                  /* 0, PEOA */   CSPCL_CIGN_CIGN_CIGN               , /*  0 */
 #endif  
  { CSPCL, CWORD, CWORD },                /* 1, ' ' */  
  { CNL, CNL, CNL },                      /* 2, \n */  
  { CWORD, CCTL, CCTL },                  /* 3, !*-/:=?[]~ */  
  { CDQUOTE, CENDQUOTE, CWORD },          /* 4, '"' */  
  { CVAR, CVAR, CWORD },                  /* 5, $ */  
  { CSQUOTE, CWORD, CENDQUOTE },          /* 6, "'" */  
  { CSPCL, CWORD, CWORD },                /* 7, ( */  
  { CSPCL, CWORD, CWORD },                /* 8, ) */  
  { CBACK, CBACK, CCTL },                 /* 9, \ */  
  { CBQUOTE, CBQUOTE, CWORD },            /* 10, ` */  
  { CENDVAR, CENDVAR, CWORD },            /* 11, } */  
 #ifndef USE_SIT_FUNCTION  
  { CENDFILE, CENDFILE, CENDFILE },       /* 12, PEOF */  
  { CWORD, CWORD, CWORD },                /* 13, 0-9A-Za-z */  
  { CCTL, CCTL, CCTL }                    /* 14, CTLESC ... */  
2650  #endif  #endif
2651     CSPCL_CWORD_CWORD_CWORD            , /*  1 */
2652     CNL_CNL_CNL_CNL                    , /*  2 */
2653     CWORD_CCTL_CCTL_CWORD              , /*  3 */
2654     CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
2655     CVAR_CVAR_CWORD_CVAR               , /*  5 */
2656     CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
2657     CSPCL_CWORD_CWORD_CLP              , /*  7 */
2658     CSPCL_CWORD_CWORD_CRP              , /*  8 */
2659     CBACK_CBACK_CCTL_CBACK             , /*  9 */
2660     CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
2661     CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
2662     CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2663     CWORD_CWORD_CWORD_CWORD            , /* 13 */
2664     CCTL_CCTL_CCTL_CCTL                , /* 14 */
2665  };  };
 #endif /* ASH_MATH_SUPPORT */  
2666    
2667  #ifdef USE_SIT_FUNCTION  /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2668     * caller must ensure proper cast on it if c is *char_ptr!
2669     */
2670    /* Values for syntax param */
2671    #define BASESYNTAX 0    /* not in quotes */
2672    #define DQSYNTAX   1    /* in double quotes */
2673    #define SQSYNTAX   2    /* in single quotes */
2674    #define ARISYNTAX  3    /* in arithmetic */
2675    #define PSSYNTAX   4    /* prompt. never passed to SIT() */
2676    
2677    #if USE_SIT_FUNCTION
2678    
2679  static int  static int
2680  SIT(int c, int syntax)  SIT(int c, int syntax)
2681  {  {
2682   static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";   static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2683  #if ENABLE_ASH_ALIAS  # if ENABLE_ASH_ALIAS
2684   static const char syntax_index_table[] ALIGN1 = {   static const uint8_t syntax_index_table[] ALIGN1 = {
2685   1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */   1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
2686   7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */   7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
2687   3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */   3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
2688   11, 3                           /* "}~" */   11, 3                           /* "}~" */
2689   };   };
2690  #else  # else
2691   static const char syntax_index_table[] ALIGN1 = {   static const uint8_t syntax_index_table[] ALIGN1 = {
2692   0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */   0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
2693   6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */   6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
2694   2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */   2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
2695   10, 2                           /* "}~" */   10, 2                           /* "}~" */
2696   };   };
2697  #endif  # endif
2698   const char *s;   const char *s;
2699   int indx;   int indx;
2700    
2701   if (c == PEOF)          /* 2^8+2 */   if (c == PEOF)
2702   return CENDFILE;   return CENDFILE;
2703  #if ENABLE_ASH_ALIAS  # if ENABLE_ASH_ALIAS
2704   if (c == PEOA)          /* 2^8+1 */   if (c == PEOA)
2705   indx = 0;   indx = 0;
2706   else   else
2707  #endif  # endif
2708     {
2709   if ((unsigned char)c >= (unsigned char)(CTLESC)   /* Cast is purely for paranoia here,
2710   && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)   * just in case someone passed signed char to us */
2711   ) {   if ((unsigned char)c >= CTL_FIRST
2712   return CCTL;   && (unsigned char)c <= CTL_LAST
2713   } else {   ) {
2714     return CCTL;
2715     }
2716   s = strchrnul(spec_symbls, c);   s = strchrnul(spec_symbls, c);
2717   if (*s == '\0')   if (*s == '\0')
2718   return CWORD;   return CWORD;
2719   indx = syntax_index_table[s - spec_symbls];   indx = syntax_index_table[s - spec_symbls];
2720   }   }
2721   return S_I_T[indx][syntax];   return (S_I_T[indx] >> (syntax*4)) & 0xf;
2722  }  }
2723    
2724  #else   /* !USE_SIT_FUNCTION */  #else   /* !USE_SIT_FUNCTION */
2725    
2726  #if ENABLE_ASH_ALIAS  static const uint8_t syntax_index_table[] = {
 #define CSPCL_CIGN_CIGN_CIGN                     0  
 #define CSPCL_CWORD_CWORD_CWORD                  1  
 #define CNL_CNL_CNL_CNL                          2  
 #define CWORD_CCTL_CCTL_CWORD                    3  
 #define CDQUOTE_CENDQUOTE_CWORD_CWORD            4  
 #define CVAR_CVAR_CWORD_CVAR                     5  
 #define CSQUOTE_CWORD_CENDQUOTE_CWORD            6  
 #define CSPCL_CWORD_CWORD_CLP                    7  
 #define CSPCL_CWORD_CWORD_CRP                    8  
 #define CBACK_CBACK_CCTL_CBACK                   9  
 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE           10  
 #define CENDVAR_CENDVAR_CWORD_CENDVAR           11  
 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE     12  
 #define CWORD_CWORD_CWORD_CWORD                 13  
 #define CCTL_CCTL_CCTL_CCTL                     14  
 #else  
 #define CSPCL_CWORD_CWORD_CWORD                  0  
 #define CNL_CNL_CNL_CNL                          1  
 #define CWORD_CCTL_CCTL_CWORD                    2  
 #define CDQUOTE_CENDQUOTE_CWORD_CWORD            3  
 #define CVAR_CVAR_CWORD_CVAR                     4  
 #define CSQUOTE_CWORD_CENDQUOTE_CWORD            5  
 #define CSPCL_CWORD_CWORD_CLP                    6  
 #define CSPCL_CWORD_CWORD_CRP                    7  
 #define CBACK_CBACK_CCTL_CBACK                   8  
 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE            9  
 #define CENDVAR_CENDVAR_CWORD_CENDVAR           10  
 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE     11  
 #define CWORD_CWORD_CWORD_CWORD                 12  
 #define CCTL_CCTL_CCTL_CCTL                     13  
 #endif  
   
 static const char syntax_index_table[258] = {  
2727   /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */   /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2728   /*   0  PEOF */      CENDFILE_CENDFILE_CENDFILE_CENDFILE,   /*   0      */ CWORD_CWORD_CWORD_CWORD,
2729  #if ENABLE_ASH_ALIAS   /*   1      */ CWORD_CWORD_CWORD_CWORD,
2730   /*   1  PEOA */      CSPCL_CIGN_CIGN_CIGN,   /*   2      */ CWORD_CWORD_CWORD_CWORD,
2731  #endif   /*   3      */ CWORD_CWORD_CWORD_CWORD,
2732   /*   2  -128 0x80 */ CWORD_CWORD_CWORD_CWORD,   /*   4      */ CWORD_CWORD_CWORD_CWORD,
2733   /*   3  -127 CTLESC       */ CCTL_CCTL_CCTL_CCTL,   /*   5      */ CWORD_CWORD_CWORD_CWORD,
2734   /*   4  -126 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,   /*   6      */ CWORD_CWORD_CWORD_CWORD,
2735   /*   5  -125 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,   /*   7      */ CWORD_CWORD_CWORD_CWORD,
2736   /*   6  -124 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,   /*   8      */ CWORD_CWORD_CWORD_CWORD,
2737   /*   7  -123 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,   /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2738   /*   8  -122 CTLARI       */ CCTL_CCTL_CCTL_CCTL,   /*  10 "\n" */ CNL_CNL_CNL_CNL,
2739   /*   9  -121 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,   /*  11      */ CWORD_CWORD_CWORD_CWORD,
2740   /*  10  -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,   /*  12      */ CWORD_CWORD_CWORD_CWORD,
2741   /*  11  -119      */ CWORD_CWORD_CWORD_CWORD,   /*  13      */ CWORD_CWORD_CWORD_CWORD,
2742   /*  12  -118      */ CWORD_CWORD_CWORD_CWORD,   /*  14      */ CWORD_CWORD_CWORD_CWORD,
2743   /*  13  -117      */ CWORD_CWORD_CWORD_CWORD,   /*  15      */ CWORD_CWORD_CWORD_CWORD,
2744   /*  14  -116      */ CWORD_CWORD_CWORD_CWORD,   /*  16      */ CWORD_CWORD_CWORD_CWORD,
2745   /*  15  -115      */ CWORD_CWORD_CWORD_CWORD,   /*  17      */ CWORD_CWORD_CWORD_CWORD,
2746   /*  16  -114      */ CWORD_CWORD_CWORD_CWORD,   /*  18      */ CWORD_CWORD_CWORD_CWORD,
2747   /*  17  -113      */ CWORD_CWORD_CWORD_CWORD,   /*  19      */ CWORD_CWORD_CWORD_CWORD,
2748   /*  18  -112      */ CWORD_CWORD_CWORD_CWORD,   /*  20      */ CWORD_CWORD_CWORD_CWORD,
2749   /*  19  -111      */ CWORD_CWORD_CWORD_CWORD,   /*  21      */ CWORD_CWORD_CWORD_CWORD,
2750   /*  20  -110      */ CWORD_CWORD_CWORD_CWORD,   /*  22      */ CWORD_CWORD_CWORD_CWORD,
2751   /*  21  -109      */ CWORD_CWORD_CWORD_CWORD,   /*  23      */ CWORD_CWORD_CWORD_CWORD,
2752   /*  22  -108      */ CWORD_CWORD_CWORD_CWORD,   /*  24      */ CWORD_CWORD_CWORD_CWORD,
2753   /*  23  -107      */ CWORD_CWORD_CWORD_CWORD,   /*  25      */ CWORD_CWORD_CWORD_CWORD,
2754   /*  24  -106      */ CWORD_CWORD_CWORD_CWORD,   /*  26      */ CWORD_CWORD_CWORD_CWORD,
2755   /*  25  -105      */ CWORD_CWORD_CWORD_CWORD,   /*  27      */ CWORD_CWORD_CWORD_CWORD,
2756   /*  26  -104      */ CWORD_CWORD_CWORD_CWORD,   /*  28      */ CWORD_CWORD_CWORD_CWORD,
2757   /*  27  -103      */ CWORD_CWORD_CWORD_CWORD,   /*  29      */ CWORD_CWORD_CWORD_CWORD,
2758   /*  28  -102      */ CWORD_CWORD_CWORD_CWORD,   /*  30      */ CWORD_CWORD_CWORD_CWORD,
2759   /*  29  -101      */ CWORD_CWORD_CWORD_CWORD,   /*  31      */ CWORD_CWORD_CWORD_CWORD,
2760   /*  30  -100      */ CWORD_CWORD_CWORD_CWORD,   /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
2761   /*  31   -99      */ CWORD_CWORD_CWORD_CWORD,   /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
2762   /*  32   -98      */ CWORD_CWORD_CWORD_CWORD,   /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2763   /*  33   -97      */ CWORD_CWORD_CWORD_CWORD,   /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
2764   /*  34   -96      */ CWORD_CWORD_CWORD_CWORD,   /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
2765   /*  35   -95      */ CWORD_CWORD_CWORD_CWORD,   /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
2766   /*  36   -94      */ CWORD_CWORD_CWORD_CWORD,   /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
2767   /*  37   -93      */ CWORD_CWORD_CWORD_CWORD,   /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2768   /*  38   -92      */ CWORD_CWORD_CWORD_CWORD,   /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
2769   /*  39   -91      */ CWORD_CWORD_CWORD_CWORD,   /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
2770   /*  40   -90      */ CWORD_CWORD_CWORD_CWORD,   /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
2771   /*  41   -89      */ CWORD_CWORD_CWORD_CWORD,   /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
2772   /*  42   -88      */ CWORD_CWORD_CWORD_CWORD,   /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
2773   /*  43   -87      */ CWORD_CWORD_CWORD_CWORD,   /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
2774   /*  44   -86      */ CWORD_CWORD_CWORD_CWORD,   /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
2775   /*  45   -85      */ CWORD_CWORD_CWORD_CWORD,   /*  47  "/" */ CWORD_CCTL_CCTL_CWORD,
2776   /*  46   -84      */ CWORD_CWORD_CWORD_CWORD,   /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
2777   /*  47   -83      */ CWORD_CWORD_CWORD_CWORD,   /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
2778   /*  48   -82      */ CWORD_CWORD_CWORD_CWORD,   /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
2779   /*  49   -81      */ CWORD_CWORD_CWORD_CWORD,   /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
2780   /*  50   -80      */ CWORD_CWORD_CWORD_CWORD,   /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
2781   /*  51   -79      */ CWORD_CWORD_CWORD_CWORD,   /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
2782   /*  52   -78      */ CWORD_CWORD_CWORD_CWORD,   /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
2783   /*  53   -77      */ CWORD_CWORD_CWORD_CWORD,   /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
2784   /*  54   -76      */ CWORD_CWORD_CWORD_CWORD,   /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
2785   /*  55   -75      */ CWORD_CWORD_CWORD_CWORD,   /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
2786   /*  56   -74      */ CWORD_CWORD_CWORD_CWORD,   /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
2787   /*  57   -73      */ CWORD_CWORD_CWORD_CWORD,   /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
2788   /*  58   -72      */ CWORD_CWORD_CWORD_CWORD,   /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
2789   /*  59   -71      */ CWORD_CWORD_CWORD_CWORD,   /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
2790   /*  60   -70      */ CWORD_CWORD_CWORD_CWORD,   /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
2791   /*  61   -69      */ CWORD_CWORD_CWORD_CWORD,   /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
2792   /*  62   -68      */ CWORD_CWORD_CWORD_CWORD,   /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
2793   /*  63   -67      */ CWORD_CWORD_CWORD_CWORD,   /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
2794   /*  64   -66      */ CWORD_CWORD_CWORD_CWORD,   /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
2795   /*  65   -65      */ CWORD_CWORD_CWORD_CWORD,   /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
2796   /*  66   -64      */ CWORD_CWORD_CWORD_CWORD,   /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
2797   /*  67   -63      */ CWORD_CWORD_CWORD_CWORD,   /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
2798   /*  68   -62      */ CWORD_CWORD_CWORD_CWORD,   /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
2799   /*  69   -61      */ CWORD_CWORD_CWORD_CWORD,   /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
2800   /*  70   -60      */ CWORD_CWORD_CWORD_CWORD,   /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
2801   /*  71   -59      */ CWORD_CWORD_CWORD_CWORD,   /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
2802   /*  72   -58      */ CWORD_CWORD_CWORD_CWORD,   /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
2803   /*  73   -57      */ CWORD_CWORD_CWORD_CWORD,   /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
2804   /*  74   -56      */ CWORD_CWORD_CWORD_CWORD,   /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
2805   /*  75   -55      */ CWORD_CWORD_CWORD_CWORD,   /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
2806   /*  76   -54      */ CWORD_CWORD_CWORD_CWORD,   /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
2807   /*  77   -53      */ CWORD_CWORD_CWORD_CWORD,   /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
2808   /*  78   -52      */ CWORD_CWORD_CWORD_CWORD,   /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
2809   /*  79   -51      */ CWORD_CWORD_CWORD_CWORD,   /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
2810   /*  80   -50      */ CWORD_CWORD_CWORD_CWORD,   /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
2811   /*  81   -49      */ CWORD_CWORD_CWORD_CWORD,   /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
2812   /*  82   -48      */ CWORD_CWORD_CWORD_CWORD,   /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
2813   /*  83   -47      */ CWORD_CWORD_CWORD_CWORD,   /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
2814   /*  84   -46      */ CWORD_CWORD_CWORD_CWORD,   /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
2815   /*  85   -45      */ CWORD_CWORD_CWORD_CWORD,   /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
2816   /*  86   -44      */ CWORD_CWORD_CWORD_CWORD,   /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
2817   /*  87   -43      */ CWORD_CWORD_CWORD_CWORD,   /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
2818   /*  88   -42      */ CWORD_CWORD_CWORD_CWORD,   /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
2819   /*  89   -41      */ CWORD_CWORD_CWORD_CWORD,   /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
2820   /*  90   -40      */ CWORD_CWORD_CWORD_CWORD,   /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
2821   /*  91   -39      */ CWORD_CWORD_CWORD_CWORD,   /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
2822   /*  92   -38      */ CWORD_CWORD_CWORD_CWORD,   /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
2823   /*  93   -37      */ CWORD_CWORD_CWORD_CWORD,   /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
2824   /*  94   -36      */ CWORD_CWORD_CWORD_CWORD,   /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2825   /*  95   -35      */ CWORD_CWORD_CWORD_CWORD,   /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
2826   /*  96   -34      */ CWORD_CWORD_CWORD_CWORD,   /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
2827   /*  97   -33      */ CWORD_CWORD_CWORD_CWORD,   /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
2828   /*  98   -32      */ CWORD_CWORD_CWORD_CWORD,   /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
2829   /*  99   -31      */ CWORD_CWORD_CWORD_CWORD,   /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
2830   /* 100   -30      */ CWORD_CWORD_CWORD_CWORD,   /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
2831   /* 101   -29      */ CWORD_CWORD_CWORD_CWORD,   /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
2832   /* 102   -28      */ CWORD_CWORD_CWORD_CWORD,   /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
2833   /* 103   -27      */ CWORD_CWORD_CWORD_CWORD,   /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
2834   /* 104   -26      */ CWORD_CWORD_CWORD_CWORD,   /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
2835   /* 105   -25      */ CWORD_CWORD_CWORD_CWORD,   /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
2836   /* 106   -24      */ CWORD_CWORD_CWORD_CWORD,   /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
2837   /* 107   -23      */ CWORD_CWORD_CWORD_CWORD,   /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
2838   /* 108   -22      */ CWORD_CWORD_CWORD_CWORD,   /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
2839   /* 109   -21      */ CWORD_CWORD_CWORD_CWORD,   /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
2840   /* 110   -20      */ CWORD_CWORD_CWORD_CWORD,   /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
2841   /* 111   -19      */ CWORD_CWORD_CWORD_CWORD,   /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
2842   /* 112   -18      */ CWORD_CWORD_CWORD_CWORD,   /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
2843   /* 113   -17      */ CWORD_CWORD_CWORD_CWORD,   /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
2844   /* 114   -16      */ CWORD_CWORD_CWORD_CWORD,   /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
2845   /* 115   -15      */ CWORD_CWORD_CWORD_CWORD,   /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
2846   /* 116   -14      */ CWORD_CWORD_CWORD_CWORD,   /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
2847   /* 117   -13      */ CWORD_CWORD_CWORD_CWORD,   /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
2848   /* 118   -12      */ CWORD_CWORD_CWORD_CWORD,   /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
2849   /* 119   -11      */ CWORD_CWORD_CWORD_CWORD,   /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
2850   /* 120   -10      */ CWORD_CWORD_CWORD_CWORD,   /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
2851   /* 121    -9      */ CWORD_CWORD_CWORD_CWORD,   /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
2852   /* 122    -8      */ CWORD_CWORD_CWORD_CWORD,   /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
2853   /* 123    -7      */ CWORD_CWORD_CWORD_CWORD,   /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2854   /* 124    -6      */ CWORD_CWORD_CWORD_CWORD,   /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
2855   /* 125    -5      */ CWORD_CWORD_CWORD_CWORD,   /* 127  del */ CWORD_CWORD_CWORD_CWORD,
2856   /* 126    -4      */ CWORD_CWORD_CWORD_CWORD,   /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2857   /* 127    -3      */ CWORD_CWORD_CWORD_CWORD,   /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
2858   /* 128    -2      */ CWORD_CWORD_CWORD_CWORD,   /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
2859   /* 129    -1      */ CWORD_CWORD_CWORD_CWORD,   /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
2860   /* 130     0      */ CWORD_CWORD_CWORD_CWORD,   /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
2861   /* 131     1      */ CWORD_CWORD_CWORD_CWORD,   /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
2862   /* 132     2      */ CWORD_CWORD_CWORD_CWORD,   /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
2863   /* 133     3      */ CWORD_CWORD_CWORD_CWORD,   /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
2864   /* 134     4      */ CWORD_CWORD_CWORD_CWORD,   /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2865   /* 135     5      */ CWORD_CWORD_CWORD_CWORD,   /* 137      */ CWORD_CWORD_CWORD_CWORD,
2866   /* 136     6      */ CWORD_CWORD_CWORD_CWORD,   /* 138      */ CWORD_CWORD_CWORD_CWORD,
2867   /* 137     7      */ CWORD_CWORD_CWORD_CWORD,   /* 139      */ CWORD_CWORD_CWORD_CWORD,
2868   /* 138     8      */ CWORD_CWORD_CWORD_CWORD,   /* 140      */ CWORD_CWORD_CWORD_CWORD,
2869   /* 139     9 "\t" */ CSPCL_CWORD_CWORD_CWORD,   /* 141      */ CWORD_CWORD_CWORD_CWORD,
2870   /* 140    10 "\n" */ CNL_CNL_CNL_CNL,   /* 142      */ CWORD_CWORD_CWORD_CWORD,
2871   /* 141    11      */ CWORD_CWORD_CWORD_CWORD,   /* 143      */ CWORD_CWORD_CWORD_CWORD,
2872   /* 142    12      */ CWORD_CWORD_CWORD_CWORD,   /* 144      */ CWORD_CWORD_CWORD_CWORD,
2873   /* 143    13      */ CWORD_CWORD_CWORD_CWORD,   /* 145      */ CWORD_CWORD_CWORD_CWORD,
2874   /* 144    14      */ CWORD_CWORD_CWORD_CWORD,   /* 146      */ CWORD_CWORD_CWORD_CWORD,
2875   /* 145    15      */ CWORD_CWORD_CWORD_CWORD,   /* 147      */ CWORD_CWORD_CWORD_CWORD,
2876   /* 146    16      */ CWORD_CWORD_CWORD_CWORD,   /* 148      */ CWORD_CWORD_CWORD_CWORD,
2877   /* 147    17      */ CWORD_CWORD_CWORD_CWORD,   /* 149      */ CWORD_CWORD_CWORD_CWORD,
2878   /* 148    18      */ CWORD_CWORD_CWORD_CWORD,   /* 150      */ CWORD_CWORD_CWORD_CWORD,
2879   /* 149    19      */ CWORD_CWORD_CWORD_CWORD,   /* 151      */ CWORD_CWORD_CWORD_CWORD,
2880   /* 150    20      */ CWORD_CWORD_CWORD_CWORD,   /* 152      */ CWORD_CWORD_CWORD_CWORD,
2881   /* 151    21      */ CWORD_CWORD_CWORD_CWORD,   /* 153      */ CWORD_CWORD_CWORD_CWORD,
2882   /* 152    22      */ CWORD_CWORD_CWORD_CWORD,   /* 154      */ CWORD_CWORD_CWORD_CWORD,
2883   /* 153    23      */ CWORD_CWORD_CWORD_CWORD,   /* 155      */ CWORD_CWORD_CWORD_CWORD,
2884   /* 154    24      */ CWORD_CWORD_CWORD_CWORD,   /* 156      */ CWORD_CWORD_CWORD_CWORD,
2885   /* 155    25      */ CWORD_CWORD_CWORD_CWORD,   /* 157      */ CWORD_CWORD_CWORD_CWORD,
2886   /* 156    26      */ CWORD_CWORD_CWORD_CWORD,   /* 158      */ CWORD_CWORD_CWORD_CWORD,
2887   /* 157    27      */ CWORD_CWORD_CWORD_CWORD,   /* 159      */ CWORD_CWORD_CWORD_CWORD,
2888   /* 158    28      */ CWORD_CWORD_CWORD_CWORD,   /* 160      */ CWORD_CWORD_CWORD_CWORD,
2889   /* 159    29      */ CWORD_CWORD_CWORD_CWORD,   /* 161      */ CWORD_CWORD_CWORD_CWORD,
2890   /* 160    30      */ CWORD_CWORD_CWORD_CWORD,   /* 162      */ CWORD_CWORD_CWORD_CWORD,
2891   /* 161    31      */ CWORD_CWORD_CWORD_CWORD,   /* 163      */ CWORD_CWORD_CWORD_CWORD,
2892   /* 162    32  " " */ CSPCL_CWORD_CWORD_CWORD,   /* 164      */ CWORD_CWORD_CWORD_CWORD,
2893   /* 163    33  "!" */ CWORD_CCTL_CCTL_CWORD,   /* 165      */ CWORD_CWORD_CWORD_CWORD,
2894   /* 164    34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,   /* 166      */ CWORD_CWORD_CWORD_CWORD,
2895   /* 165    35  "#" */ CWORD_CWORD_CWORD_CWORD,   /* 167      */ CWORD_CWORD_CWORD_CWORD,
2896   /* 166    36  "$" */ CVAR_CVAR_CWORD_CVAR,   /* 168      */ CWORD_CWORD_CWORD_CWORD,
2897   /* 167    37  "%" */ CWORD_CWORD_CWORD_CWORD,   /* 169      */ CWORD_CWORD_CWORD_CWORD,
2898   /* 168    38  "&" */ CSPCL_CWORD_CWORD_CWORD,   /* 170      */ CWORD_CWORD_CWORD_CWORD,
2899   /* 169    39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,   /* 171      */ CWORD_CWORD_CWORD_CWORD,
2900   /* 170    40  "(" */ CSPCL_CWORD_CWORD_CLP,   /* 172      */ CWORD_CWORD_CWORD_CWORD,
2901   /* 171    41  ")" */ CSPCL_CWORD_CWORD_CRP,   /* 173      */ CWORD_CWORD_CWORD_CWORD,
2902   /* 172    42  "*" */ CWORD_CCTL_CCTL_CWORD,   /* 174      */ CWORD_CWORD_CWORD_CWORD,
2903   /* 173    43  "+" */ CWORD_CWORD_CWORD_CWORD,   /* 175      */ CWORD_CWORD_CWORD_CWORD,
2904   /* 174    44  "," */ CWORD_CWORD_CWORD_CWORD,   /* 176      */ CWORD_CWORD_CWORD_CWORD,
2905   /* 175    45  "-" */ CWORD_CCTL_CCTL_CWORD,   /* 177      */ CWORD_CWORD_CWORD_CWORD,
2906   /* 176    46  "." */ CWORD_CWORD_CWORD_CWORD,   /* 178      */ CWORD_CWORD_CWORD_CWORD,
2907   /* 177    47  "/" */ CWORD_CCTL_CCTL_CWORD,   /* 179      */ CWORD_CWORD_CWORD_CWORD,
2908   /* 178    48  "0" */ CWORD_CWORD_CWORD_CWORD,   /* 180      */ CWORD_CWORD_CWORD_CWORD,
2909   /* 179    49  "1" */ CWORD_CWORD_CWORD_CWORD,   /* 181      */ CWORD_CWORD_CWORD_CWORD,
2910   /* 180    50  "2" */ CWORD_CWORD_CWORD_CWORD,   /* 182      */ CWORD_CWORD_CWORD_CWORD,
2911   /* 181    51  "3" */ CWORD_CWORD_CWORD_CWORD,   /* 183      */ CWORD_CWORD_CWORD_CWORD,
2912   /* 182    52  "4" */ CWORD_CWORD_CWORD_CWORD,   /* 184      */ CWORD_CWORD_CWORD_CWORD,
2913   /* 183    53  "5" */ CWORD_CWORD_CWORD_CWORD,   /* 185      */ CWORD_CWORD_CWORD_CWORD,
2914   /* 184    54  "6" */ CWORD_CWORD_CWORD_CWORD,   /* 186      */ CWORD_CWORD_CWORD_CWORD,
2915   /* 185    55  "7" */ CWORD_CWORD_CWORD_CWORD,   /* 187      */ CWORD_CWORD_CWORD_CWORD,
2916   /* 186    56  "8" */ CWORD_CWORD_CWORD_CWORD,   /* 188      */ CWORD_CWORD_CWORD_CWORD,
2917   /* 187    57  "9" */ CWORD_CWORD_CWORD_CWORD,   /* 189      */ CWORD_CWORD_CWORD_CWORD,
2918   /* 188    58  ":" */ CWORD_CCTL_CCTL_CWORD,   /* 190      */ CWORD_CWORD_CWORD_CWORD,
2919   /* 189    59  ";" */ CSPCL_CWORD_CWORD_CWORD,   /* 191      */ CWORD_CWORD_CWORD_CWORD,
2920   /* 190    60  "<" */ CSPCL_CWORD_CWORD_CWORD,   /* 192      */ CWORD_CWORD_CWORD_CWORD,
2921   /* 191    61  "=" */ CWORD_CCTL_CCTL_CWORD,   /* 193      */ CWORD_CWORD_CWORD_CWORD,
2922   /* 192    62  ">" */ CSPCL_CWORD_CWORD_CWORD,   /* 194      */ CWORD_CWORD_CWORD_CWORD,
2923   /* 193    63  "?" */ CWORD_CCTL_CCTL_CWORD,   /* 195      */ CWORD_CWORD_CWORD_CWORD,
2924   /* 194    64  "@" */ CWORD_CWORD_CWORD_CWORD,   /* 196      */ CWORD_CWORD_CWORD_CWORD,
2925   /* 195    65  "A" */ CWORD_CWORD_CWORD_CWORD,   /* 197      */ CWORD_CWORD_CWORD_CWORD,
2926   /* 196    66  "B" */ CWORD_CWORD_CWORD_CWORD,   /* 198      */ CWORD_CWORD_CWORD_CWORD,
2927   /* 197    67  "C" */ CWORD_CWORD_CWORD_CWORD,   /* 199      */ CWORD_CWORD_CWORD_CWORD,
2928   /* 198    68  "D" */ CWORD_CWORD_CWORD_CWORD,   /* 200      */ CWORD_CWORD_CWORD_CWORD,
2929   /* 199    69  "E" */ CWORD_CWORD_CWORD_CWORD,   /* 201      */ CWORD_CWORD_CWORD_CWORD,
2930   /* 200    70  "F" */ CWORD_CWORD_CWORD_CWORD,   /* 202      */ CWORD_CWORD_CWORD_CWORD,
2931   /* 201    71  "G" */ CWORD_CWORD_CWORD_CWORD,   /* 203      */ CWORD_CWORD_CWORD_CWORD,
2932   /* 202    72  "H" */ CWORD_CWORD_CWORD_CWORD,   /* 204      */ CWORD_CWORD_CWORD_CWORD,
2933   /* 203    73  "I" */ CWORD_CWORD_CWORD_CWORD,   /* 205      */ CWORD_CWORD_CWORD_CWORD,
2934   /* 204    74  "J" */ CWORD_CWORD_CWORD_CWORD,   /* 206      */ CWORD_CWORD_CWORD_CWORD,
2935   /* 205    75  "K" */ CWORD_CWORD_CWORD_CWORD,   /* 207      */ CWORD_CWORD_CWORD_CWORD,
2936   /* 206    76  "L" */ CWORD_CWORD_CWORD_CWORD,   /* 208      */ CWORD_CWORD_CWORD_CWORD,
2937   /* 207    77  "M" */ CWORD_CWORD_CWORD_CWORD,   /* 209      */ CWORD_CWORD_CWORD_CWORD,
2938   /* 208    78  "N" */ CWORD_CWORD_CWORD_CWORD,   /* 210      */ CWORD_CWORD_CWORD_CWORD,
2939   /* 209    79  "O" */ CWORD_CWORD_CWORD_CWORD,   /* 211      */ CWORD_CWORD_CWORD_CWORD,
2940   /* 210    80  "P" */ CWORD_CWORD_CWORD_CWORD,   /* 212      */ CWORD_CWORD_CWORD_CWORD,
2941   /* 211    81  "Q" */ CWORD_CWORD_CWORD_CWORD,   /* 213      */ CWORD_CWORD_CWORD_CWORD,
2942   /* 212    82  "R" */ CWORD_CWORD_CWORD_CWORD,   /* 214      */ CWORD_CWORD_CWORD_CWORD,
2943   /* 213    83  "S" */ CWORD_CWORD_CWORD_CWORD,   /* 215      */ CWORD_CWORD_CWORD_CWORD,
2944   /* 214    84  "T" */ CWORD_CWORD_CWORD_CWORD,   /* 216      */ CWORD_CWORD_CWORD_CWORD,
2945   /* 215    85  "U" */ CWORD_CWORD_CWORD_CWORD,   /* 217      */ CWORD_CWORD_CWORD_CWORD,
2946   /* 216    86  "V" */ CWORD_CWORD_CWORD_CWORD,   /* 218      */ CWORD_CWORD_CWORD_CWORD,
2947   /* 217    87  "W" */ CWORD_CWORD_CWORD_CWORD,   /* 219      */ CWORD_CWORD_CWORD_CWORD,
2948   /* 218    88  "X" */ CWORD_CWORD_CWORD_CWORD,   /* 220      */ CWORD_CWORD_CWORD_CWORD,
2949   /* 219    89  "Y" */ CWORD_CWORD_CWORD_CWORD,   /* 221      */ CWORD_CWORD_CWORD_CWORD,
2950   /* 220    90  "Z" */ CWORD_CWORD_CWORD_CWORD,   /* 222      */ CWORD_CWORD_CWORD_CWORD,
2951   /* 221    91  "[" */ CWORD_CCTL_CCTL_CWORD,   /* 223      */ CWORD_CWORD_CWORD_CWORD,
2952   /* 222    92  "\" */ CBACK_CBACK_CCTL_CBACK,   /* 224      */ CWORD_CWORD_CWORD_CWORD,
2953   /* 223    93  "]" */ CWORD_CCTL_CCTL_CWORD,   /* 225      */ CWORD_CWORD_CWORD_CWORD,
2954   /* 224    94  "^" */ CWORD_CWORD_CWORD_CWORD,   /* 226      */ CWORD_CWORD_CWORD_CWORD,
2955   /* 225    95  "_" */ CWORD_CWORD_CWORD_CWORD,   /* 227      */ CWORD_CWORD_CWORD_CWORD,
2956   /* 226    96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,   /* 228      */ CWORD_CWORD_CWORD_CWORD,
2957   /* 227    97  "a" */ CWORD_CWORD_CWORD_CWORD,   /* 229      */ CWORD_CWORD_CWORD_CWORD,
2958   /* 228    98  "b" */ CWORD_CWORD_CWORD_CWORD,   /* 230      */ CWORD_CWORD_CWORD_CWORD,
2959   /* 229    99  "c" */ CWORD_CWORD_CWORD_CWORD,   /* 231      */ CWORD_CWORD_CWORD_CWORD,
2960   /* 230   100  "d" */ CWORD_CWORD_CWORD_CWORD,   /* 232      */ CWORD_CWORD_CWORD_CWORD,
2961   /* 231   101  "e" */ CWORD_CWORD_CWORD_CWORD,   /* 233      */ CWORD_CWORD_CWORD_CWORD,
2962   /* 232   102  "f" */ CWORD_CWORD_CWORD_CWORD,   /* 234      */ CWORD_CWORD_CWORD_CWORD,
2963   /* 233   103  "g" */ CWORD_CWORD_CWORD_CWORD,   /* 235      */ CWORD_CWORD_CWORD_CWORD,
2964   /* 234   104  "h" */ CWORD_CWORD_CWORD_CWORD,   /* 236      */ CWORD_CWORD_CWORD_CWORD,
2965   /* 235   105  "i" */ CWORD_CWORD_CWORD_CWORD,   /* 237      */ CWORD_CWORD_CWORD_CWORD,
2966   /* 236   106  "j" */ CWORD_CWORD_CWORD_CWORD,   /* 238      */ CWORD_CWORD_CWORD_CWORD,
2967   /* 237   107  "k" */ CWORD_CWORD_CWORD_CWORD,   /* 239      */ CWORD_CWORD_CWORD_CWORD,
2968   /* 238   108  "l" */ CWORD_CWORD_CWORD_CWORD,   /* 230      */ CWORD_CWORD_CWORD_CWORD,
2969   /* 239   109  "m" */ CWORD_CWORD_CWORD_CWORD,   /* 241      */ CWORD_CWORD_CWORD_CWORD,
2970   /* 240   110  "n" */ CWORD_CWORD_CWORD_CWORD,   /* 242      */ CWORD_CWORD_CWORD_CWORD,
2971   /* 241   111  "o" */ CWORD_CWORD_CWORD_CWORD,   /* 243      */ CWORD_CWORD_CWORD_CWORD,
2972   /* 242   112  "p" */ CWORD_CWORD_CWORD_CWORD,   /* 244      */ CWORD_CWORD_CWORD_CWORD,
2973   /* 243   113  "q" */ CWORD_CWORD_CWORD_CWORD,   /* 245      */ CWORD_CWORD_CWORD_CWORD,
2974   /* 244   114  "r" */ CWORD_CWORD_CWORD_CWORD,   /* 246      */ CWORD_CWORD_CWORD_CWORD,
2975   /* 245   115  "s" */ CWORD_CWORD_CWORD_CWORD,   /* 247      */ CWORD_CWORD_CWORD_CWORD,
2976   /* 246   116  "t" */ CWORD_CWORD_CWORD_CWORD,   /* 248      */ CWORD_CWORD_CWORD_CWORD,
2977   /* 247   117  "u" */ CWORD_CWORD_CWORD_CWORD,   /* 249      */ CWORD_CWORD_CWORD_CWORD,
2978   /* 248   118  "v" */ CWORD_CWORD_CWORD_CWORD,   /* 250      */ CWORD_CWORD_CWORD_CWORD,
2979   /* 249   119  "w" */ CWORD_CWORD_CWORD_CWORD,   /* 251      */ CWORD_CWORD_CWORD_CWORD,
2980   /* 250   120  "x" */ CWORD_CWORD_CWORD_CWORD,   /* 252      */ CWORD_CWORD_CWORD_CWORD,
2981   /* 251   121  "y" */ CWORD_CWORD_CWORD_CWORD,   /* 253      */ CWORD_CWORD_CWORD_CWORD,
2982   /* 252   122  "z" */ CWORD_CWORD_CWORD_CWORD,   /* 254      */ CWORD_CWORD_CWORD_CWORD,
2983   /* 253   123  "{" */ CWORD_CWORD_CWORD_CWORD,   /* 255      */ CWORD_CWORD_CWORD_CWORD,
2984   /* 254   124  "|" */ CSPCL_CWORD_CWORD_CWORD,   /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2985   /* 255   125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,  # if ENABLE_ASH_ALIAS
2986   /* 256   126  "~" */ CWORD_CCTL_CCTL_CWORD,   /* PEOA */     CSPCL_CIGN_CIGN_CIGN,
2987   /* 257   127      */ CWORD_CWORD_CWORD_CWORD,  # endif
2988  };  };
2989    
2990  #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])  # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
2991    
2992  #endif  /* USE_SIT_FUNCTION */  #endif  /* !USE_SIT_FUNCTION */
2993    
2994    
2995  /* ============ Alias handling */  /* ============ Alias handling */
# Line 3196  printalias(const struct alias *ap) Line 3137  printalias(const struct alias *ap)
3137  /*  /*
3138   * TODO - sort output   * TODO - sort output
3139   */   */
3140  static int  static int FAST_FUNC
3141  aliascmd(int argc UNUSED_PARAM, char **argv)  aliascmd(int argc UNUSED_PARAM, char **argv)
3142  {  {
3143   char *n, *v;   char *n, *v;
# Line 3231  aliascmd(int argc UNUSED_PARAM, char **a Line 3172  aliascmd(int argc UNUSED_PARAM, char **a
3172   return ret;   return ret;
3173  }  }
3174    
3175  static int  static int FAST_FUNC
3176  unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3177  {  {
3178   int i;   int i;
# Line 3258  unaliascmd(int argc UNUSED_PARAM, char * Line 3199  unaliascmd(int argc UNUSED_PARAM, char *
3199  /* ============ jobs.c */  /* ============ jobs.c */
3200    
3201  /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */  /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
3202  #define FORK_FG 0  #define FORK_FG    0
3203  #define FORK_BG 1  #define FORK_BG    1
3204  #define FORK_NOJOB 2  #define FORK_NOJOB 2
3205    
3206  /* mode flags for showjob(s) */  /* mode flags for showjob(s) */
3207  #define SHOW_PGID       0x01    /* only show pgid - for jobs -p */  #define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
3208  #define SHOW_PID        0x04    /* include process pid */  #define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
3209  #define SHOW_CHANGED    0x08    /* only jobs whose state has changed */  #define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
3210    
3211  /*  /*
3212   * A job structure contains information about a job.  A job is either a   * A job structure contains information about a job.  A job is either a
# Line 3273  unaliascmd(int argc UNUSED_PARAM, char * Line 3214  unaliascmd(int argc UNUSED_PARAM, char *
3214   * latter case, pidlist will be non-NULL, and will point to a -1 terminated   * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3215   * array of pids.   * array of pids.
3216   */   */
   
3217  struct procstat {  struct procstat {
3218   pid_t   pid;            /* process id */   pid_t   ps_pid;         /* process id */
3219   int     status;         /* last process status from wait() */   int     ps_status;      /* last process status from wait() */
3220   char    *cmd;           /* text of command being run */   char    *ps_cmd;        /* text of command being run */
3221  };  };
3222    
3223  struct job {  struct job {
# Line 3303  struct job { Line 3243  struct job {
3243  };  };
3244    
3245  static struct job *makejob(/*union node *,*/ int);  static struct job *makejob(/*union node *,*/ int);
 #if !JOBS  
 #define forkshell(job, node, mode) forkshell(job, mode)  
 #endif  
3246  static int forkshell(struct job *, union node *, int);  static int forkshell(struct job *, union node *, int);
3247  static int waitforjob(struct job *);  static int waitforjob(struct job *);
3248    
# Line 3318  static void setjobctl(int); Line 3255  static void setjobctl(int);
3255  #endif  #endif
3256    
3257  /*  /*
3258     * Ignore a signal.
3259     */
3260    static void
3261    ignoresig(int signo)
3262    {
3263     /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3264     if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3265     /* No, need to do it */
3266     signal(signo, SIG_IGN);
3267     }
3268     sigmode[signo - 1] = S_HARD_IGN;
3269    }
3270    
3271    /*
3272     * Signal handler. Only one usage site - in setsignal()
3273     */
3274    static void
3275    onsig(int signo)
3276    {
3277     gotsig[signo - 1] = 1;
3278    
3279     if (signo == SIGINT && !trap[SIGINT]) {
3280     if (!suppress_int) {
3281     pending_sig = 0;
3282     raise_interrupt(); /* does not return */
3283     }
3284     pending_int = 1;
3285     } else {
3286     pending_sig = signo;
3287     }
3288    }
3289    
3290    /*
3291   * Set the signal handler for the specified signal.  The routine figures   * Set the signal handler for the specified signal.  The routine figures
3292   * out what it should be set to.   * out what it should be set to.
3293   */   */
3294  static void  static void
3295  setsignal(int signo)  setsignal(int signo)
3296  {  {
3297   int action;   char *t;
3298   char *t, tsig;   char cur_act, new_act;
3299   struct sigaction act;   struct sigaction act;
3300    
3301   t = trap[signo];   t = trap[signo];
3302   action = S_IGN;   new_act = S_DFL;
3303   if (t == NULL)   if (t != NULL) { /* trap for this sig is set */
3304   action = S_DFL;   new_act = S_CATCH;
3305   else if (*t != '\0')   if (t[0] == '\0') /* trap is "": ignore this sig */
3306   action = S_CATCH;   new_act = S_IGN;
3307   if (rootshell && action == S_DFL) {   }
3308    
3309     if (rootshell && new_act == S_DFL) {
3310   switch (signo) {   switch (signo) {
3311   case SIGINT:   case SIGINT:
3312   if (iflag || minusc || sflag == 0)   if (iflag || minusc || sflag == 0)
3313   action = S_CATCH;   new_act = S_CATCH;
3314   break;   break;
3315   case SIGQUIT:   case SIGQUIT:
3316  #if DEBUG  #if DEBUG
3317   if (debug)   if (debug)
3318   break;   break;
3319  #endif  #endif
3320   /* FALLTHROUGH */   /* man bash:
3321     * "In all cases, bash ignores SIGQUIT. Non-builtin
3322     * commands run by bash have signal handlers
3323     * set to the values inherited by the shell
3324     * from its parent". */
3325     new_act = S_IGN;
3326     break;
3327   case SIGTERM:   case SIGTERM:
3328   if (iflag)   if (iflag)
3329   action = S_IGN;   new_act = S_IGN;
3330   break;   break;
3331  #if JOBS  #if JOBS
3332   case SIGTSTP:   case SIGTSTP:
3333   case SIGTTOU:   case SIGTTOU:
3334   if (mflag)   if (mflag)
3335   action = S_IGN;   new_act = S_IGN;
3336   break;   break;
3337  #endif  #endif
3338   }   }
3339   }   }
3340    //TODO: if !rootshell, we reset SIGQUIT to DFL,
3341    //whereas we have to restore it to what shell got on entry
3342    //from the parent. See comment above
3343    
3344   t = &sigmode[signo - 1];   t = &sigmode[signo - 1];
3345   tsig = *t;   cur_act = *t;
3346   if (tsig == 0) {   if (cur_act == 0) {
3347   /*   /* current setting is not yet known */
3348   * current setting unknown   if (sigaction(signo, NULL, &act)) {
3349   */   /* pretend it worked; maybe we should give a warning,
3350   if (sigaction(signo, NULL, &act) == -1) {   * but other shells don't. We don't alter sigmode,
3351   /*   * so we retry every time.
3352   * Pretend it worked; maybe we should give a warning   * btw, in Linux it never fails. --vda */
  * here, but other shells don't. We don't alter  
  * sigmode, so that we retry every time.  
  */  
3353   return;   return;
3354   }   }
  tsig = S_RESET; /* force to be set */  
3355   if (act.sa_handler == SIG_IGN) {   if (act.sa_handler == SIG_IGN) {
3356   tsig = S_HARD_IGN;   cur_act = S_HARD_IGN;
3357   if (mflag   if (mflag
3358   && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)   && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3359   ) {   ) {
3360   tsig = S_IGN;   /* don't hard ignore these */   cur_act = S_IGN;   /* don't hard ignore these */
3361   }   }
3362   }   }
3363   }   }
3364   if (tsig == S_HARD_IGN || tsig == action)   if (cur_act == S_HARD_IGN || cur_act == new_act)
3365   return;   return;
3366    
3367   act.sa_handler = SIG_DFL;   act.sa_handler = SIG_DFL;
3368   switch (action) {   switch (new_act) {
3369   case S_CATCH:   case S_CATCH:
3370   act.sa_handler = onsig;   act.sa_handler = onsig;
3371     act.sa_flags = 0; /* matters only if !DFL and !IGN */
3372     sigfillset(&act.sa_mask); /* ditto */
3373   break;   break;
3374   case S_IGN:   case S_IGN:
3375   act.sa_handler = SIG_IGN;   act.sa_handler = SIG_IGN;
3376   break;   break;
3377   }   }
  *t = action;  
  act.sa_flags = 0;  
  sigfillset(&act.sa_mask);  
3378   sigaction_set(signo, &act);   sigaction_set(signo, &act);
3379    
3380     *t = new_act;
3381  }  }
3382    
3383  /* mode flags for set_curjob */  /* mode flags for set_curjob */
# Line 3491  getjob(const char *name, int getctl) Line 3470  getjob(const char *name, int getctl)
3470  {  {
3471   struct job *jp;   struct job *jp;
3472   struct job *found;   struct job *found;
3473   const char *err_msg = "No such job: %s";   const char *err_msg = "%s: no such job";
3474   unsigned num;   unsigned num;
3475   int c;   int c;
3476   const char *p;   const char *p;
# Line 3527  getjob(const char *name, int getctl) Line 3506  getjob(const char *name, int getctl)
3506   }   }
3507    
3508   if (is_number(p)) {   if (is_number(p)) {
 // TODO: number() instead? It does error checking...  
3509   num = atoi(p);   num = atoi(p);
3510   if (num < njobs) {   if (num < njobs) {
3511   jp = jobtab + num - 1;   jp = jobtab + num - 1;
# Line 3543  getjob(const char *name, int getctl) Line 3521  getjob(const char *name, int getctl)
3521   p++;   p++;
3522   }   }
3523    
3524   found = 0;   found = NULL;
3525   while (1) {   while (jp) {
3526   if (!jp)   if (match(jp->ps[0].ps_cmd, p)) {
  goto err;  
  if (match(jp->ps[0].cmd, p)) {  
3527   if (found)   if (found)
3528   goto err;   goto err;
3529   found = jp;   found = jp;
# Line 3555  getjob(const char *name, int getctl) Line 3531  getjob(const char *name, int getctl)
3531   }   }
3532   jp = jp->prev_job;   jp = jp->prev_job;
3533   }   }
3534     if (!found)
3535     goto err;
3536     jp = found;
3537    
3538   gotit:   gotit:
3539  #if JOBS  #if JOBS
# Line 3578  freejob(struct job *jp) Line 3557  freejob(struct job *jp)
3557    
3558   INT_OFF;   INT_OFF;
3559   for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {   for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3560   if (ps->cmd != nullstr)   if (ps->ps_cmd != nullstr)
3561   free(ps->cmd);   free(ps->ps_cmd);
3562   }   }
3563   if (jp->ps != &jp->ps0)   if (jp->ps != &jp->ps0)
3564   free(jp->ps);   free(jp->ps);
# Line 3673  setjobctl(int on) Line 3652  setjobctl(int on)
3652   doing_jobctl = on;   doing_jobctl = on;
3653  }  }
3654    
3655  static int  static int FAST_FUNC
3656  killcmd(int argc, char **argv)  killcmd(int argc, char **argv)
3657  {  {
3658   int i = 1;   int i = 1;
# Line 3681  killcmd(int argc, char **argv) Line 3660  killcmd(int argc, char **argv)
3660   do {   do {
3661   if (argv[i][0] == '%') {   if (argv[i][0] == '%') {
3662   struct job *jp = getjob(argv[i], 0);   struct job *jp = getjob(argv[i], 0);
3663   unsigned pid = jp->ps[0].pid;   unsigned pid = jp->ps[0].ps_pid;
3664   /* Enough space for ' -NNN<nul>' */   /* Enough space for ' -NNN<nul>' */
3665   argv[i] = alloca(sizeof(int)*3 + 3);   argv[i] = alloca(sizeof(int)*3 + 3);
3666   /* kill_main has matching code to expect   /* kill_main has matching code to expect
# Line 3695  killcmd(int argc, char **argv) Line 3674  killcmd(int argc, char **argv)
3674  }  }
3675    
3676  static void  static void
3677  showpipe(struct job *jp, FILE *out)  showpipe(struct job *jp /*, FILE *out*/)
3678  {  {
3679   struct procstat *sp;   struct procstat *ps;
3680   struct procstat *spend;   struct procstat *psend;
3681    
3682   spend = jp->ps + jp->nprocs;   psend = jp->ps + jp->nprocs;
3683   for (sp = jp->ps + 1; sp < spend; sp++)   for (ps = jp->ps + 1; ps < psend; ps++)
3684   fprintf(out, " | %s", sp->cmd);   printf(" | %s", ps->ps_cmd);
3685   outcslow('\n', out);   outcslow('\n', stdout);
3686   flush_stdout_stderr();   flush_stdout_stderr();
3687  }  }
3688    
# Line 3720  restartjob(struct job *jp, int mode) Line 3699  restartjob(struct job *jp, int mode)
3699   if (jp->state == JOBDONE)   if (jp->state == JOBDONE)
3700   goto out;   goto out;
3701   jp->state = JOBRUNNING;   jp->state = JOBRUNNING;
3702   pgid = jp->ps->pid;   pgid = jp->ps[0].ps_pid;
3703   if (mode == FORK_FG)   if (mode == FORK_FG)
3704   xtcsetpgrp(ttyfd, pgid);   xtcsetpgrp(ttyfd, pgid);
3705   killpg(pgid, SIGCONT);   killpg(pgid, SIGCONT);
3706   ps = jp->ps;   ps = jp->ps;
3707   i = jp->nprocs;   i = jp->nprocs;
3708   do {   do {
3709   if (WIFSTOPPED(ps->status)) {   if (WIFSTOPPED(ps->ps_status)) {
3710   ps->status = -1;   ps->ps_status = -1;
3711   }   }
3712   ps++;   ps++;
3713   } while (--i);   } while (--i);
# Line 3738  restartjob(struct job *jp, int mode) Line 3717  restartjob(struct job *jp, int mode)
3717   return status;   return status;
3718  }  }
3719    
3720  static int  static int FAST_FUNC
3721  fg_bgcmd(int argc UNUSED_PARAM, char **argv)  fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3722  {  {
3723   struct job *jp;   struct job *jp;
  FILE *out;  
3724   int mode;   int mode;
3725   int retval;   int retval;
3726    
3727   mode = (**argv == 'f') ? FORK_FG : FORK_BG;   mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3728   nextopt(nullstr);   nextopt(nullstr);
3729   argv = argptr;   argv = argptr;
  out = stdout;  
3730   do {   do {
3731   jp = getjob(*argv, 1);   jp = getjob(*argv, 1);
3732   if (mode == FORK_BG) {   if (mode == FORK_BG) {
3733   set_curjob(jp, CUR_RUNNING);   set_curjob(jp, CUR_RUNNING);
3734   fprintf(out, "[%d] ", jobno(jp));   printf("[%d] ", jobno(jp));
3735   }   }
3736   outstr(jp->ps->cmd, out);   out1str(jp->ps[0].ps_cmd);
3737   showpipe(jp, out);   showpipe(jp /*, stdout*/);
3738   retval = restartjob(jp, mode);   retval = restartjob(jp, mode);
3739   } while (*argv && *++argv);   } while (*argv && *++argv);
3740   return retval;   return retval;
# Line 3816  dowait(int wait_flags, struct job *job) Line 3793  dowait(int wait_flags, struct job *job)
3793   /* Do a wait system call. If job control is compiled in, we accept   /* Do a wait system call. If job control is compiled in, we accept
3794   * stopped processes. wait_flags may have WNOHANG, preventing blocking.   * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3795   * NB: _not_ safe_waitpid, we need to detect EINTR */   * NB: _not_ safe_waitpid, we need to detect EINTR */
3796   pid = waitpid(-1, &status,   if (doing_jobctl)
3797   (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));   wait_flags |= WUNTRACED;
3798   TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", pid, status, errno, strerror(errno)));   pid = waitpid(-1, &status, wait_flags);
3799     TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3800   if (pid <= 0) {   pid, status, errno, strerror(errno)));
3801   /* If we were doing blocking wait and (probably) got EINTR,   if (pid <= 0)
  * check for pending sigs received while waiting.  
  * (NB: can be moved into callers if needed) */  
  if (wait_flags == DOWAIT_BLOCK && pendingsig)  
  raise_exception(EXSIG);  
3802   return pid;   return pid;
3803   }  
3804   INT_OFF;   INT_OFF;
3805   thisjob = NULL;   thisjob = NULL;
3806   for (jp = curjob; jp; jp = jp->prev_job) {   for (jp = curjob; jp; jp = jp->prev_job) {
3807   struct procstat *sp;   struct procstat *ps;
3808   struct procstat *spend;   struct procstat *psend;
3809   if (jp->state == JOBDONE)   if (jp->state == JOBDONE)
3810   continue;   continue;
3811   state = JOBDONE;   state = JOBDONE;
3812   spend = jp->ps + jp->nprocs;   ps = jp->ps;
3813   sp = jp->ps;   psend = ps + jp->nprocs;
3814   do {   do {
3815   if (sp->pid == pid) {   if (ps->ps_pid == pid) {
3816   TRACE(("Job %d: changing status of proc %d "   TRACE(("Job %d: changing status of proc %d "
3817   "from 0x%x to 0x%x\n",   "from 0x%x to 0x%x\n",
3818   jobno(jp), pid, sp->status, status));   jobno(jp), pid, ps->ps_status, status));
3819   sp->status = status;   ps->ps_status = status;
3820   thisjob = jp;   thisjob = jp;
3821   }   }
3822   if (sp->status == -1)   if (ps->ps_status == -1)
3823   state = JOBRUNNING;   state = JOBRUNNING;
3824  #if JOBS  #if JOBS
3825   if (state == JOBRUNNING)   if (state == JOBRUNNING)
3826   continue;   continue;
3827   if (WIFSTOPPED(sp->status)) {   if (WIFSTOPPED(ps->ps_status)) {
3828   jp->stopstatus = sp->status;   jp->stopstatus = ps->ps_status;
3829   state = JOBSTOPPED;   state = JOBSTOPPED;
3830   }   }
3831  #endif  #endif
3832   } while (++sp < spend);   } while (++ps < psend);
3833   if (thisjob)   if (thisjob)
3834   goto gotjob;   goto gotjob;
3835   }   }
# Line 3899  dowait(int wait_flags, struct job *job) Line 3872  dowait(int wait_flags, struct job *job)
3872   return pid;   return pid;
3873  }  }
3874    
3875    static int
3876    blocking_wait_with_raise_on_sig(struct job *job)
3877    {
3878     pid_t pid = dowait(DOWAIT_BLOCK, job);
3879     if (pid <= 0 && pending_sig)
3880     raise_exception(EXSIG);
3881     return pid;
3882    }
3883    
3884  #if JOBS  #if JOBS
3885  static void  static void
3886  showjob(FILE *out, struct job *jp, int mode)  showjob(FILE *out, struct job *jp, int mode)
# Line 3911  showjob(FILE *out, struct job *jp, int m Line 3893  showjob(FILE *out, struct job *jp, int m
3893    
3894   ps = jp->ps;   ps = jp->ps;
3895    
3896   if (mode & SHOW_PGID) {   if (mode & SHOW_ONLY_PGID) { /* jobs -p */
3897   /* just output process (group) id of pipeline */   /* just output process (group) id of pipeline */
3898   fprintf(out, "%d\n", ps->pid);   fprintf(out, "%d\n", ps->ps_pid);
3899   return;   return;
3900   }   }
3901    
# Line 3921  showjob(FILE *out, struct job *jp, int m Line 3903  showjob(FILE *out, struct job *jp, int m
3903   indent_col = col;   indent_col = col;
3904    
3905   if (jp == curjob)   if (jp == curjob)
3906   s[col - 2] = '+';   s[col - 3] = '+';
3907   else if (curjob && jp == curjob->prev_job)   else if (curjob && jp == curjob->prev_job)
3908   s[col - 2] = '-';   s[col - 3] = '-';
3909    
3910   if (mode & SHOW_PID)   if (mode & SHOW_PIDS)
3911   col += fmtstr(s + col, 16, "%d ", ps->pid);   col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
3912    
3913   psend = ps + jp->nprocs;   psend = ps + jp->nprocs;
3914    
# Line 3934  showjob(FILE *out, struct job *jp, int m Line 3916  showjob(FILE *out, struct job *jp, int m
3916   strcpy(s + col, "Running");   strcpy(s + col, "Running");
3917   col += sizeof("Running") - 1;   col += sizeof("Running") - 1;
3918   } else {   } else {
3919   int status = psend[-1].status;   int status = psend[-1].ps_status;
3920   if (jp->state == JOBSTOPPED)   if (jp->state == JOBSTOPPED)
3921   status = jp->stopstatus;   status = jp->stopstatus;
3922   col += sprint_status(s + col, status, 0);   col += sprint_status(s + col, status, 0);
3923   }   }
3924     /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
3925    
3926     /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
3927     * or prints several "PID             | <cmdN>" lines,
3928     * depending on SHOW_PIDS bit.
3929     * We do not print status of individual processes
3930     * between PID and <cmdN>. bash does it, but not very well:
3931     * first line shows overall job status, not process status,
3932     * making it impossible to know 1st process status.
3933     */
3934   goto start;   goto start;
   
3935   do {   do {
3936   /* for each process */   /* for each process */
3937   col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;   s[0] = '\0';
3938     col = 33;
3939     if (mode & SHOW_PIDS)
3940     col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
3941   start:   start:
3942   fprintf(out, "%s%*c%s",   fprintf(out, "%s%*c%s%s",
3943   s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd   s,
3944     33 - col >= 0 ? 33 - col : 0, ' ',
3945     ps == jp->ps ? "" : "| ",
3946     ps->ps_cmd
3947   );   );
3948   if (!(mode & SHOW_PID)) {   } while (++ps != psend);
3949   showpipe(jp, out);   outcslow('\n', out);
  break;  
  }  
  if (++ps == psend) {  
  outcslow('\n', out);  
  break;  
  }  
  } while (1);  
3950    
3951   jp->changed = 0;   jp->changed = 0;
3952    
# Line 3976  showjobs(FILE *out, int mode) Line 3965  showjobs(FILE *out, int mode)
3965  {  {
3966   struct job *jp;   struct job *jp;
3967    
3968   TRACE(("showjobs(%x) called\n", mode));   TRACE(("showjobs(0x%x) called\n", mode));
3969    
3970   /* If not even one job changed, there is nothing to do */   /* Handle all finished jobs */
3971   while (dowait(DOWAIT_NONBLOCK, NULL) > 0)   while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3972   continue;   continue;
3973    
# Line 3989  showjobs(FILE *out, int mode) Line 3978  showjobs(FILE *out, int mode)
3978   }   }
3979  }  }
3980    
3981  static int  static int FAST_FUNC
3982  jobscmd(int argc UNUSED_PARAM, char **argv)  jobscmd(int argc UNUSED_PARAM, char **argv)
3983  {  {
3984   int mode, m;   int mode, m;
3985    
3986   mode = 0;   mode = 0;
3987   while ((m = nextopt("lp"))) {   while ((m = nextopt("lp")) != '\0') {
3988   if (m == 'l')   if (m == 'l')
3989   mode = SHOW_PID;   mode |= SHOW_PIDS;
3990   else   else
3991   mode = SHOW_PGID;   mode |= SHOW_ONLY_PGID;
3992   }   }
3993    
3994   argv = argptr;   argv = argptr;
3995   if (*argv) {   if (*argv) {
3996   do   do
3997   showjob(stdout, getjob(*argv,0), mode);   showjob(stdout, getjob(*argv, 0), mode);
3998   while (*++argv);   while (*++argv);
3999   } else   } else {
4000   showjobs(stdout, mode);   showjobs(stdout, mode);
4001     }
4002    
4003   return 0;   return 0;
4004  }  }
4005  #endif /* JOBS */  #endif /* JOBS */
4006    
4007    /* Called only on finished or stopped jobs (no members are running) */
4008  static int  static int
4009  getstatus(struct job *job)  getstatus(struct job *job)
4010  {  {
4011   int status;   int status;
4012   int retval;   int retval;
4013     struct procstat *ps;
4014    
4015     /* Fetch last member's status */
4016     ps = job->ps + job->nprocs - 1;
4017     status = ps->ps_status;
4018     if (pipefail) {
4019     /* "set -o pipefail" mode: use last _nonzero_ status */
4020     while (status == 0 && --ps >= job->ps)
4021     status = ps->ps_status;
4022     }
4023    
  status = job->ps[job->nprocs - 1].status;  
4024   retval = WEXITSTATUS(status);   retval = WEXITSTATUS(status);
4025   if (!WIFEXITED(status)) {   if (!WIFEXITED(status)) {
4026  #if JOBS  #if JOBS
# Line 4037  getstatus(struct job *job) Line 4037  getstatus(struct job *job)
4037   }   }
4038   retval += 128;   retval += 128;
4039   }   }
4040   TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",   TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4041   jobno(job), job->nprocs, status, retval));   jobno(job), job->nprocs, status, retval));
4042   return retval;   return retval;
4043  }  }
4044    
4045  static int  static int FAST_FUNC
4046  waitcmd(int argc UNUSED_PARAM, char **argv)  waitcmd(int argc UNUSED_PARAM, char **argv)
4047  {  {
4048   struct job *job;   struct job *job;
4049   int retval;   int retval;
4050   struct job *jp;   struct job *jp;
4051    
4052  // exsig++;   if (pending_sig)
 // xbarrier();  
  if (pendingsig)  
4053   raise_exception(EXSIG);   raise_exception(EXSIG);
4054    
4055   nextopt(nullstr);   nextopt(nullstr);
# Line 4070  waitcmd(int argc UNUSED_PARAM, char **ar Line 4068  waitcmd(int argc UNUSED_PARAM, char **ar
4068   jp->waited = 1;   jp->waited = 1;
4069   jp = jp->prev_job;   jp = jp->prev_job;
4070   }   }
4071   dowait(DOWAIT_BLOCK, NULL);   /* man bash:
4072     * "When bash is waiting for an asynchronous command via
4073     * the wait builtin, the reception of a signal for which a trap
4074     * has been set will cause the wait builtin to return immediately
4075     * with an exit status greater than 128, immediately after which
4076     * the trap is executed."
4077     * Do we do it that way? */
4078     blocking_wait_with_raise_on_sig(NULL);
4079   }   }
4080   }   }
4081    
# Line 4082  waitcmd(int argc UNUSED_PARAM, char **ar Line 4087  waitcmd(int argc UNUSED_PARAM, char **ar
4087   while (1) {   while (1) {
4088   if (!job)   if (!job)
4089   goto repeat;   goto repeat;
4090   if (job->ps[job->nprocs - 1].pid == pid)   if (job->ps[job->nprocs - 1].ps_pid == pid)
4091   break;   break;
4092   job = job->prev_job;   job = job->prev_job;
4093   }   }
# Line 4090  waitcmd(int argc UNUSED_PARAM, char **ar Line 4095  waitcmd(int argc UNUSED_PARAM, char **ar
4095   job = getjob(*argv, 0);   job = getjob(*argv, 0);
4096   /* loop until process terminated or stopped */   /* loop until process terminated or stopped */
4097   while (job->state == JOBRUNNING)   while (job->state == JOBRUNNING)
4098   dowait(DOWAIT_BLOCK, NULL);   blocking_wait_with_raise_on_sig(NULL);
4099   job->waited = 1;   job->waited = 1;
4100   retval = getstatus(job);   retval = getstatus(job);
4101   repeat:   repeat: ;
  ;  
4102   } while (*++argv);   } while (*++argv);
4103    
4104   ret:   ret:
# Line 4202  cmdputs(const char *s) Line 4206  cmdputs(const char *s)
4206   static const char vstype[VSTYPE + 1][3] = {   static const char vstype[VSTYPE + 1][3] = {
4207   "", "}", "-", "+", "?", "=",   "", "}", "-", "+", "?", "=",
4208   "%", "%%", "#", "##"   "%", "%%", "#", "##"
4209   USE_ASH_BASH_COMPAT(, ":", "/", "//")   IF_ASH_BASH_COMPAT(, ":", "/", "//")
4210   };   };
4211    
4212   const char *p, *str;   const char *p, *str;
4213   char c, cc[2] = " ";   char cc[2];
4214   char *nextc;   char *nextc;
4215   int subtype = 0;   unsigned char c;
4216     unsigned char subtype = 0;
4217   int quoted = 0;   int quoted = 0;
4218    
4219     cc[1] = '\0';
4220   nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);   nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4221   p = s;   p = s;
4222   while ((c = *p++) != 0) {   while ((c = *p++) != '\0') {
4223   str = NULL;   str = NULL;
4224   switch (c) {   switch (c) {
4225   case CTLESC:   case CTLESC:
# Line 4241  cmdputs(const char *s) Line 4247  cmdputs(const char *s)
4247   case CTLBACKQ+CTLQUOTE:   case CTLBACKQ+CTLQUOTE:
4248   str = "\"$(...)\"";   str = "\"$(...)\"";
4249   goto dostr;   goto dostr;
4250  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
4251   case CTLARI:   case CTLARI:
4252   str = "$((";   str = "$((";
4253   goto dostr;   goto dostr;
# Line 4281  cmdputs(const char *s) Line 4287  cmdputs(const char *s)
4287   if (!str)   if (!str)
4288   continue;   continue;
4289   dostr:   dostr:
4290   while ((c = *str++)) {   while ((c = *str++) != '\0') {
4291   USTPUTC(c, nextc);   USTPUTC(c, nextc);
4292   }   }
4293   }   } /* while *p++ not NUL */
4294    
4295   if (quoted & 1) {   if (quoted & 1) {
4296   USTPUTC('"', nextc);   USTPUTC('"', nextc);
4297   }   }
# Line 4358  cmdtxt(union node *n) Line 4365  cmdtxt(union node *n)
4365   cmdputs("if ");   cmdputs("if ");
4366   cmdtxt(n->nif.test);   cmdtxt(n->nif.test);
4367   cmdputs("; then ");   cmdputs("; then ");
  n = n->nif.ifpart;  
4368   if (n->nif.elsepart) {   if (n->nif.elsepart) {
4369   cmdtxt(n);   cmdtxt(n->nif.ifpart);
4370   cmdputs("; else ");   cmdputs("; else ");
4371   n = n->nif.elsepart;   n = n->nif.elsepart;
4372     } else {
4373     n = n->nif.ifpart;
4374   }   }
4375   p = "; fi";   p = "; fi";
4376   goto dotail;   goto dotail;
# Line 4499  clear_traps(void) Line 4507  clear_traps(void)
4507   for (tp = trap; tp < &trap[NSIG]; tp++) {   for (tp = trap; tp < &trap[NSIG]; tp++) {
4508   if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */   if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
4509   INT_OFF;   INT_OFF;
4510   free(*tp);   if (trap_ptr == trap)
4511     free(*tp);
4512     /* else: it "belongs" to trap_ptr vector, don't free */
4513   *tp = NULL;   *tp = NULL;
4514   if (tp != &trap[0])   if ((tp - trap) != 0)
4515   setsignal(tp - trap);   setsignal(tp - trap);
4516   INT_ON;   INT_ON;
4517   }   }
# Line 4512  clear_traps(void) Line 4522  clear_traps(void)
4522  static void closescript(void);  static void closescript(void);
4523    
4524  /* Called after fork(), in child */  /* Called after fork(), in child */
4525  static void  static NOINLINE void
4526  forkchild(struct job *jp, /*union node *n,*/ int mode)  forkchild(struct job *jp, union node *n, int mode)
4527  {  {
4528   int oldlvl;   int oldlvl;
4529    
# Line 4521  forkchild(struct job *jp, /*union node * Line 4531  forkchild(struct job *jp, /*union node *
4531   oldlvl = shlvl;   oldlvl = shlvl;
4532   shlvl++;   shlvl++;
4533    
4534     /* man bash: "Non-builtin commands run by bash have signal handlers
4535     * set to the values inherited by the shell from its parent".
4536     * Do we do it correctly? */
4537    
4538   closescript();   closescript();
4539    
4540     if (mode == FORK_NOJOB          /* is it `xxx` ? */
4541     && n && n->type == NCMD        /* is it single cmd? */
4542     /* && n->ncmd.args->type == NARG - always true? */
4543     && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4544     && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4545     /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4546     ) {
4547     TRACE(("Trap hack\n"));
4548     /* Awful hack for `trap` or $(trap).
4549     *
4550     * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4551     * contains an example where "trap" is executed in a subshell:
4552     *
4553     * save_traps=$(trap)
4554     * ...
4555     * eval "$save_traps"
4556     *
4557     * Standard does not say that "trap" in subshell shall print
4558     * parent shell's traps. It only says that its output
4559     * must have suitable form, but then, in the above example
4560     * (which is not supposed to be normative), it implies that.
4561     *
4562     * bash (and probably other shell) does implement it
4563     * (traps are reset to defaults, but "trap" still shows them),
4564     * but as a result, "trap" logic is hopelessly messed up:
4565     *
4566     * # trap
4567     * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
4568     * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
4569     * # true | trap   <--- trap is in subshell - no output (ditto)
4570     * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
4571     * trap -- 'echo Ho' SIGWINCH
4572     * # echo `(trap)`         <--- in subshell in subshell - output
4573     * trap -- 'echo Ho' SIGWINCH
4574     * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
4575     * trap -- 'echo Ho' SIGWINCH
4576     *
4577     * The rules when to forget and when to not forget traps
4578     * get really complex and nonsensical.
4579     *
4580     * Our solution: ONLY bare $(trap) or `trap` is special.
4581     */
4582     /* Save trap handler strings for trap builtin to print */
4583     trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
4584     /* Fall through into clearing traps */
4585     }
4586   clear_traps();   clear_traps();
4587  #if JOBS  #if JOBS
4588   /* do job control only in root shell */   /* do job control only in root shell */
# Line 4532  forkchild(struct job *jp, /*union node * Line 4593  forkchild(struct job *jp, /*union node *
4593   if (jp->nprocs == 0)   if (jp->nprocs == 0)
4594   pgrp = getpid();   pgrp = getpid();
4595   else   else
4596   pgrp = jp->ps[0].pid;   pgrp = jp->ps[0].ps_pid;
4597   /* This can fail because we are doing it in the parent also */   /* this can fail because we are doing it in the parent also */
4598   (void)setpgid(0, pgrp);   setpgid(0, pgrp);
4599   if (mode == FORK_FG)   if (mode == FORK_FG)
4600   xtcsetpgrp(ttyfd, pgrp);   xtcsetpgrp(ttyfd, pgrp);
4601   setsignal(SIGTSTP);   setsignal(SIGTSTP);
# Line 4542  forkchild(struct job *jp, /*union node * Line 4603  forkchild(struct job *jp, /*union node *
4603   } else   } else
4604  #endif  #endif
4605   if (mode == FORK_BG) {   if (mode == FORK_BG) {
4606     /* man bash: "When job control is not in effect,
4607     * asynchronous commands ignore SIGINT and SIGQUIT" */
4608   ignoresig(SIGINT);   ignoresig(SIGINT);
4609   ignoresig(SIGQUIT);   ignoresig(SIGQUIT);
4610   if (jp->nprocs == 0) {   if (jp->nprocs == 0) {
4611   close(0);   close(0);
4612   if (open(bb_dev_null, O_RDONLY) != 0)   if (open(bb_dev_null, O_RDONLY) != 0)
4613   ash_msg_and_raise_error("can't open %s", bb_dev_null);   ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4614   }   }
4615   }   }
4616   if (!oldlvl && iflag) {   if (!oldlvl) {
4617   setsignal(SIGINT);   if (iflag) { /* why if iflag only? */
4618     setsignal(SIGINT);
4619     setsignal(SIGTERM);
4620     }
4621     /* man bash:
4622     * "In all cases, bash ignores SIGQUIT. Non-builtin
4623     * commands run by bash have signal handlers
4624     * set to the values inherited by the shell
4625     * from its parent".
4626     * Take care of the second rule: */
4627   setsignal(SIGQUIT);   setsignal(SIGQUIT);
  setsignal(SIGTERM);  
4628   }   }
4629    #if JOBS
4630     if (n && n->type == NCMD
4631     && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4632     ) {
4633     TRACE(("Job hack\n"));
4634     /* "jobs": we do not want to clear job list for it,
4635     * instead we remove only _its_ own_ job from job list.
4636     * This makes "jobs .... | cat" more useful.
4637     */
4638     freejob(curjob);
4639     return;
4640     }
4641    #endif
4642   for (jp = curjob; jp; jp = jp->prev_job)   for (jp = curjob; jp; jp = jp->prev_job)
4643   freejob(jp);   freejob(jp);
4644   jobless = 0;   jobless = 0;
# Line 4581  forkparent(struct job *jp, union node *n Line 4665  forkparent(struct job *jp, union node *n
4665   if (jp->nprocs == 0)   if (jp->nprocs == 0)
4666   pgrp = pid;   pgrp = pid;
4667   else   else
4668   pgrp = jp->ps[0].pid;   pgrp = jp->ps[0].ps_pid;
4669   /* This can fail because we are doing it in the child also */   /* This can fail because we are doing it in the child also */
4670   setpgid(pid, pgrp);   setpgid(pid, pgrp);
4671   }   }
# Line 4592  forkparent(struct job *jp, union node *n Line 4676  forkparent(struct job *jp, union node *n
4676   }   }
4677   if (jp) {   if (jp) {
4678   struct procstat *ps = &jp->ps[jp->nprocs++];   struct procstat *ps = &jp->ps[jp->nprocs++];
4679   ps->pid = pid;   ps->ps_pid = pid;
4680   ps->status = -1;   ps->ps_status = -1;
4681   ps->cmd = nullstr;   ps->ps_cmd = nullstr;
4682  #if JOBS  #if JOBS
4683   if (doing_jobctl && n)   if (doing_jobctl && n)
4684   ps->cmd = commandtext(n);   ps->ps_cmd = commandtext(n);
4685  #endif  #endif
4686   }   }
4687  }  }
# Line 4615  forkshell(struct job *jp, union node *n, Line 4699  forkshell(struct job *jp, union node *n,
4699   freejob(jp);   freejob(jp);
4700   ash_msg_and_raise_error("can't fork");   ash_msg_and_raise_error("can't fork");
4701   }   }
4702   if (pid == 0)   if (pid == 0) {
4703   forkchild(jp, /*n,*/ mode);   CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4704   else   forkchild(jp, n, mode);
4705     } else {
4706   forkparent(jp, n, mode, pid);   forkparent(jp, n, mode, pid);
4707     }
4708   return pid;   return pid;
4709  }  }
4710    
4711  /*  /*
4712   * Wait for job to finish.   * Wait for job to finish.
4713   *   *
4714   * Under job control we have the problem that while a child process is   * Under job control we have the problem that while a child process
4715   * running interrupts generated by the user are sent to the child but not   * is running interrupts generated by the user are sent to the child
4716   * to the shell.  This means that an infinite loop started by an inter-   * but not to the shell.  This means that an infinite loop started by
4717   * active user may be hard to kill.  With job control turned off, an   * an interactive user may be hard to kill.  With job control turned off,
4718   * interactive user may place an interactive program inside a loop.  If   * an interactive user may place an interactive program inside a loop.
4719   * the interactive program catches interrupts, the user doesn't want   * If the interactive program catches interrupts, the user doesn't want
4720   * these interrupts to also abort the loop.  The approach we take here   * these interrupts to also abort the loop.  The approach we take here
4721   * is to have the shell ignore interrupt signals while waiting for a   * is to have the shell ignore interrupt signals while waiting for a
4722   * foreground process to terminate, and then send itself an interrupt   * foreground process to terminate, and then send itself an interrupt
# Line 4648  waitforjob(struct job *jp) Line 4734  waitforjob(struct job *jp)
4734   int st;   int st;
4735    
4736   TRACE(("waitforjob(%%%d) called\n", jobno(jp)));   TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4737    
4738     INT_OFF;
4739   while (jp->state == JOBRUNNING) {   while (jp->state == JOBRUNNING) {
4740     /* In non-interactive shells, we _can_ get
4741     * a keyboard signal here and be EINTRed,
4742     * but we just loop back, waiting for command to complete.
4743     *
4744     * man bash:
4745     * "If bash is waiting for a command to complete and receives
4746     * a signal for which a trap has been set, the trap
4747     * will not be executed until the command completes."
4748     *
4749     * Reality is that even if trap is not set, bash
4750     * will not act on the signal until command completes.
4751     * Try this. sleep5intoff.c:
4752     * #include <signal.h>
4753     * #include <unistd.h>
4754     * int main() {
4755     *         sigset_t set;
4756     *         sigemptyset(&set);
4757     *         sigaddset(&set, SIGINT);
4758     *         sigaddset(&set, SIGQUIT);
4759     *         sigprocmask(SIG_BLOCK, &set, NULL);
4760     *         sleep(5);
4761     *         return 0;
4762     * }
4763     * $ bash -c './sleep5intoff; echo hi'
4764     * ^C^C^C^C <--- pressing ^C once a second
4765     * $ _
4766     * $ bash -c './sleep5intoff; echo hi'
4767     * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4768     * $ _
4769     */
4770   dowait(DOWAIT_BLOCK, jp);   dowait(DOWAIT_BLOCK, jp);
4771   }   }
4772     INT_ON;
4773    
4774   st = getstatus(jp);   st = getstatus(jp);
4775  #if JOBS  #if JOBS
4776   if (jp->jobctl) {   if (jp->jobctl) {
# Line 4786  openhere(union node *redir) Line 4906  openhere(union node *redir)
4906   if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {   if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4907   /* child */   /* child */
4908   close(pip[0]);   close(pip[0]);
4909   signal(SIGINT, SIG_IGN);   ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
4910   signal(SIGQUIT, SIG_IGN);   ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
4911   signal(SIGHUP, SIG_IGN);   ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
4912  #ifdef SIGTSTP   ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
  signal(SIGTSTP, SIG_IGN);  
 #endif  
4913   signal(SIGPIPE, SIG_DFL);   signal(SIGPIPE, SIG_DFL);
4914   if (redir->type == NHERE)   if (redir->type == NHERE)
4915   full_write(pip[1], redir->nhere.doc->narg.text, len);   full_write(pip[1], redir->nhere.doc->narg.text, len);
# Line 4911  struct redirtab { Line 5029  struct redirtab {
5029   struct redirtab *next;   struct redirtab *next;
5030   int nullredirs;   int nullredirs;
5031   int pair_count;   int pair_count;
5032   struct two_fd_t two_fd[0];   struct two_fd_t two_fd[];
5033  };  };
5034  #define redirlist (G_var.redirlist)  #define redirlist (G_var.redirlist)
5035    
# Line 4990  redirect(union node *redir, int flags) Line 5108  redirect(union node *redir, int flags)
5108   do {   do {
5109   sv_pos++;   sv_pos++;
5110  #if ENABLE_ASH_BASH_COMPAT  #if ENABLE_ASH_BASH_COMPAT
5111   if (redir->nfile.type == NTO2)   if (tmp->nfile.type == NTO2)
5112   sv_pos++;   sv_pos++;
5113  #endif  #endif
5114   tmp = tmp->nfile.next;   tmp = tmp->nfile.next;
# Line 5168  redirectsafe(union node *redir, int flag Line 5286  redirectsafe(union node *redir, int flag
5286   redirect(redir, flags);   redirect(redir, flags);
5287   }   }
5288   exception_handler = savehandler;   exception_handler = savehandler;
5289   if (err && exception != EXERROR)   if (err && exception_type != EXERROR)
5290   longjmp(exception_handler->loc, 1);   longjmp(exception_handler->loc, 1);
5291   RESTORE_INT(saveint);   RESTORE_INT(saveint);
5292   return err;   return err;
# Line 5180  redirectsafe(union node *redir, int flag Line 5298  redirectsafe(union node *redir, int flag
5298   * We have to deal with backquotes, shell variables, and file metacharacters.   * We have to deal with backquotes, shell variables, and file metacharacters.
5299   */   */
5300    
5301  #if ENABLE_ASH_MATH_SUPPORT_64  #if ENABLE_SH_MATH_SUPPORT
5302  typedef int64_t arith_t;  static arith_t
5303  #define arith_t_type long long  ash_arith(const char *s)
5304  #else  {
5305  typedef long arith_t;   arith_eval_hooks_t math_hooks;
5306  #define arith_t_type long   arith_t result;
5307  #endif   int errcode = 0;
5308    
5309     math_hooks.lookupvar = lookupvar;
5310     math_hooks.setvar    = setvar2;
5311     math_hooks.endofname = endofname;
5312    
5313     INT_OFF;
5314     result = arith(s, &errcode, &math_hooks);
5315     if (errcode < 0) {
5316     if (errcode == -3)
5317     ash_msg_and_raise_error("exponent less than 0");
5318     if (errcode == -2)
5319     ash_msg_and_raise_error("divide by zero");
5320     if (errcode == -5)
5321     ash_msg_and_raise_error("expression recursion loop detected");
5322     raise_error_syntax(s);
5323     }
5324     INT_ON;
5325    
5326  #if ENABLE_ASH_MATH_SUPPORT   return result;
5327  static arith_t dash_arith(const char *);  }
 static arith_t arith(const char *expr, int *perrcode);  
5328  #endif  #endif
5329    
5330  /*  /*
# Line 5206  static arith_t arith(const char *expr, i Line 5340  static arith_t arith(const char *expr, i
5340  #define EXP_WORD        0x80    /* expand word in parameter expansion */  #define EXP_WORD        0x80    /* expand word in parameter expansion */
5341  #define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */  #define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
5342  /*  /*
5343   * _rmescape() flags   * rmescape() flags
5344   */   */
5345  #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */  #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
5346  #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */  #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
# Line 5250  cvtnum(arith_t num) Line 5384  cvtnum(arith_t num)
5384   int len;   int len;
5385    
5386   expdest = makestrspace(32, expdest);   expdest = makestrspace(32, expdest);
5387  #if ENABLE_ASH_MATH_SUPPORT_64   len = fmtstr(expdest, 32, arith_t_fmt, num);
  len = fmtstr(expdest, 32, "%lld", (long long) num);  
 #else  
  len = fmtstr(expdest, 32, "%ld", num);  
 #endif  
5388   STADJUST(len, expdest);   STADJUST(len, expdest);
5389   return len;   return len;
5390  }  }
# Line 5264  esclen(const char *start, const char *p) Line 5394  esclen(const char *start, const char *p)
5394  {  {
5395   size_t esc = 0;   size_t esc = 0;
5396    
5397   while (p > start && *--p == CTLESC) {   while (p > start && (unsigned char)*--p == CTLESC) {
5398   esc++;   esc++;
5399   }   }
5400   return esc;   return esc;
# Line 5274  esclen(const char *start, const char *p) Line 5404  esclen(const char *start, const char *p)
5404   * Remove any CTLESC characters from a string.   * Remove any CTLESC characters from a string.
5405   */   */
5406  static char *  static char *
5407  _rmescapes(char *str, int flag)  rmescapes(char *str, int flag)
5408  {  {
5409   static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };   static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5410    
5411   char *p, *q, *r;   char *p, *q, *r;
5412   unsigned inquotes;   unsigned inquotes;
5413   int notescaped;   unsigned protect_against_glob;
5414   int globbing;   unsigned globbing;
5415    
5416   p = strpbrk(str, qchars);   p = strpbrk(str, qchars);
5417   if (!p) {   if (!p)
5418   return str;   return str;
5419   }  
5420   q = p;   q = p;
5421   r = str;   r = str;
5422   if (flag & RMESCAPE_ALLOC) {   if (flag & RMESCAPE_ALLOC) {
# Line 5305  _rmescapes(char *str, int flag) Line 5435  _rmescapes(char *str, int flag)
5435   q = (char *)memcpy(q, str, len) + len;   q = (char *)memcpy(q, str, len) + len;
5436   }   }
5437   }   }
5438    
5439   inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;   inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5440   globbing = flag & RMESCAPE_GLOB;   globbing = flag & RMESCAPE_GLOB;
5441   notescaped = globbing;   protect_against_glob = globbing;
5442   while (*p) {   while (*p) {
5443   if (*p == CTLQUOTEMARK) {   if ((unsigned char)*p == CTLQUOTEMARK) {
5444    // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5445    // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5446    // Note: both inquotes and protect_against_glob only affect whether
5447    // CTLESC,<ch> gets converted to <ch> or to \<ch>
5448   inquotes = ~inquotes;   inquotes = ~inquotes;
5449   p++;   p++;
5450   notescaped = globbing;   protect_against_glob = globbing;
5451   continue;   continue;
5452   }   }
5453   if (*p == '\\') {   if (*p == '\\') {
5454   /* naked back slash */   /* naked back slash */
5455   notescaped = 0;   protect_against_glob = 0;
5456   goto copy;   goto copy;
5457   }   }
5458   if (*p == CTLESC) {   if ((unsigned char)*p == CTLESC) {
5459   p++;   p++;
5460   if (notescaped && inquotes && *p != '/') {   if (protect_against_glob && inquotes && *p != '/') {
5461   *q++ = '\\';   *q++ = '\\';
5462   }   }
5463   }   }
5464   notescaped = globbing;   protect_against_glob = globbing;
5465   copy:   copy:
5466   *q++ = *p++;   *q++ = *p++;
5467   }   }
# Line 5337  _rmescapes(char *str, int flag) Line 5472  _rmescapes(char *str, int flag)
5472   }   }
5473   return r;   return r;
5474  }  }
 #define rmescapes(p) _rmescapes((p), 0)  
   
5475  #define pmatch(a, b) !fnmatch((a), (b), 0)  #define pmatch(a, b) !fnmatch((a), (b), 0)
5476    
5477  /*  /*
# Line 5353  preglob(const char *pattern, int quoted, Line 5486  preglob(const char *pattern, int quoted,
5486   if (quoted) {   if (quoted) {
5487   flag |= RMESCAPE_QUOTED;   flag |= RMESCAPE_QUOTED;
5488   }   }
5489   return _rmescapes((char *)pattern, flag);   return rmescapes((char *)pattern, flag);
5490  }  }
5491    
5492  /*  /*
# Line 5364  memtodest(const char *p, size_t len, int Line 5497  memtodest(const char *p, size_t len, int
5497  {  {
5498   char *q = expdest;   char *q = expdest;
5499    
5500   q = makestrspace(len * 2, q);   q = makestrspace(quotes ? len * 2 : len, q);
5501    
5502   while (len--) {   while (len--) {
5503   int c = signed_char2int(*p++);   unsigned char c = *p++;
5504   if (!c)   if (c == '\0')
5505   continue;   continue;
5506   if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))   if (quotes) {
5507   USTPUTC(CTLESC, q);   int n = SIT(c, syntax);
5508     if (n == CCTL || n == CBACK)
5509     USTPUTC(CTLESC, q);
5510     }
5511   USTPUTC(c, q);   USTPUTC(c, q);
5512   }   }
5513    
# Line 5448  removerecordregions(int endoff) Line 5584  removerecordregions(int endoff)
5584  }  }
5585    
5586  static char *  static char *
5587  exptilde(char *startp, char *p, int flag)  exptilde(char *startp, char *p, int flags)
5588  {  {
5589   char c;   unsigned char c;
5590   char *name;   char *name;
5591   struct passwd *pw;   struct passwd *pw;
5592   const char *home;   const char *home;
5593   int quotes = flag & (EXP_FULL | EXP_CASE);   int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
5594   int startloc;   int startloc;
5595    
5596   name = p + 1;   name = p + 1;
# Line 5466  exptilde(char *startp, char *p, int flag Line 5602  exptilde(char *startp, char *p, int flag
5602   case CTLQUOTEMARK:   case CTLQUOTEMARK:
5603   return startp;   return startp;
5604   case ':':   case ':':
5605   if (flag & EXP_VARTILDE)   if (flags & EXP_VARTILDE)
5606   goto done;   goto done;
5607   break;   break;
5608   case '/':   case '/':
# Line 5514  static uint8_t back_exitstatus; /* exit Line 5650  static uint8_t back_exitstatus; /* exit
5650  #define EV_EXIT 01              /* exit after evaluating tree */  #define EV_EXIT 01              /* exit after evaluating tree */
5651  static void evaltree(union node *, int);  static void evaltree(union node *, int);
5652    
5653  static void  static void FAST_FUNC
5654  evalbackcmd(union node *n, struct backcmd *result)  evalbackcmd(union node *n, struct backcmd *result)
5655  {  {
5656   int saveherefd;   int saveherefd;
# Line 5523  evalbackcmd(union node *n, struct backcm Line 5659  evalbackcmd(union node *n, struct backcm
5659   result->buf = NULL;   result->buf = NULL;
5660   result->nleft = 0;   result->nleft = 0;
5661   result->jp = NULL;   result->jp = NULL;
5662   if (n == NULL) {   if (n == NULL)
5663   goto out;   goto out;
  }  
5664    
5665   saveherefd = herefd;   saveherefd = herefd;
5666   herefd = -1;   herefd = -1;
# Line 5619  expbackq(union node *cmd, int quoted, in Line 5754  expbackq(union node *cmd, int quoted, in
5754   stackblock() + startloc));   stackblock() + startloc));
5755  }  }
5756    
5757  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
5758  /*  /*
5759   * Expand arithmetic expression.  Backup to start of expression,   * Expand arithmetic expression.  Backup to start of expression,
5760   * evaluate, place result in (backed up) result, adjust string position.   * evaluate, place result in (backed up) result, adjust string position.
# Line 5632  expari(int quotes) Line 5767  expari(int quotes)
5767   int flag;   int flag;
5768   int len;   int len;
5769    
5770   /*      ifsfree(); */   /* ifsfree(); */
5771    
5772   /*   /*
5773   * This routine is slightly over-complicated for   * This routine is slightly over-complicated for
# Line 5646  expari(int quotes) Line 5781  expari(int quotes)
5781   do {   do {
5782   int esc;   int esc;
5783    
5784   while (*p != CTLARI) {   while ((unsigned char)*p != CTLARI) {
5785   p--;   p--;
5786  #if DEBUG  #if DEBUG
5787   if (p < start) {   if (p < start) {
# Line 5672  expari(int quotes) Line 5807  expari(int quotes)
5807   expdest = p;   expdest = p;
5808    
5809   if (quotes)   if (quotes)
5810   rmescapes(p + 2);   rmescapes(p + 2, 0);
5811    
5812   len = cvtnum(dash_arith(p + 2));   len = cvtnum(ash_arith(p + 2));
5813    
5814   if (flag != '"')   if (flag != '"')
5815   recordregion(begoff, begoff + len, 0);   recordregion(begoff, begoff + len, 0);
# Line 5682  expari(int quotes) Line 5817  expari(int quotes)
5817  #endif  #endif
5818    
5819  /* argstr needs it */  /* argstr needs it */
5820  static char *evalvar(char *p, int flag, struct strlist *var_str_list);  static char *evalvar(char *p, int flags, struct strlist *var_str_list);
5821    
5822  /*  /*
5823   * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC   * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
# Line 5694  static char *evalvar(char *p, int flag, Line 5829  static char *evalvar(char *p, int flag,
5829   * for correct expansion of "B=$A" word.   * for correct expansion of "B=$A" word.
5830   */   */
5831  static void  static void
5832  argstr(char *p, int flag, struct strlist *var_str_list)  argstr(char *p, int flags, struct strlist *var_str_list)
5833  {  {
5834   static const char spclchars[] ALIGN1 = {   static const char spclchars[] ALIGN1 = {
5835   '=',   '=',
# Line 5705  argstr(char *p, int flag, struct strlist Line 5840  argstr(char *p, int flag, struct strlist
5840   CTLVAR,   CTLVAR,
5841   CTLBACKQ,   CTLBACKQ,
5842   CTLBACKQ | CTLQUOTE,   CTLBACKQ | CTLQUOTE,
5843  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
5844   CTLENDARI,   CTLENDARI,
5845  #endif  #endif
5846   0   '\0'
5847   };   };
5848   const char *reject = spclchars;   const char *reject = spclchars;
5849   int c;   int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
5850   int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */   int breakall = flags & EXP_WORD;
  int breakall = flag & EXP_WORD;  
5851   int inquotes;   int inquotes;
5852   size_t length;   size_t length;
5853   int startloc;   int startloc;
5854    
5855   if (!(flag & EXP_VARTILDE)) {   if (!(flags & EXP_VARTILDE)) {
5856   reject += 2;   reject += 2;
5857   } else if (flag & EXP_VARTILDE2) {   } else if (flags & EXP_VARTILDE2) {
5858   reject++;   reject++;
5859   }   }
5860   inquotes = 0;   inquotes = 0;
5861   length = 0;   length = 0;
5862   if (flag & EXP_TILDE) {   if (flags & EXP_TILDE) {
5863   char *q;   char *q;
5864    
5865   flag &= ~EXP_TILDE;   flags &= ~EXP_TILDE;
5866   tilde:   tilde:
5867   q = p;   q = p;
5868   if (*q == CTLESC && (flag & EXP_QWORD))   if (*q == CTLESC && (flags & EXP_QWORD))
5869   q++;   q++;
5870   if (*q == '~')   if (*q == '~')
5871   p = exptilde(p, q, flag);   p = exptilde(p, q, flags);
5872   }   }
5873   start:   start:
5874   startloc = expdest - (char *)stackblock();   startloc = expdest - (char *)stackblock();
5875   for (;;) {   for (;;) {
5876     unsigned char c;
5877    
5878   length += strcspn(p + length, reject);   length += strcspn(p + length, reject);
5879   c = p[length];   c = p[length];
5880   if (c && (!(c & 0x80)   if (c) {
5881  #if ENABLE_ASH_MATH_SUPPORT   if (!(c & 0x80)
5882   || c == CTLENDARI  #if ENABLE_SH_MATH_SUPPORT
5883     || c == CTLENDARI
5884  #endif  #endif
5885     )) {   ) {
5886   /* c == '=' || c == ':' || c == CTLENDARI */   /* c == '=' || c == ':' || c == CTLENDARI */
5887   length++;   length++;
5888     }
5889   }   }
5890   if (length > 0) {   if (length > 0) {
5891   int newloc;   int newloc;
# Line 5765  argstr(char *p, int flag, struct strlist Line 5903  argstr(char *p, int flag, struct strlist
5903   case '\0':   case '\0':
5904   goto breakloop;   goto breakloop;
5905   case '=':   case '=':
5906   if (flag & EXP_VARTILDE2) {   if (flags & EXP_VARTILDE2) {
5907   p--;   p--;
5908   continue;   continue;
5909   }   }
5910   flag |= EXP_VARTILDE2;   flags |= EXP_VARTILDE2;
5911   reject++;   reject++;
5912   /* fall through */   /* fall through */
5913   case ':':   case ':':
# Line 5788  argstr(char *p, int flag, struct strlist Line 5926  argstr(char *p, int flag, struct strlist
5926   goto breakloop;   goto breakloop;
5927   case CTLQUOTEMARK:   case CTLQUOTEMARK:
5928   /* "$@" syntax adherence hack */   /* "$@" syntax adherence hack */
5929   if (   if (!inquotes
5930   !inquotes &&   && memcmp(p, dolatstr, 4) == 0
5931   !memcmp(p, dolatstr, 4) &&   && (  p[4] == CTLQUOTEMARK
5932   (p[4] == CTLQUOTEMARK || (      || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK)
5933   p[4] == CTLENDVAR &&      )
  p[5] == CTLQUOTEMARK  
  ))  
5934   ) {   ) {
5935   p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;   p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
5936   goto start;   goto start;
5937   }   }
5938   inquotes = !inquotes;   inquotes = !inquotes;
# Line 5812  argstr(char *p, int flag, struct strlist Line 5948  argstr(char *p, int flag, struct strlist
5948   length++;   length++;
5949   goto addquote;   goto addquote;
5950   case CTLVAR:   case CTLVAR:
5951   p = evalvar(p, flag, var_str_list);   p = evalvar(p, flags, var_str_list);
5952   goto start;   goto start;
5953   case CTLBACKQ:   case CTLBACKQ:
5954   c = 0;   c = '\0';
5955   case CTLBACKQ|CTLQUOTE:   case CTLBACKQ|CTLQUOTE:
5956   expbackq(argbackq->n, c, quotes);   expbackq(argbackq->n, c, quotes);
5957   argbackq = argbackq->next;   argbackq = argbackq->next;
5958   goto start;   goto start;
5959  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
5960   case CTLENDARI:   case CTLENDARI:
5961   p--;   p--;
5962   expari(quotes);   expari(quotes);
# Line 5895  scanleft(char *startp, char *rmesc, char Line 6031  scanleft(char *startp, char *rmesc, char
6031   *loc2 = c;   *loc2 = c;
6032   if (match) // if (!match)   if (match) // if (!match)
6033   return loc;   return loc;
6034   if (quotes && *loc == CTLESC)   if (quotes && (unsigned char)*loc == CTLESC)
6035   loc++;   loc++;
6036   loc++;   loc++;
6037   loc2++;   loc2++;
# Line 5947  varunset(const char *end, const char *va Line 6083  varunset(const char *end, const char *va
6083   tail = nullstr;   tail = nullstr;
6084   msg = "parameter not set";   msg = "parameter not set";
6085   if (umsg) {   if (umsg) {
6086   if (*end == CTLENDVAR) {   if ((unsigned char)*end == CTLENDVAR) {
6087   if (varflags & VSNUL)   if (varflags & VSNUL)
6088   tail = " or null";   tail = " or null";
6089   } else   } else {
6090   msg = umsg;   msg = umsg;
6091     }
6092   }   }
6093   ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);   ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
6094  }  }
# Line 5994  subevalvar(char *p, char *str, int strlo Line 6131  subevalvar(char *p, char *str, int strlo
6131   char *startp;   char *startp;
6132   char *loc;   char *loc;
6133   char *rmesc, *rmescend;   char *rmesc, *rmescend;
6134   USE_ASH_BASH_COMPAT(char *repl = NULL;)   IF_ASH_BASH_COMPAT(char *repl = NULL;)
6135   USE_ASH_BASH_COMPAT(char null = '\0';)   IF_ASH_BASH_COMPAT(char null = '\0';)
6136   USE_ASH_BASH_COMPAT(int pos, len, orig_len;)   IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6137   int saveherefd = herefd;   int saveherefd = herefd;
6138   int amount, workloc, resetloc;   int amount, workloc, resetloc;
6139   int zero;   int zero;
# Line 6020  subevalvar(char *p, char *str, int strlo Line 6157  subevalvar(char *p, char *str, int strlo
6157  #if ENABLE_ASH_BASH_COMPAT  #if ENABLE_ASH_BASH_COMPAT
6158   case VSSUBSTR:   case VSSUBSTR:
6159   loc = str = stackblock() + strloc;   loc = str = stackblock() + strloc;
6160  // TODO: number() instead? It does error checking...   /* Read POS in ${var:POS:LEN} */
6161   pos = atoi(loc);   pos = atoi(loc); /* number(loc) errors out on "1:4" */
6162   len = str - startp - 1;   len = str - startp - 1;
6163    
6164   /* *loc != '\0', guaranteed by parser */   /* *loc != '\0', guaranteed by parser */
6165   if (quotes) {   if (quotes) {
6166   char *ptr;   char *ptr;
6167    
6168   /* We must adjust the length by the number of escapes we find. */   /* Adjust the length by the number of escapes */
6169   for (ptr = startp; ptr < (str - 1); ptr++) {   for (ptr = startp; ptr < (str - 1); ptr++) {
6170   if (*ptr == CTLESC) {   if ((unsigned char)*ptr == CTLESC) {
6171   len--;   len--;
6172   ptr++;   ptr++;
6173   }   }
# Line 6039  subevalvar(char *p, char *str, int strlo Line 6176  subevalvar(char *p, char *str, int strlo
6176   orig_len = len;   orig_len = len;
6177    
6178   if (*loc++ == ':') {   if (*loc++ == ':') {
6179  // TODO: number() instead? It does error checking...   /* ${var::LEN} */
6180   len = atoi(loc);   len = number(loc);
6181   } else {   } else {
6182     /* Skip POS in ${var:POS:LEN} */
6183   len = orig_len;   len = orig_len;
6184   while (*loc && *loc != ':')   while (*loc && *loc != ':') {
6185     /* TODO?
6186     * bash complains on: var=qwe; echo ${var:1a:123}
6187     if (!isdigit(*loc))
6188     ash_msg_and_raise_error(msg_illnum, str);
6189     */
6190   loc++;   loc++;
6191   if (*loc++ == ':')   }
6192  // TODO: number() instead? It does error checking...   if (*loc++ == ':') {
6193   len = atoi(loc);   len = number(loc);
6194     }
6195   }   }
6196   if (pos >= orig_len) {   if (pos >= orig_len) {
6197   pos = 0;   pos = 0;
# Line 6057  subevalvar(char *p, char *str, int strlo Line 6201  subevalvar(char *p, char *str, int strlo
6201   len = orig_len - pos;   len = orig_len - pos;
6202    
6203   for (str = startp; pos; str++, pos--) {   for (str = startp; pos; str++, pos--) {
6204   if (quotes && *str == CTLESC)   if (quotes && (unsigned char)*str == CTLESC)
6205   str++;   str++;
6206   }   }
6207   for (loc = startp; len; len--) {   for (loc = startp; len; len--) {
6208   if (quotes && *str == CTLESC)   if (quotes && (unsigned char)*str == CTLESC)
6209   *loc++ = *str++;   *loc++ = *str++;
6210   *loc++ = *str++;   *loc++ = *str++;
6211   }   }
# Line 6082  subevalvar(char *p, char *str, int strlo Line 6226  subevalvar(char *p, char *str, int strlo
6226   * stack will need rebasing, and we'll need to remove our work   * stack will need rebasing, and we'll need to remove our work
6227   * areas each time   * areas each time
6228   */   */
6229   USE_ASH_BASH_COMPAT(restart:)   IF_ASH_BASH_COMPAT(restart:)
6230    
6231   amount = expdest - ((char *)stackblock() + resetloc);   amount = expdest - ((char *)stackblock() + resetloc);
6232   STADJUST(-amount, expdest);   STADJUST(-amount, expdest);
# Line 6091  subevalvar(char *p, char *str, int strlo Line 6235  subevalvar(char *p, char *str, int strlo
6235   rmesc = startp;   rmesc = startp;
6236   rmescend = (char *)stackblock() + strloc;   rmescend = (char *)stackblock() + strloc;
6237   if (quotes) {   if (quotes) {
6238   rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);   rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6239   if (rmesc != startp) {   if (rmesc != startp) {
6240   rmescend = expdest;   rmescend = expdest;
6241   startp = (char *)stackblock() + startloc;   startp = (char *)stackblock() + startloc;
# Line 6125  subevalvar(char *p, char *str, int strlo Line 6269  subevalvar(char *p, char *str, int strlo
6269   /* No match, advance */   /* No match, advance */
6270   restart_detect = stackblock();   restart_detect = stackblock();
6271   STPUTC(*idx, expdest);   STPUTC(*idx, expdest);
6272   if (quotes && *idx == CTLESC) {   if (quotes && (unsigned char)*idx == CTLESC) {
6273   idx++;   idx++;
6274   len++;   len++;
6275   STPUTC(*idx, expdest);   STPUTC(*idx, expdest);
# Line 6140  subevalvar(char *p, char *str, int strlo Line 6284  subevalvar(char *p, char *str, int strlo
6284    
6285   if (subtype == VSREPLACEALL) {   if (subtype == VSREPLACEALL) {
6286   while (idx < loc) {   while (idx < loc) {
6287   if (quotes && *idx == CTLESC)   if (quotes && (unsigned char)*idx == CTLESC)
6288   idx++;   idx++;
6289   idx++;   idx++;
6290   rmesc++;   rmesc++;
6291   }   }
6292   } else   } else {
6293   idx = loc;   idx = loc;
6294     }
6295    
6296   for (loc = repl; *loc; loc++) {   for (loc = repl; *loc; loc++) {
6297   restart_detect = stackblock();   restart_detect = stackblock();
# Line 6207  subevalvar(char *p, char *str, int strlo Line 6352  subevalvar(char *p, char *str, int strlo
6352    
6353  /*  /*
6354   * Add the value of a specialized variable to the stack string.   * Add the value of a specialized variable to the stack string.
6355     * name parameter (examples):
6356     * ash -c 'echo $1'      name:'1='
6357     * ash -c 'echo $qwe'    name:'qwe='
6358     * ash -c 'echo $$'      name:'$='
6359     * ash -c 'echo ${$}'    name:'$='
6360     * ash -c 'echo ${$##q}' name:'$=q'
6361     * ash -c 'echo ${#$}'   name:'$='
6362     * note: examples with bad shell syntax:
6363     * ash -c 'echo ${#$1}'  name:'$=1'
6364     * ash -c 'echo ${#1#}'  name:'1=#'
6365   */   */
6366  static ssize_t  static NOINLINE ssize_t
6367  varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)  varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6368  {  {
6369     const char *p;
6370   int num;   int num;
  char *p;  
6371   int i;   int i;
  int sep = 0;  
6372   int sepq = 0;   int sepq = 0;
6373   ssize_t len = 0;   ssize_t len = 0;
  char **ap;  
  int syntax;  
  int quoted = varflags & VSQUOTE;  
6374   int subtype = varflags & VSTYPE;   int subtype = varflags & VSTYPE;
6375   int quotes = flags & (EXP_FULL | EXP_CASE);   int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
6376     int quoted = varflags & VSQUOTE;
6377   if (quoted && (flags & EXP_FULL))   int syntax = quoted ? DQSYNTAX : BASESYNTAX;
  sep = 1 << CHAR_BIT;  
6378    
  syntax = quoted ? DQSYNTAX : BASESYNTAX;  
6379   switch (*name) {   switch (*name) {
6380   case '$':   case '$':
6381   num = rootpid;   num = rootpid;
# Line 6243  varvalue(char *name, int varflags, int f Line 6392  varvalue(char *name, int varflags, int f
6392   return -1;   return -1;
6393   numvar:   numvar:
6394   len = cvtnum(num);   len = cvtnum(num);
6395   break;   goto check_1char_name;
6396   case '-':   case '-':
6397   p = makestrspace(NOPTS, expdest);   expdest = makestrspace(NOPTS, expdest);
6398   for (i = NOPTS - 1; i >= 0; i--) {   for (i = NOPTS - 1; i >= 0; i--) {
6399   if (optlist[i]) {   if (optlist[i]) {
6400   USTPUTC(optletters(i), p);   USTPUTC(optletters(i), expdest);
6401   len++;   len++;
6402   }   }
6403   }   }
6404   expdest = p;   check_1char_name:
6405    #if 0
6406     /* handles cases similar to ${#$1} */
6407     if (name[2] != '\0')
6408     raise_error_syntax("bad substitution");
6409    #endif
6410   break;   break;
6411   case '@':   case '@': {
6412   if (sep)   char **ap;
6413     int sep;
6414    
6415     if (quoted && (flags & EXP_FULL)) {
6416     /* note: this is not meant as PEOF value */
6417     sep = 1 << CHAR_BIT;
6418   goto param;   goto param;
6419     }
6420   /* fall through */   /* fall through */
6421   case '*':   case '*':
6422   sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';   sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6423   if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))   i = SIT(sep, syntax);
6424     if (quotes && (i == CCTL || i == CBACK))
6425   sepq = 1;   sepq = 1;
6426   param:   param:
6427   ap = shellparam.p;   ap = shellparam.p;
6428   if (!ap)   if (!ap)
6429   return -1;   return -1;
6430   while ((p = *ap++)) {   while ((p = *ap++) != NULL) {
6431   size_t partlen;   size_t partlen;
6432    
6433   partlen = strlen(p);   partlen = strlen(p);
# Line 6285  varvalue(char *name, int varflags, int f Line 6446  varvalue(char *name, int varflags, int f
6446   q = expdest;   q = expdest;
6447   if (sepq)   if (sepq)
6448   STPUTC(CTLESC, q);   STPUTC(CTLESC, q);
6449     /* note: may put NUL despite sep != 0
6450     * (see sep = 1 << CHAR_BIT above) */
6451   STPUTC(sep, q);   STPUTC(sep, q);
6452   expdest = q;   expdest = q;
6453   }   }
6454   }   }
6455   return len;   return len;
6456     } /* case '@' and '*' */
6457   case '0':   case '0':
6458   case '1':   case '1':
6459   case '2':   case '2':
# Line 6300  varvalue(char *name, int varflags, int f Line 6464  varvalue(char *name, int varflags, int f
6464   case '7':   case '7':
6465   case '8':   case '8':
6466   case '9':   case '9':
6467  // TODO: number() instead? It does error checking...   num = atoi(name); /* number(name) fails on ${N#str} etc */
  num = atoi(name);  
6468   if (num < 0 || num > shellparam.nparam)   if (num < 0 || num > shellparam.nparam)
6469   return -1;   return -1;
6470   p = num ? shellparam.p[num - 1] : arg0;   p = num ? shellparam.p[num - 1] : arg0;
# Line 6322  varvalue(char *name, int varflags, int f Line 6485  varvalue(char *name, int varflags, int f
6485   break;   break;
6486   eq++;   eq++;
6487   if (name_len == (unsigned)(eq - str)   if (name_len == (unsigned)(eq - str)
6488   && strncmp(str, name, name_len) == 0) {   && strncmp(str, name, name_len) == 0
6489     ) {
6490   p = eq;   p = eq;
6491   /* goto value; - WRONG! */   /* goto value; - WRONG! */
6492   /* think "A=1 A=2 B=$A" */   /* think "A=1 A=2 B=$A" */
# Line 6353  varvalue(char *name, int varflags, int f Line 6517  varvalue(char *name, int varflags, int f
6517   * input string.   * input string.
6518   */   */
6519  static char *  static char *
6520  evalvar(char *p, int flag, struct strlist *var_str_list)  evalvar(char *p, int flags, struct strlist *var_str_list)
6521  {  {
6522   char varflags;   char varflags;
6523   char subtype;   char subtype;
# Line 6364  evalvar(char *p, int flag, struct strlis Line 6528  evalvar(char *p, int flag, struct strlis
6528   int startloc;   int startloc;
6529   ssize_t varlen;   ssize_t varlen;
6530    
6531   varflags = *p++;   varflags = (unsigned char) *p++;
6532   subtype = varflags & VSTYPE;   subtype = varflags & VSTYPE;
6533   quoted = varflags & VSQUOTE;   quoted = varflags & VSQUOTE;
6534   var = p;   var = p;
# Line 6373  evalvar(char *p, int flag, struct strlis Line 6537  evalvar(char *p, int flag, struct strlis
6537   p = strchr(p, '=') + 1;   p = strchr(p, '=') + 1;
6538    
6539   again:   again:
6540   varlen = varvalue(var, varflags, flag, var_str_list);   varlen = varvalue(var, varflags, flags, var_str_list);
6541   if (varflags & VSNUL)   if (varflags & VSNUL)
6542   varlen--;   varlen--;
6543    
# Line 6386  evalvar(char *p, int flag, struct strlis Line 6550  evalvar(char *p, int flag, struct strlis
6550   vsplus:   vsplus:
6551   if (varlen < 0) {   if (varlen < 0) {
6552   argstr(   argstr(
6553   p, flag | EXP_TILDE |   p, flags | EXP_TILDE |
6554   (quoted ?  EXP_QWORD : EXP_WORD),   (quoted ? EXP_QWORD : EXP_WORD),
6555   var_str_list   var_str_list
6556   );   );
6557   goto end;   goto end;
# Line 6459  evalvar(char *p, int flag, struct strlis Line 6623  evalvar(char *p, int flag, struct strlis
6623   patloc = expdest - (char *)stackblock();   patloc = expdest - (char *)stackblock();
6624   if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,   if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6625   startloc, varflags,   startloc, varflags,
6626   /* quotes: */ flag & (EXP_FULL | EXP_CASE),  //TODO: | EXP_REDIR too? All other such places do it too
6627     /* quotes: */ flags & (EXP_FULL | EXP_CASE),
6628   var_str_list)   var_str_list)
6629   ) {   ) {
6630   int amount = expdest - (   int amount = expdest - (
# Line 6477  evalvar(char *p, int flag, struct strlis Line 6642  evalvar(char *p, int flag, struct strlis
6642   if (subtype != VSNORMAL) {      /* skip to end of alternative */   if (subtype != VSNORMAL) {      /* skip to end of alternative */
6643   int nesting = 1;   int nesting = 1;
6644   for (;;) {   for (;;) {
6645   char c = *p++;   unsigned char c = *p++;
6646   if (c == CTLESC)   if (c == CTLESC)
6647   p++;   p++;
6648   else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {   else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
# Line 6525  ifsbreakup(char *string, struct arglist Line 6690  ifsbreakup(char *string, struct arglist
6690   ifsspc = 0;   ifsspc = 0;
6691   while (p < string + ifsp->endoff) {   while (p < string + ifsp->endoff) {
6692   q = p;   q = p;
6693   if (*p == CTLESC)   if ((unsigned char)*p == CTLESC)
6694   p++;   p++;
6695   if (!strchr(ifs, *p)) {   if (!strchr(ifs, *p)) {
6696   p++;   p++;
# Line 6551  ifsbreakup(char *string, struct arglist Line 6716  ifsbreakup(char *string, struct arglist
6716   break;   break;
6717   }   }
6718   q = p;   q = p;
6719   if (*p == CTLESC)   if ((unsigned char)*p == CTLESC)
6720   p++;   p++;
6721   if (strchr(ifs, *p) == NULL) {   if (strchr(ifs, *p) == NULL) {
6722   p = q;   p = q;
# Line 6713  expmeta(char *enddir, char *name) Line 6878  expmeta(char *enddir, char *name)
6878   p++;   p++;
6879   if (*p == '.')   if (*p == '.')
6880   matchdot++;   matchdot++;
6881   while (!intpending && (dp = readdir(dirp)) != NULL) {   while (!pending_int && (dp = readdir(dirp)) != NULL) {
6882   if (dp->d_name[0] == '.' && !matchdot)   if (dp->d_name[0] == '.' && !matchdot)
6883   continue;   continue;
6884   if (pmatch(start, dp->d_name)) {   if (pmatch(start, dp->d_name)) {
# Line 6834  expandmeta(struct strlist *str /*, int f Line 6999  expandmeta(struct strlist *str /*, int f
6999   */   */
7000   nometa:   nometa:
7001   *exparg.lastp = str;   *exparg.lastp = str;
7002   rmescapes(str->text);   rmescapes(str->text, 0);
7003   exparg.lastp = &str->next;   exparg.lastp = &str->next;
7004   } else {   } else {
7005   *exparg.lastp = NULL;   *exparg.lastp = NULL;
# Line 6882  expandarg(union node *arg, struct arglis Line 7047  expandarg(union node *arg, struct arglis
7047   expandmeta(exparg.list /*, flag*/);   expandmeta(exparg.list /*, flag*/);
7048   } else {   } else {
7049   if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */   if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
7050   rmescapes(p);   rmescapes(p, 0);
7051   sp = stzalloc(sizeof(*sp));   sp = stzalloc(sizeof(*sp));
7052   sp->text = p;   sp->text = p;
7053   *exparg.lastp = sp;   *exparg.lastp = sp;
# Line 6943  casematch(union node *pattern, char *val Line 7108  casematch(union node *pattern, char *val
7108    
7109  struct builtincmd {  struct builtincmd {
7110   const char *name;   const char *name;
7111   int (*builtin)(int, char **);   int (*builtin)(int, char **) FAST_FUNC;
7112   /* unsigned flags; */   /* unsigned flags; */
7113  };  };
7114  #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)  #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
# Line 7008  static int builtinloc = -1;     /* index Line 7173  static int builtinloc = -1;     /* index
7173    
7174    
7175  static void  static void
7176  tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)  tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7177  {  {
7178   int repeated = 0;   int repeated = 0;
7179    
# Line 7080  shellexec(char **argv, const char *path, Line 7245  shellexec(char **argv, const char *path,
7245   || (applet_no = find_applet_by_name(argv[0])) >= 0   || (applet_no = find_applet_by_name(argv[0])) >= 0
7246  #endif  #endif
7247   ) {   ) {
7248   tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);   tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7249   e = errno;   e = errno;
7250   } else {   } else {
7251   e = ENOENT;   e = ENOENT;
7252   while ((cmdname = padvance(&path, argv[0])) != NULL) {   while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7253   if (--idx < 0 && pathopt == NULL) {   if (--idx < 0 && pathopt == NULL) {
7254   tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);   tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7255   if (errno != ENOENT && errno != ENOTDIR)   if (errno != ENOENT && errno != ENOTDIR)
7256   e = errno;   e = errno;
7257   }   }
# Line 7107  shellexec(char **argv, const char *path, Line 7272  shellexec(char **argv, const char *path,
7272   break;   break;
7273   }   }
7274   exitstatus = exerrno;   exitstatus = exerrno;
7275   TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",   TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7276   argv[0], e, suppressint));   argv[0], e, suppress_int));
7277   ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));   ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7278   /* NOTREACHED */   /* NOTREACHED */
7279  }  }
# Line 7123  printentry(struct tblentry *cmdp) Line 7288  printentry(struct tblentry *cmdp)
7288   idx = cmdp->param.index;   idx = cmdp->param.index;
7289   path = pathval();   path = pathval();
7290   do {   do {
7291   name = padvance(&path, cmdp->cmdname);   name = path_advance(&path, cmdp->cmdname);
7292   stunalloc(name);   stunalloc(name);
7293   } while (--idx >= 0);   } while (--idx >= 0);
7294   out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));   out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
# Line 7237  addcmdentry(char *name, struct cmdentry Line 7402  addcmdentry(char *name, struct cmdentry
7402   cmdp->rehash = 0;   cmdp->rehash = 0;
7403  }  }
7404    
7405  static int  static int FAST_FUNC
7406  hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7407  {  {
7408   struct tblentry **pp;   struct tblentry **pp;
# Line 7307  hashcd(void) Line 7472  hashcd(void)
7472   * pathval() still returns the old value at this point.   * pathval() still returns the old value at this point.
7473   * Called with interrupts off.   * Called with interrupts off.
7474   */   */
7475  static void  static void FAST_FUNC
7476  changepath(const char *new)  changepath(const char *new)
7477  {  {
7478   const char *old;   const char *old;
# Line 7495  describe_command(char *command, int desc Line 7660  describe_command(char *command, int desc
7660   p = command;   p = command;
7661   } else {   } else {
7662   do {   do {
7663   p = padvance(&path, command);   p = path_advance(&path, command);
7664   stunalloc(p);   stunalloc(p);
7665   } while (--j >= 0);   } while (--j >= 0);
7666   }   }
# Line 7535  describe_command(char *command, int desc Line 7700  describe_command(char *command, int desc
7700   return 127;   return 127;
7701   }   }
7702   out:   out:
7703   outstr("\n", stdout);   out1str("\n");
7704   return 0;   return 0;
7705  }  }
7706    
7707  static int  static int FAST_FUNC
7708  typecmd(int argc UNUSED_PARAM, char **argv)  typecmd(int argc UNUSED_PARAM, char **argv)
7709  {  {
7710   int i = 1;   int i = 1;
# Line 7558  typecmd(int argc UNUSED_PARAM, char **ar Line 7723  typecmd(int argc UNUSED_PARAM, char **ar
7723  }  }
7724    
7725  #if ENABLE_ASH_CMDCMD  #if ENABLE_ASH_CMDCMD
7726  static int  static int FAST_FUNC
7727  commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7728  {  {
7729   int c;   int c;
# Line 7598  static char *funcstring;        /* block Line 7763  static char *funcstring;        /* block
7763  #define EV_TESTED  02           /* exit status is checked; ignore -e flag */  #define EV_TESTED  02           /* exit status is checked; ignore -e flag */
7764  #define EV_BACKCMD 04           /* command executing within back quotes */  #define EV_BACKCMD 04           /* command executing within back quotes */
7765    
7766  static const short nodesize[N_NUMBER] = {  static const uint8_t nodesize[N_NUMBER] = {
7767   [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),   [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
7768   [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),   [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
7769   [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),   [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
# Line 7881  defun(char *name, union node *func) Line 8046  defun(char *name, union node *func)
8046   INT_ON;   INT_ON;
8047  }  }
8048    
8049  static int evalskip;            /* set if we are skipping commands */  /* Reasons for skipping commands (see comment on breakcmd routine) */
 /* reasons for skipping commands (see comment on breakcmd routine) */  
8050  #define SKIPBREAK      (1 << 0)  #define SKIPBREAK      (1 << 0)
8051  #define SKIPCONT       (1 << 1)  #define SKIPCONT       (1 << 1)
8052  #define SKIPFUNC       (1 << 2)  #define SKIPFUNC       (1 << 2)
8053  #define SKIPFILE       (1 << 3)  #define SKIPFILE       (1 << 3)
8054  #define SKIPEVAL       (1 << 4)  #define SKIPEVAL       (1 << 4)
8055    static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
8056  static int skipcount;           /* number of levels to skip */  static int skipcount;           /* number of levels to skip */
8057  static int funcnest;            /* depth of function calls */  static int funcnest;            /* depth of function calls */
8058  static int loopnest;            /* current loop nesting level */  static int loopnest;            /* current loop nesting level */
8059    
8060  /* forward decl way out to parsing code - dotrap needs it */  /* Forward decl way out to parsing code - dotrap needs it */
8061  static int evalstring(char *s, int mask);  static int evalstring(char *s, int mask);
8062    
8063  /*  /* Called to execute a trap.
8064   * Called to execute a trap.  Perhaps we should avoid entering new trap   * Single callsite - at the end of evaltree().
8065   * handlers while we are executing a trap handler.   * If we return non-zero, exaltree raises EXEXIT exception.
8066     *
8067     * Perhaps we should avoid entering new trap handlers
8068     * while we are executing a trap handler. [is it a TODO?]
8069   */   */
8070  static int  static int
8071  dotrap(void)  dotrap(void)
8072  {  {
8073   char *p;   uint8_t *g;
8074   char *q;   int sig;
8075   int i;   uint8_t savestatus;
  int savestatus;  
  int skip;  
8076    
8077   savestatus = exitstatus;   savestatus = exitstatus;
8078   pendingsig = 0;   pending_sig = 0;
8079   xbarrier();   xbarrier();
8080    
8081   TRACE(("dotrap entered\n"));   TRACE(("dotrap entered\n"));
8082   for (i = 1, q = gotsig; i < NSIG; i++, q++) {   for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8083   if (!*q)   int want_exexit;
8084   continue;   char *t;
8085    
8086   p = trap[i];   if (*g == 0)
8087     continue;
8088     t = trap[sig];
8089   /* non-trapped SIGINT is handled separately by raise_interrupt,   /* non-trapped SIGINT is handled separately by raise_interrupt,
8090   * don't upset it by resetting gotsig[SIGINT-1] */   * don't upset it by resetting gotsig[SIGINT-1] */
8091   if (i == SIGINT && !p)   if (sig == SIGINT && !t)
8092   continue;   continue;
8093    
8094   TRACE(("sig %d is active, will run handler '%s'\n", i, p));   TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8095   *q = '\0';   *g = 0;
8096   if (!p)   if (!t)
8097   continue;   continue;
8098   skip = evalstring(p, SKIPEVAL);   want_exexit = evalstring(t, SKIPEVAL);
8099   exitstatus = savestatus;   exitstatus = savestatus;
8100   if (skip) {   if (want_exexit) {
8101   TRACE(("dotrap returns %d\n", skip));   TRACE(("dotrap returns %d\n", want_exexit));
8102   return skip;   return want_exexit;
8103   }   }
8104   }   }
8105    
# Line 7970  evaltree(union node *n, int flags) Line 8138  evaltree(union node *n, int flags)
8138   TRACE(("evaltree(NULL) called\n"));   TRACE(("evaltree(NULL) called\n"));
8139   goto out1;   goto out1;
8140   }   }
8141   TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));   TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8142    
8143   exception_handler = &jmploc;   exception_handler = &jmploc;
8144   {   {
8145   int err = setjmp(jmploc.loc);   int err = setjmp(jmploc.loc);
8146   if (err) {   if (err) {
8147   /* if it was a signal, check for trap handlers */   /* if it was a signal, check for trap handlers */
8148   if (exception == EXSIG) {   if (exception_type == EXSIG) {
8149   TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", exception, err));   TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8150     exception_type, err));
8151   goto out;   goto out;
8152   }   }
8153   /* continue on the way out */   /* continue on the way out */
8154   TRACE(("exception %d in evaltree, propagating err=%d\n", exception, err));   TRACE(("exception %d in evaltree, propagating err=%d\n",
8155     exception_type, err));
8156   exception_handler = savehandler;   exception_handler = savehandler;
8157   longjmp(exception_handler->loc, err);   longjmp(exception_handler->loc, err);
8158   }   }
# Line 7992  evaltree(union node *n, int flags) Line 8162  evaltree(union node *n, int flags)
8162   default:   default:
8163  #if DEBUG  #if DEBUG
8164   out1fmt("Node type = %d\n", n->type);   out1fmt("Node type = %d\n", n->type);
8165   fflush(stdout);   fflush_all();
8166   break;   break;
8167  #endif  #endif
8168   case NNOT:   case NNOT:
# Line 8085  evaltree(union node *n, int flags) Line 8255  evaltree(union node *n, int flags)
8255   out1:   out1:
8256   if (checkexit & exitstatus)   if (checkexit & exitstatus)
8257   evalskip |= SKIPEVAL;   evalskip |= SKIPEVAL;
8258   else if (pendingsig && dotrap())   else if (pending_sig && dotrap())
8259   goto exexit;   goto exexit;
8260    
8261   if (flags & EV_EXIT) {   if (flags & EV_EXIT) {
# Line 8371  setinteractive(int on) Line 8541  setinteractive(int on)
8541   static smallint did_banner;   static smallint did_banner;
8542    
8543   if (!did_banner) {   if (!did_banner) {
8544   out1fmt(   /* note: ash and hush share this string */
8545   "\n\n"   out1fmt("\n\n%s %s\n"
  "%s built-in shell (ash)\n"  
8546   "Enter 'help' for a list of built-in commands."   "Enter 'help' for a list of built-in commands."
8547   "\n\n",   "\n\n",
8548   bb_banner);   bb_banner,
8549     "built-in shell (ash)"
8550     );
8551   did_banner = 1;   did_banner = 1;
8552   }   }
8553   }   }
# Line 8416  poplocalvars(void) Line 8587  poplocalvars(void)
8587   while ((lvp = localvars) != NULL) {   while ((lvp = localvars) != NULL) {
8588   localvars = lvp->next;   localvars = lvp->next;
8589   vp = lvp->vp;   vp = lvp->vp;
8590   TRACE(("poplocalvar %s", vp ? vp->text : "-"));   TRACE(("poplocalvar %s\n", vp ? vp->text : "-"));
8591   if (vp == NULL) {       /* $- saved */   if (vp == NULL) {       /* $- saved */
8592   memcpy(optlist, lvp->text, sizeof(optlist));   memcpy(optlist, lvp->text, sizeof(optlist));
8593   free((char*)lvp->text);   free((char*)lvp->text);
# Line 8564  mklocal(char *name) Line 8735  mklocal(char *name)
8735  /*  /*
8736   * The "local" command.   * The "local" command.
8737   */   */
8738  static int  static int FAST_FUNC
8739  localcmd(int argc UNUSED_PARAM, char **argv)  localcmd(int argc UNUSED_PARAM, char **argv)
8740  {  {
8741   char *name;   char *name;
# Line 8576  localcmd(int argc UNUSED_PARAM, char **a Line 8747  localcmd(int argc UNUSED_PARAM, char **a
8747   return 0;   return 0;
8748  }  }
8749    
8750  static int  static int FAST_FUNC
8751  falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8752  {  {
8753   return 1;   return 1;
8754  }  }
8755    
8756  static int  static int FAST_FUNC
8757  truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8758  {  {
8759   return 0;   return 0;
8760  }  }
8761    
8762  static int  static int FAST_FUNC
8763  execcmd(int argc UNUSED_PARAM, char **argv)  execcmd(int argc UNUSED_PARAM, char **argv)
8764  {  {
8765   if (argv[1]) {   if (argv[1]) {
# Line 8603  execcmd(int argc UNUSED_PARAM, char **ar Line 8774  execcmd(int argc UNUSED_PARAM, char **ar
8774  /*  /*
8775   * The return command.   * The return command.
8776   */   */
8777  static int  static int FAST_FUNC
8778  returncmd(int argc UNUSED_PARAM, char **argv)  returncmd(int argc UNUSED_PARAM, char **argv)
8779  {  {
8780   /*   /*
# Line 8615  returncmd(int argc UNUSED_PARAM, char ** Line 8786  returncmd(int argc UNUSED_PARAM, char **
8786  }  }
8787    
8788  /* Forward declarations for builtintab[] */  /* Forward declarations for builtintab[] */
8789  static int breakcmd(int, char **);  static int breakcmd(int, char **) FAST_FUNC;
8790  static int dotcmd(int, char **);  static int dotcmd(int, char **) FAST_FUNC;
8791  static int evalcmd(int, char **);  static int evalcmd(int, char **) FAST_FUNC;
8792  static int exitcmd(int, char **);  static int exitcmd(int, char **) FAST_FUNC;
8793  static int exportcmd(int, char **);  static int exportcmd(int, char **) FAST_FUNC;
8794  #if ENABLE_ASH_GETOPTS  #if ENABLE_ASH_GETOPTS
8795  static int getoptscmd(int, char **);  static int getoptscmd(int, char **) FAST_FUNC;
8796  #endif  #endif
8797  #if !ENABLE_FEATURE_SH_EXTRA_QUIET  #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8798  static int helpcmd(int, char **);  static int helpcmd(int, char **) FAST_FUNC;
8799  #endif  #endif
8800  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
8801  static int letcmd(int, char **);  static int letcmd(int, char **) FAST_FUNC;
8802  #endif  #endif
8803  static int readcmd(int, char **);  static int readcmd(int, char **) FAST_FUNC;
8804  static int setcmd(int, char **);  static int setcmd(int, char **) FAST_FUNC;
8805  static int shiftcmd(int, char **);  static int shiftcmd(int, char **) FAST_FUNC;
8806  static int timescmd(int, char **);  static int timescmd(int, char **) FAST_FUNC;
8807  static int trapcmd(int, char **);  static int trapcmd(int, char **) FAST_FUNC;
8808  static int umaskcmd(int, char **);  static int umaskcmd(int, char **) FAST_FUNC;
8809  static int unsetcmd(int, char **);  static int unsetcmd(int, char **) FAST_FUNC;
8810  static int ulimitcmd(int, char **);  static int ulimitcmd(int, char **) FAST_FUNC;
8811    
8812  #define BUILTIN_NOSPEC          "0"  #define BUILTIN_NOSPEC          "0"
8813  #define BUILTIN_SPECIAL         "1"  #define BUILTIN_SPECIAL         "1"
# Line 8647  static int ulimitcmd(int, char **); Line 8818  static int ulimitcmd(int, char **);
8818  #define BUILTIN_REG_ASSG        "6"  #define BUILTIN_REG_ASSG        "6"
8819  #define BUILTIN_SPEC_REG_ASSG   "7"  #define BUILTIN_SPEC_REG_ASSG   "7"
8820    
8821  /* We do not handle [[ expr ]] bashism bash-compatibly,  /* Stubs for calling non-FAST_FUNC's */
8822   * we make it a synonym of [ expr ].  #if ENABLE_ASH_BUILTIN_ECHO
8823   * Basically, word splitting and pathname expansion should NOT be performed  static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
8824   * Examples:  #endif
8825   * no word splitting:     a="a b"; [[ $a = "a b" ]]; echo $? should print "0"  #if ENABLE_ASH_BUILTIN_PRINTF
8826   * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"  static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
8827   * Additional operators:  #endif
8828   * || and && should work as -o and -a  #if ENABLE_ASH_BUILTIN_TEST
8829   * =~ regexp match  static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
8830   * Apart from the above, [[ expr ]] should work as [ expr ]  #endif
  */  
   
 #define echocmd   echo_main  
 #define printfcmd printf_main  
 #define testcmd   test_main  
8831    
8832  /* Keep these in proper order since it is searched via bsearch() */  /* Keep these in proper order since it is searched via bsearch() */
8833  static const struct builtincmd builtintab[] = {  static const struct builtincmd builtintab[] = {
# Line 8708  static const struct builtincmd builtinta Line 8874  static const struct builtincmd builtinta
8874   { BUILTIN_REGULAR       "jobs", jobscmd },   { BUILTIN_REGULAR       "jobs", jobscmd },
8875   { BUILTIN_REGULAR       "kill", killcmd },   { BUILTIN_REGULAR       "kill", killcmd },
8876  #endif  #endif
8877  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
8878   { BUILTIN_NOSPEC        "let", letcmd },   { BUILTIN_NOSPEC        "let", letcmd },
8879  #endif  #endif
8880   { BUILTIN_ASSIGN        "local", localcmd },   { BUILTIN_ASSIGN        "local", localcmd },
# Line 8784  isassignment(const char *p) Line 8950  isassignment(const char *p)
8950   return 0;   return 0;
8951   return *q == '=';   return *q == '=';
8952  }  }
8953  static int  static int FAST_FUNC
8954  bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8955  {  {
8956   /* Preserve exitstatus of a previous possible redirection   /* Preserve exitstatus of a previous possible redirection
# Line 8913  evalcommand(union node *cmd, int flags) Line 9079  evalcommand(union node *cmd, int flags)
9079   for (;;) {   for (;;) {
9080   find_command(argv[0], &cmdentry, cmd_flag, path);   find_command(argv[0], &cmdentry, cmd_flag, path);
9081   if (cmdentry.cmdtype == CMDUNKNOWN) {   if (cmdentry.cmdtype == CMDUNKNOWN) {
9082   flush_stderr();   flush_stdout_stderr();
9083   status = 127;   status = 127;
9084   goto bail;   goto bail;
9085   }   }
# Line 9003  evalcommand(union node *cmd, int flags) Line 9169  evalcommand(union node *cmd, int flags)
9169    
9170   if (evalbltin(cmdentry.u.cmd, argc, argv)) {   if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9171   int exit_status;   int exit_status;
9172   int i = exception;   int i = exception_type;
9173   if (i == EXEXIT)   if (i == EXEXIT)
9174   goto raise;   goto raise;
9175   exit_status = 2;   exit_status = 2;
9176   if (i == EXINT)   if (i == EXINT)
9177   exit_status = 128 + SIGINT;   exit_status = 128 + SIGINT;
9178   if (i == EXSIG)   if (i == EXSIG)
9179   exit_status = 128 + pendingsig;   exit_status = 128 + pending_sig;
9180   exitstatus = exit_status;   exitstatus = exit_status;
9181   if (i == EXINT || spclbltin > 0) {   if (i == EXINT || spclbltin > 0) {
9182   raise:   raise:
# Line 9064  evalbltin(const struct builtincmd *cmd, Line 9230  evalbltin(const struct builtincmd *cmd,
9230   exitstatus |= ferror(stdout);   exitstatus |= ferror(stdout);
9231   clearerr(stdout);   clearerr(stdout);
9232   commandname = savecmdname;   commandname = savecmdname;
 // exsig = 0;  
9233   exception_handler = savehandler;   exception_handler = savehandler;
9234    
9235   return i;   return i;
# Line 9109  prehash(union node *n) Line 9274  prehash(union node *n)
9274   * be an error to break out of more loops than exist, but it isn't   * be an error to break out of more loops than exist, but it isn't
9275   * in the standard shell so we don't make it one here.   * in the standard shell so we don't make it one here.
9276   */   */
9277  static int  static int FAST_FUNC
9278  breakcmd(int argc UNUSED_PARAM, char **argv)  breakcmd(int argc UNUSED_PARAM, char **argv)
9279  {  {
9280   int n = argv[1] ? number(argv[1]) : 1;   int n = argv[1] ? number(argv[1]) : 1;
9281    
9282   if (n <= 0)   if (n <= 0)
9283   ash_msg_and_raise_error(illnum, argv[1]);   ash_msg_and_raise_error(msg_illnum, argv[1]);
9284   if (n > loopnest)   if (n > loopnest)
9285   n = loopnest;   n = loopnest;
9286   if (n > 0) {   if (n > 0) {
# Line 9136  enum { Line 9301  enum {
9301   INPUT_NOFILE_OK = 2,   INPUT_NOFILE_OK = 2,
9302  };  };
9303    
 static int plinno = 1;                  /* input line number */  
 /* number of characters left in input buffer */  
 static int parsenleft;                  /* copy of parsefile->nleft */  
 static int parselleft;                  /* copy of parsefile->lleft */  
 /* next character in input buffer */  
 static char *parsenextc;                /* copy of parsefile->nextc */  
   
9304  static smallint checkkwd;  static smallint checkkwd;
9305  /* values of checkkwd variable */  /* values of checkkwd variable */
9306  #define CHKALIAS        0x1  #define CHKALIAS        0x1
9307  #define CHKKWD          0x2  #define CHKKWD          0x2
9308  #define CHKNL           0x4  #define CHKNL           0x4
9309    
9310    /*
9311     * Push a string back onto the input at this current parsefile level.
9312     * We handle aliases this way.
9313     */
9314    #if !ENABLE_ASH_ALIAS
9315    #define pushstring(s, ap) pushstring(s)
9316    #endif
9317    static void
9318    pushstring(char *s, struct alias *ap)
9319    {
9320     struct strpush *sp;
9321     int len;
9322    
9323     len = strlen(s);
9324     INT_OFF;
9325     if (g_parsefile->strpush) {
9326     sp = ckzalloc(sizeof(*sp));
9327     sp->prev = g_parsefile->strpush;
9328     } else {
9329     sp = &(g_parsefile->basestrpush);
9330     }
9331     g_parsefile->strpush = sp;
9332     sp->prev_string = g_parsefile->next_to_pgetc;
9333     sp->prev_left_in_line = g_parsefile->left_in_line;
9334    #if ENABLE_ASH_ALIAS
9335     sp->ap = ap;
9336     if (ap) {
9337     ap->flag |= ALIASINUSE;
9338     sp->string = s;
9339     }
9340    #endif
9341     g_parsefile->next_to_pgetc = s;
9342     g_parsefile->left_in_line = len;
9343     INT_ON;
9344    }
9345    
9346  static void  static void
9347  popstring(void)  popstring(void)
9348  {  {
# Line 9157  popstring(void) Line 9351  popstring(void)
9351   INT_OFF;   INT_OFF;
9352  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
9353   if (sp->ap) {   if (sp->ap) {
9354   if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {   if (g_parsefile->next_to_pgetc[-1] == ' '
9355     || g_parsefile->next_to_pgetc[-1] == '\t'
9356     ) {
9357   checkkwd |= CHKALIAS;   checkkwd |= CHKALIAS;
9358   }   }
9359   if (sp->string != sp->ap->val) {   if (sp->string != sp->ap->val) {
# Line 9169  popstring(void) Line 9365  popstring(void)
9365   }   }
9366   }   }
9367  #endif  #endif
9368   parsenextc = sp->prevstring;   g_parsefile->next_to_pgetc = sp->prev_string;
9369   parsenleft = sp->prevnleft;   g_parsefile->left_in_line = sp->prev_left_in_line;
9370   g_parsefile->strpush = sp->prev;   g_parsefile->strpush = sp->prev;
9371   if (sp != &(g_parsefile->basestrpush))   if (sp != &(g_parsefile->basestrpush))
9372   free(sp);   free(sp);
9373   INT_ON;   INT_ON;
9374  }  }
9375    
9376    //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9377    //it peeks whether it is &>, and then pushes back both chars.
9378    //This function needs to save last *next_to_pgetc to buf[0]
9379    //to make two pungetc() reliable. Currently,
9380    // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9381  static int  static int
9382  preadfd(void)  preadfd(void)
9383  {  {
9384   int nr;   int nr;
9385   char *buf = g_parsefile->buf;   char *buf = g_parsefile->buf;
  parsenextc = buf;  
9386    
9387     g_parsefile->next_to_pgetc = buf;
9388  #if ENABLE_FEATURE_EDITING  #if ENABLE_FEATURE_EDITING
9389   retry:   retry:
9390   if (!iflag || g_parsefile->fd != STDIN_FILENO)   if (!iflag || g_parsefile->fd != STDIN_FILENO)
# Line 9234  preadfd(void) Line 9435  preadfd(void)
9435   * Refill the input buffer and return the next input character:   * Refill the input buffer and return the next input character:
9436   *   *
9437   * 1) If a string was pushed back on the input, pop it;   * 1) If a string was pushed back on the input, pop it;
9438   * 2) If an EOF was pushed back (parsenleft < -BIGNUM) or we are reading   * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9439   *    from a string so we can't refill the buffer, return EOF.   *    or we are reading from a string so we can't refill the buffer,
9440   * 3) If the is more stuff in this buffer, use it else call read to fill it.   *    return EOF.
9441     * 3) If there is more stuff in this buffer, use it else call read to fill it.
9442   * 4) Process input up to the next newline, deleting nul characters.   * 4) Process input up to the next newline, deleting nul characters.
9443   */   */
9444  //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)  //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
# Line 9249  preadbuffer(void) Line 9451  preadbuffer(void)
9451    
9452   while (g_parsefile->strpush) {   while (g_parsefile->strpush) {
9453  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
9454   if (parsenleft == -1 && g_parsefile->strpush->ap   if (g_parsefile->left_in_line == -1
9455   && parsenextc[-1] != ' ' && parsenextc[-1] != '\t'   && g_parsefile->strpush->ap
9456     && g_parsefile->next_to_pgetc[-1] != ' '
9457     && g_parsefile->next_to_pgetc[-1] != '\t'
9458   ) {   ) {
9459   pgetc_debug("preadbuffer PEOA");   pgetc_debug("preadbuffer PEOA");
9460   return PEOA;   return PEOA;
# Line 9258  preadbuffer(void) Line 9462  preadbuffer(void)
9462  #endif  #endif
9463   popstring();   popstring();
9464   /* try "pgetc" now: */   /* try "pgetc" now: */
9465   pgetc_debug("internal pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc);   pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9466   if (--parsenleft >= 0)   g_parsefile->left_in_line,
9467   return signed_char2int(*parsenextc++);   g_parsefile->next_to_pgetc,
9468     g_parsefile->next_to_pgetc);
9469     if (--g_parsefile->left_in_line >= 0)
9470     return (unsigned char)(*g_parsefile->next_to_pgetc++);
9471   }   }
9472   /* on both branches above parsenleft < 0.   /* on both branches above g_parsefile->left_in_line < 0.
9473   * "pgetc" needs refilling.   * "pgetc" needs refilling.
9474   */   */
9475    
9476   /* -90 is -BIGNUM. Below we use -99 to mark "EOF on read",   /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9477   * pungetc() may decrement it a few times. -90 is enough.   * pungetc() may increment it a few times.
9478     * Assuming it won't increment it to less than -90.
9479   */   */
9480   if (parsenleft < -90 || g_parsefile->buf == NULL) {   if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9481   pgetc_debug("preadbuffer PEOF1");   pgetc_debug("preadbuffer PEOF1");
9482   /* even in failure keep them in lock step,   /* even in failure keep left_in_line and next_to_pgetc
9483   * for correct pungetc. */   * in lock step, for correct multi-layer pungetc.
9484   parsenextc++;   * left_in_line was decremented before preadbuffer(),
9485     * must inc next_to_pgetc: */
9486     g_parsefile->next_to_pgetc++;
9487   return PEOF;   return PEOF;
9488   }   }
9489    
9490   more = parselleft;   more = g_parsefile->left_in_buffer;
9491   if (more <= 0) {   if (more <= 0) {
9492   flush_stdout_stderr();   flush_stdout_stderr();
9493   again:   again:
9494   more = preadfd();   more = preadfd();
9495   if (more <= 0) {   if (more <= 0) {
9496   parselleft = parsenleft = -99;   /* don't try reading again */
9497     g_parsefile->left_in_line = -99;
9498   pgetc_debug("preadbuffer PEOF2");   pgetc_debug("preadbuffer PEOF2");
9499   parsenextc++;   g_parsefile->next_to_pgetc++;
9500   return PEOF;   return PEOF;
9501   }   }
9502   }   }
9503    
9504   /* Find out where's the end of line.   /* Find out where's the end of line.
9505   * Set parsenleft/parselleft acordingly.   * Set g_parsefile->left_in_line
9506     * and g_parsefile->left_in_buffer acordingly.
9507   * NUL chars are deleted.   * NUL chars are deleted.
9508   */   */
9509   q = parsenextc;   q = g_parsefile->next_to_pgetc;
9510   for (;;) {   for (;;) {
9511   char c;   char c;
9512    
# Line 9306  preadbuffer(void) Line 9518  preadbuffer(void)
9518   } else {   } else {
9519   q++;   q++;
9520   if (c == '\n') {   if (c == '\n') {
9521   parsenleft = q - parsenextc - 1;   g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9522   break;   break;
9523   }   }
9524   }   }
9525    
9526   if (more <= 0) {   if (more <= 0) {
9527   parsenleft = q - parsenextc - 1;   g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9528   if (parsenleft < 0)   if (g_parsefile->left_in_line < 0)
9529   goto again;   goto again;
9530   break;   break;
9531   }   }
9532   }   }
9533   parselleft = more;   g_parsefile->left_in_buffer = more;
9534    
9535   if (vflag) {   if (vflag) {
9536   char save = *q;   char save = *q;
9537   *q = '\0';   *q = '\0';
9538   out2str(parsenextc);   out2str(g_parsefile->next_to_pgetc);
9539   *q = save;   *q = save;
9540   }   }
9541    
9542   pgetc_debug("preadbuffer at %d:%p'%s'", parsenleft, parsenextc, parsenextc);   pgetc_debug("preadbuffer at %d:%p'%s'",
9543   return signed_char2int(*parsenextc++);   g_parsefile->left_in_line,
9544     g_parsefile->next_to_pgetc,
9545     g_parsefile->next_to_pgetc);
9546     return (unsigned char)*g_parsefile->next_to_pgetc++;
9547  }  }
9548    
9549  #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())  #define pgetc_as_macro() \
9550     (--g_parsefile->left_in_line >= 0 \
9551     ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9552     : preadbuffer() \
9553     )
9554    
9555  static int  static int
9556  pgetc(void)  pgetc(void)
9557  {  {
9558   pgetc_debug("pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc);   pgetc_debug("pgetc_fast at %d:%p'%s'",
9559     g_parsefile->left_in_line,
9560     g_parsefile->next_to_pgetc,
9561     g_parsefile->next_to_pgetc);
9562   return pgetc_as_macro();   return pgetc_as_macro();
9563  }  }
9564    
9565  #if ENABLE_ASH_OPTIMIZE_FOR_SIZE  #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9566  #define pgetc_fast() pgetc()  # define pgetc_fast() pgetc()
9567  #else  #else
9568  #define pgetc_fast() pgetc_as_macro()  # define pgetc_fast() pgetc_as_macro()
9569  #endif  #endif
9570    
 /*  
  * Same as pgetc(), but ignores PEOA.  
  */  
9571  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
9572  static int  static int
9573  pgetc2(void)  pgetc_without_PEOA(void)
9574  {  {
9575   int c;   int c;
9576   do {   do {
9577     pgetc_debug("pgetc_fast at %d:%p'%s'",
9578     g_parsefile->left_in_line,
9579     g_parsefile->next_to_pgetc,
9580     g_parsefile->next_to_pgetc);
9581   c = pgetc_fast();   c = pgetc_fast();
9582   } while (c == PEOA);   } while (c == PEOA);
9583   return c;   return c;
9584  }  }
9585  #else  #else
9586  #define pgetc2() pgetc()  # define pgetc_without_PEOA() pgetc()
9587  #endif  #endif
9588    
9589  /*  /*
# Line 9374  pfgets(char *line, int len) Line 9597  pfgets(char *line, int len)
9597   int c;   int c;
9598    
9599   while (--nleft > 0) {   while (--nleft > 0) {
9600   c = pgetc2();   c = pgetc_without_PEOA();
9601   if (c == PEOF) {   if (c == PEOF) {
9602   if (p == line)   if (p == line)
9603   return NULL;   return NULL;
# Line 9395  pfgets(char *line, int len) Line 9618  pfgets(char *line, int len)
9618  static void  static void
9619  pungetc(void)  pungetc(void)
9620  {  {
9621   parsenleft++;   g_parsefile->left_in_line++;
9622   parsenextc--;   g_parsefile->next_to_pgetc--;
9623   pgetc_debug("pushed back to %d:%p'%s'", parsenleft, parsenextc, parsenextc);   pgetc_debug("pushed back to %d:%p'%s'",
9624  }   g_parsefile->left_in_line,
9625     g_parsefile->next_to_pgetc,
9626  /*   g_parsefile->next_to_pgetc);
  * Push a string back onto the input at this current parsefile level.  
  * We handle aliases this way.  
  */  
 #if !ENABLE_ASH_ALIAS  
 #define pushstring(s, ap) pushstring(s)  
 #endif  
 static void  
 pushstring(char *s, struct alias *ap)  
 {  
  struct strpush *sp;  
  int len;  
   
  len = strlen(s);  
  INT_OFF;  
  if (g_parsefile->strpush) {  
  sp = ckzalloc(sizeof(*sp));  
  sp->prev = g_parsefile->strpush;  
  } else {  
  sp = &(g_parsefile->basestrpush);  
  }  
  g_parsefile->strpush = sp;  
  sp->prevstring = parsenextc;  
  sp->prevnleft = parsenleft;  
 #if ENABLE_ASH_ALIAS  
  sp->ap = ap;  
  if (ap) {  
  ap->flag |= ALIASINUSE;  
  sp->string = s;  
  }  
 #endif  
  parsenextc = s;  
  parsenleft = len;  
  INT_ON;  
9627  }  }
9628    
9629  /*  /*
# Line 9445  pushfile(void) Line 9635  pushfile(void)
9635  {  {
9636   struct parsefile *pf;   struct parsefile *pf;
9637    
  g_parsefile->nleft = parsenleft;  
  g_parsefile->lleft = parselleft;  
  g_parsefile->nextc = parsenextc;  
  g_parsefile->linno = plinno;  
9638   pf = ckzalloc(sizeof(*pf));   pf = ckzalloc(sizeof(*pf));
9639   pf->prev = g_parsefile;   pf->prev = g_parsefile;
9640   pf->fd = -1;   pf->fd = -1;
# Line 9470  popfile(void) Line 9656  popfile(void)
9656   popstring();   popstring();
9657   g_parsefile = pf->prev;   g_parsefile = pf->prev;
9658   free(pf);   free(pf);
  parsenleft = g_parsefile->nleft;  
  parselleft = g_parsefile->lleft;  
  parsenextc = g_parsefile->nextc;  
  plinno = g_parsefile->linno;  
9659   INT_ON;   INT_ON;
9660  }  }
9661    
# Line 9516  setinputfd(int fd, int push) Line 9698  setinputfd(int fd, int push)
9698   g_parsefile->fd = fd;   g_parsefile->fd = fd;
9699   if (g_parsefile->buf == NULL)   if (g_parsefile->buf == NULL)
9700   g_parsefile->buf = ckmalloc(IBUFSIZ);   g_parsefile->buf = ckmalloc(IBUFSIZ);
9701   parselleft = parsenleft = 0;   g_parsefile->left_in_buffer = 0;
9702   plinno = 1;   g_parsefile->left_in_line = 0;
9703     g_parsefile->linno = 1;
9704  }  }
9705    
9706  /*  /*
# Line 9535  setinputfile(const char *fname, int flag Line 9718  setinputfile(const char *fname, int flag
9718   if (fd < 0) {   if (fd < 0) {
9719   if (flags & INPUT_NOFILE_OK)   if (flags & INPUT_NOFILE_OK)
9720   goto out;   goto out;
9721   ash_msg_and_raise_error("can't open %s", fname);   ash_msg_and_raise_error("can't open '%s'", fname);
9722   }   }
9723   if (fd < 10) {   if (fd < 10) {
9724   fd2 = copyfd(fd, 10);   fd2 = copyfd(fd, 10);
# Line 9558  setinputstring(char *string) Line 9741  setinputstring(char *string)
9741  {  {
9742   INT_OFF;   INT_OFF;
9743   pushfile();   pushfile();
9744   parsenextc = string;   g_parsefile->next_to_pgetc = string;
9745   parsenleft = strlen(string);   g_parsefile->left_in_line = strlen(string);
9746   g_parsefile->buf = NULL;   g_parsefile->buf = NULL;
9747   plinno = 1;   g_parsefile->linno = 1;
9748   INT_ON;   INT_ON;
9749  }  }
9750    
# Line 9599  chkmail(void) Line 9782  chkmail(void)
9782   setstackmark(&smark);   setstackmark(&smark);
9783   mpath = mpathset() ? mpathval() : mailval();   mpath = mpathset() ? mpathval() : mailval();
9784   for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {   for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9785   p = padvance(&mpath, nullstr);   p = path_advance(&mpath, nullstr);
9786   if (p == NULL)   if (p == NULL)
9787   break;   break;
9788   if (*p == '\0')   if (*p == '\0')
# Line 9627  chkmail(void) Line 9810  chkmail(void)
9810   popstackmark(&smark);   popstackmark(&smark);
9811  }  }
9812    
9813  static void  static void FAST_FUNC
9814  changemail(const char *val UNUSED_PARAM)  changemail(const char *val UNUSED_PARAM)
9815  {  {
9816   mail_var_path_changed = 1;   mail_var_path_changed = 1;
# Line 9783  options(int cmdline) Line 9966  options(int cmdline)
9966  /*  /*
9967   * The shift builtin command.   * The shift builtin command.
9968   */   */
9969  static int  static int FAST_FUNC
9970  shiftcmd(int argc UNUSED_PARAM, char **argv)  shiftcmd(int argc UNUSED_PARAM, char **argv)
9971  {  {
9972   int n;   int n;
# Line 9845  showvars(const char *sep_prefix, int on, Line 10028  showvars(const char *sep_prefix, int on,
10028  /*  /*
10029   * The set command builtin.   * The set command builtin.
10030   */   */
10031  static int  static int FAST_FUNC
10032  setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10033  {  {
10034   int retval;   int retval;
# Line 9866  setcmd(int argc UNUSED_PARAM, char **arg Line 10049  setcmd(int argc UNUSED_PARAM, char **arg
10049  }  }
10050    
10051  #if ENABLE_ASH_RANDOM_SUPPORT  #if ENABLE_ASH_RANDOM_SUPPORT
10052  static void  static void FAST_FUNC
10053  change_random(const char *value)  change_random(const char *value)
10054  {  {
10055   /* Galois LFSR parameter */   uint32_t t;
  /* Taps at 32 31 29 1: */  
  enum { MASK = 0x8000000b };  
  /* Another example - taps at 32 31 30 10: */  
  /* MASK = 0x00400007 */  
10056    
10057   if (value == NULL) {   if (value == NULL) {
10058   /* "get", generate */   /* "get", generate */
10059   uint32_t t;   t = next_random(&random_gen);
   
  /* LCG has period of 2^32 and alternating lowest bit */  
  random_LCG = 1664525 * random_LCG + 1013904223;  
  /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */  
  t = (random_galois_LFSR << 1);  
  if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */  
  t ^= MASK;  
  random_galois_LFSR = t;  
  /* Both are weak, combining them gives better randomness  
  * and ~2^64 period. & 0x7fff is probably bash compat  
  * for $RANDOM range. Combining with subtraction is  
  * just for fun. + and ^ would work equally well. */  
  t = (t - random_LCG) & 0x7fff;  
10060   /* set without recursion */   /* set without recursion */
10061   setvar(vrandom.text, utoa(t), VNOFUNC);   setvar(vrandom.text, utoa(t), VNOFUNC);
10062   vrandom.flags &= ~VNOFUNC;   vrandom.flags &= ~VNOFUNC;
10063   } else {   } else {
10064   /* set/reset */   /* set/reset */
10065   random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);   t = strtoul(value, NULL, 10);
10066     INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10067   }   }
10068  }  }
10069  #endif  #endif
# Line 9996  getopts(char *optstr, char *optvar, char Line 10163  getopts(char *optstr, char *optvar, char
10163   * be processed in the current argument.  If shellparam.optnext is NULL,   * be processed in the current argument.  If shellparam.optnext is NULL,
10164   * then it's the first time getopts has been called.   * then it's the first time getopts has been called.
10165   */   */
10166  static int  static int FAST_FUNC
10167  getoptscmd(int argc, char **argv)  getoptscmd(int argc, char **argv)
10168  {  {
10169   char **optbase;   char **optbase;
# Line 10041  static char *wordtext;                 / Line 10208  static char *wordtext;                 /
10208  static struct nodelist *backquotelist;  static struct nodelist *backquotelist;
10209  static union node *redirnode;  static union node *redirnode;
10210  static struct heredoc *heredoc;  static struct heredoc *heredoc;
 /*  
  * NEOF is returned by parsecmd when it encounters an end of file.  It  
  * must be distinct from NULL, so we use the address of a variable that  
  * happens to be handy.  
  */  
 #define NEOF ((union node *)&tokpushback)  
   
 static void raise_error_syntax(const char *) NORETURN;  
 static void  
 raise_error_syntax(const char *msg)  
 {  
  ash_msg_and_raise_error("syntax error: %s", msg);  
  /* NOTREACHED */  
 }  
10211    
10212  /*  /*
10213   * Called when an unexpected token is read during the parse.  The argument   * Called when an unexpected token is read during the parse.  The argument
# Line 10068  raise_error_unexpected_syntax(int token) Line 10221  raise_error_unexpected_syntax(int token)
10221   char msg[64];   char msg[64];
10222   int l;   int l;
10223    
10224   l = sprintf(msg, "%s unexpected", tokname(lasttoken));   l = sprintf(msg, "unexpected %s", tokname(lasttoken));
10225   if (token >= 0)   if (token >= 0)
10226   sprintf(msg + l, " (expecting %s)", tokname(token));   sprintf(msg + l, " (expecting %s)", tokname(token));
10227   raise_error_syntax(msg);   raise_error_syntax(msg);
# Line 10260  fixredir(union node *n, const char *text Line 10413  fixredir(union node *n, const char *text
10413   * or backquotes).   * or backquotes).
10414   */   */
10415  static int  static int
10416  noexpand(char *text)  noexpand(const char *text)
10417  {  {
10418   char *p;   unsigned char c;
  char c;  
10419    
10420   p = text;   while ((c = *text++) != '\0') {
  while ((c = *p++) != '\0') {  
10421   if (c == CTLQUOTEMARK)   if (c == CTLQUOTEMARK)
10422   continue;   continue;
10423   if (c == CTLESC)   if (c == CTLESC)
10424   p++;   text++;
10425   else if (SIT(c, BASESYNTAX) == CCTL)   else if (SIT(c, BASESYNTAX) == CCTL)
10426   return 0;   return 0;
10427   }   }
# Line 10294  parsefname(void) Line 10445  parsefname(void)
10445   TRACE(("Here document %d\n", n->type));   TRACE(("Here document %d\n", n->type));
10446   if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)   if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10447   raise_error_syntax("illegal eof marker for << redirection");   raise_error_syntax("illegal eof marker for << redirection");
10448   rmescapes(wordtext);   rmescapes(wordtext, 0);
10449   here->eofmark = wordtext;   here->eofmark = wordtext;
10450   here->next = NULL;   here->next = NULL;
10451   if (heredoclist == NULL)   if (heredoclist == NULL)
# Line 10656  static int decode_dollar_squote(void) Line 10807  static int decode_dollar_squote(void)
10807   * If eofmark is NULL, read a word or a redirection symbol.  If eofmark   * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10808   * is not NULL, read a here document.  In the latter case, eofmark is the   * is not NULL, read a here document.  In the latter case, eofmark is the
10809   * word which marks the end of the document and striptabs is true if   * word which marks the end of the document and striptabs is true if
10810   * leading tabs should be stripped from the document.  The argument firstc   * leading tabs should be stripped from the document.  The argument c
10811   * is the first character of the input token or document.   * is the first character of the input token or document.
10812   *   *
10813   * Because C does not have internal subroutines, I have simulated them   * Because C does not have internal subroutines, I have simulated them
# Line 10670  static int decode_dollar_squote(void) Line 10821  static int decode_dollar_squote(void)
10821  #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}  #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10822  #define PARSEARITH()    {goto parsearith; parsearith_return:;}  #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10823  static int  static int
10824  readtoken1(int firstc, int syntax, char *eofmark, int striptabs)  readtoken1(int c, int syntax, char *eofmark, int striptabs)
10825  {  {
10826   /* NB: syntax parameter fits into smallint */   /* NB: syntax parameter fits into smallint */
10827   int c = firstc;   /* c parameter is an unsigned char or PEOF or PEOA */
10828   char *out;   char *out;
10829   int len;   int len;
10830   char line[EOFMARKLEN + 1];   char line[EOFMARKLEN + 1];
# Line 10690  readtoken1(int firstc, int syntax, char Line 10841  readtoken1(int firstc, int syntax, char
10841   int parenlevel;      /* levels of parens in arithmetic */   int parenlevel;      /* levels of parens in arithmetic */
10842   int dqvarnest;       /* levels of variables expansion within double quotes */   int dqvarnest;       /* levels of variables expansion within double quotes */
10843    
10844   USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)   IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10845    
10846  #if __GNUC__  #if __GNUC__
10847   /* Avoid longjmp clobbering */   /* Avoid longjmp clobbering */
# Line 10705  readtoken1(int firstc, int syntax, char Line 10856  readtoken1(int firstc, int syntax, char
10856   (void) &prevsyntax;   (void) &prevsyntax;
10857   (void) &syntax;   (void) &syntax;
10858  #endif  #endif
10859   startlinno = plinno;   startlinno = g_parsefile->linno;
10860   bqlist = NULL;   bqlist = NULL;
10861   quotef = 0;   quotef = 0;
10862   oldstyle = 0;   oldstyle = 0;
# Line 10733  readtoken1(int firstc, int syntax, char Line 10884  readtoken1(int firstc, int syntax, char
10884   if (syntax == BASESYNTAX)   if (syntax == BASESYNTAX)
10885   goto endword;   /* exit outer loop */   goto endword;   /* exit outer loop */
10886   USTPUTC(c, out);   USTPUTC(c, out);
10887   plinno++;   g_parsefile->linno++;
10888   if (doprompt)   if (doprompt)
10889   setprompt(2);   setprompt(2);
10890   c = pgetc();   c = pgetc();
# Line 10756  readtoken1(int firstc, int syntax, char Line 10907  readtoken1(int firstc, int syntax, char
10907   USTPUTC(c, out);   USTPUTC(c, out);
10908   break;   break;
10909   case CBACK:     /* backslash */   case CBACK:     /* backslash */
10910   c = pgetc2();   c = pgetc_without_PEOA();
10911   if (c == PEOF) {   if (c == PEOF) {
10912   USTPUTC(CTLESC, out);   USTPUTC(CTLESC, out);
10913   USTPUTC('\\', out);   USTPUTC('\\', out);
# Line 10796  readtoken1(int firstc, int syntax, char Line 10947  readtoken1(int firstc, int syntax, char
10947   dblquote = 1;   dblquote = 1;
10948   goto quotemark;   goto quotemark;
10949   case CENDQUOTE:   case CENDQUOTE:
10950   USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)   IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10951   if (eofmark != NULL && arinest == 0   if (eofmark != NULL && arinest == 0
10952   && varnest == 0   && varnest == 0
10953   ) {   ) {
# Line 10824  readtoken1(int firstc, int syntax, char Line 10975  readtoken1(int firstc, int syntax, char
10975   USTPUTC(c, out);   USTPUTC(c, out);
10976   }   }
10977   break;   break;
10978  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
10979   case CLP:       /* '(' in arithmetic */   case CLP:       /* '(' in arithmetic */
10980   parenlevel++;   parenlevel++;
10981   USTPUTC(c, out);   USTPUTC(c, out);
# Line 10870  readtoken1(int firstc, int syntax, char Line 11021  readtoken1(int firstc, int syntax, char
11021  #endif  #endif
11022   goto endword;   /* exit outer loop */   goto endword;   /* exit outer loop */
11023   }   }
11024  #if ENABLE_ASH_ALIAS   IF_ASH_ALIAS(if (c != PEOA))
  if (c != PEOA)  
 #endif  
11025   USTPUTC(c, out);   USTPUTC(c, out);
11026    
11027   }   }
# Line 10880  readtoken1(int firstc, int syntax, char Line 11029  readtoken1(int firstc, int syntax, char
11029   } /* for (;;) */   } /* for (;;) */
11030   }   }
11031   endword:   endword:
11032  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
11033   if (syntax == ARISYNTAX)   if (syntax == ARISYNTAX)
11034   raise_error_syntax("missing '))'");   raise_error_syntax("missing '))'");
11035  #endif  #endif
11036   if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)   if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
11037   raise_error_syntax("unterminated quoted string");   raise_error_syntax("unterminated quoted string");
11038   if (varnest != 0) {   if (varnest != 0) {
11039   startlinno = plinno;   startlinno = g_parsefile->linno;
11040   /* { */   /* { */
11041   raise_error_syntax("missing '}'");   raise_error_syntax("missing '}'");
11042   }   }
# Line 10895  readtoken1(int firstc, int syntax, char Line 11044  readtoken1(int firstc, int syntax, char
11044   len = out - (char *)stackblock();   len = out - (char *)stackblock();
11045   out = stackblock();   out = stackblock();
11046   if (eofmark == NULL) {   if (eofmark == NULL) {
11047   if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))   if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11048   && quotef == 0   && quotef == 0
11049   ) {   ) {
11050   if (isdigit_str9(out)) {   if (isdigit_str9(out)) {
# Line 10924  readtoken1(int firstc, int syntax, char Line 11073  readtoken1(int firstc, int syntax, char
11073  checkend: {  checkend: {
11074   if (eofmark) {   if (eofmark) {
11075  #if ENABLE_ASH_ALIAS  #if ENABLE_ASH_ALIAS
11076   if (c == PEOA) {   if (c == PEOA)
11077   c = pgetc2();   c = pgetc_without_PEOA();
  }  
11078  #endif  #endif
11079   if (striptabs) {   if (striptabs) {
11080   while (c == '\t') {   while (c == '\t') {
11081   c = pgetc2();   c = pgetc_without_PEOA();
11082   }   }
11083   }   }
11084   if (c == *eofmark) {   if (c == *eofmark) {
# Line 10942  checkend: { Line 11090  checkend: {
11090   continue;   continue;
11091   if (*p == '\n' && *q == '\0') {   if (*p == '\n' && *q == '\0') {
11092   c = PEOF;   c = PEOF;
11093   plinno++;   g_parsefile->linno++;
11094   needprompt = doprompt;   needprompt = doprompt;
11095   } else {   } else {
11096   pushstring(line, NULL);   pushstring(line, NULL);
# Line 11038  parseredir: { Line 11186  parseredir: {
11186   (((unsigned)(c) - 33 < 32) \   (((unsigned)(c) - 33 < 32) \
11187   && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))   && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11188  parsesub: {  parsesub: {
11189   int subtype;   unsigned char subtype;
11190   int typeloc;   int typeloc;
11191   int flags;   int flags;
11192   char *p;   char *p;
11193   static const char types[] ALIGN1 = "}-+?=";   static const char types[] ALIGN1 = "}-+?=";
11194    
11195   c = pgetc();   c = pgetc();
11196   if (c <= PEOA_OR_PEOF   if (c > 255 /* PEOA or PEOF */
11197   || (c != '(' && c != '{' && !is_name(c) && !is_special(c))   || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11198   ) {   ) {
11199  #if ENABLE_ASH_BASH_COMPAT  #if ENABLE_ASH_BASH_COMPAT
# Line 11057  parsesub: { Line 11205  parsesub: {
11205   pungetc();   pungetc();
11206   } else if (c == '(') {  /* $(command) or $((arith)) */   } else if (c == '(') {  /* $(command) or $((arith)) */
11207   if (pgetc() == '(') {   if (pgetc() == '(') {
11208  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
11209   PARSEARITH();   PARSEARITH();
11210  #else  #else
11211   raise_error_syntax("you disabled math support for $((arith)) syntax");   raise_error_syntax("you disabled math support for $((arith)) syntax");
# Line 11082  parsesub: { Line 11230  parsesub: {
11230   } else   } else
11231   subtype = 0;   subtype = 0;
11232   }   }
11233   if (c > PEOA_OR_PEOF && is_name(c)) {   if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11234   do {   do {
11235   STPUTC(c, out);   STPUTC(c, out);
11236   c = pgetc();   c = pgetc();
11237   } while (c > PEOA_OR_PEOF && is_in_name(c));   } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11238   } else if (isdigit(c)) {   } else if (isdigit(c)) {
11239   do {   do {
11240   STPUTC(c, out);   STPUTC(c, out);
# Line 11099  parsesub: { Line 11247  parsesub: {
11247   badsub:   badsub:
11248   raise_error_syntax("bad substitution");   raise_error_syntax("bad substitution");
11249   }   }
11250     if (c != '}' && subtype == VSLENGTH)
11251     goto badsub;
11252    
11253   STPUTC('=', out);   STPUTC('=', out);
11254   flags = 0;   flags = 0;
# Line 11148  parsesub: { Line 11298  parsesub: {
11298   }   }
11299   if (dblquote || arinest)   if (dblquote || arinest)
11300   flags |= VSQUOTE;   flags |= VSQUOTE;
11301   *((char *)stackblock() + typeloc) = subtype | flags;   ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11302   if (subtype != VSNORMAL) {   if (subtype != VSNORMAL) {
11303   varnest++;   varnest++;
11304   if (dblquote || arinest) {   if (dblquote || arinest) {
# Line 11218  parsebackq: { Line 11368  parsebackq: {
11368   case '\\':   case '\\':
11369   pc = pgetc();   pc = pgetc();
11370   if (pc == '\n') {   if (pc == '\n') {
11371   plinno++;   g_parsefile->linno++;
11372   if (doprompt)   if (doprompt)
11373   setprompt(2);   setprompt(2);
11374   /*   /*
# Line 11230  parsebackq: { Line 11380  parsebackq: {
11380   continue;   continue;
11381   }   }
11382   if (pc != '\\' && pc != '`' && pc != '$'   if (pc != '\\' && pc != '`' && pc != '$'
11383   && (!dblquote || pc != '"'))   && (!dblquote || pc != '"')
11384     ) {
11385   STPUTC('\\', pout);   STPUTC('\\', pout);
11386   if (pc > PEOA_OR_PEOF) {   }
11387     if (pc <= 255 /* not PEOA or PEOF */) {
11388   break;   break;
11389   }   }
11390   /* fall through */   /* fall through */
11391    
11392   case PEOF:   case PEOF:
11393  #if ENABLE_ASH_ALIAS   IF_ASH_ALIAS(case PEOA:)
11394   case PEOA:   startlinno = g_parsefile->linno;
 #endif  
  startlinno = plinno;  
11395   raise_error_syntax("EOF in backquote substitution");   raise_error_syntax("EOF in backquote substitution");
11396    
11397   case '\n':   case '\n':
11398   plinno++;   g_parsefile->linno++;
11399   needprompt = doprompt;   needprompt = doprompt;
11400   break;   break;
11401    
# Line 11312  parsebackq: { Line 11462  parsebackq: {
11462   goto parsebackq_newreturn;   goto parsebackq_newreturn;
11463  }  }
11464    
11465  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
11466  /*  /*
11467   * Parse an arithmetic expansion (indicate start of one and set state)   * Parse an arithmetic expansion (indicate start of one and set state)
11468   */   */
# Line 11386  xxreadtoken(void) Line 11536  xxreadtoken(void)
11536   if (needprompt) {   if (needprompt) {
11537   setprompt(2);   setprompt(2);
11538   }   }
11539   startlinno = plinno;   startlinno = g_parsefile->linno;
11540   for (;;) {                      /* until token or start of word found */   for (;;) {                      /* until token or start of word found */
11541   c = pgetc_fast();   c = pgetc_fast();
11542   if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))   if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11543   continue;   continue;
11544    
11545   if (c == '#') {   if (c == '#') {
# Line 11401  xxreadtoken(void) Line 11551  xxreadtoken(void)
11551   pungetc();   pungetc();
11552   break; /* return readtoken1(...) */   break; /* return readtoken1(...) */
11553   }   }
11554   startlinno = ++plinno;   startlinno = ++g_parsefile->linno;
11555   if (doprompt)   if (doprompt)
11556   setprompt(2);   setprompt(2);
11557   } else {   } else {
# Line 11410  xxreadtoken(void) Line 11560  xxreadtoken(void)
11560   p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;   p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11561   if (c != PEOF) {   if (c != PEOF) {
11562   if (c == '\n') {   if (c == '\n') {
11563   plinno++;   g_parsefile->linno++;
11564   needprompt = doprompt;   needprompt = doprompt;
11565   }   }
11566    
# Line 11452  xxreadtoken(void) Line 11602  xxreadtoken(void)
11602   if (needprompt) {   if (needprompt) {
11603   setprompt(2);   setprompt(2);
11604   }   }
11605   startlinno = plinno;   startlinno = g_parsefile->linno;
11606   for (;;) {      /* until token or start of word found */   for (;;) {      /* until token or start of word found */
11607   c = pgetc_fast();   c = pgetc_fast();
11608   switch (c) {   switch (c) {
11609   case ' ': case '\t':   case ' ': case '\t':
11610  #if ENABLE_ASH_ALIAS   IF_ASH_ALIAS(case PEOA:)
  case PEOA:  
 #endif  
11611   continue;   continue;
11612   case '#':   case '#':
11613   while ((c = pgetc()) != '\n' && c != PEOF)   while ((c = pgetc()) != '\n' && c != PEOF)
# Line 11468  xxreadtoken(void) Line 11616  xxreadtoken(void)
11616   continue;   continue;
11617   case '\\':   case '\\':
11618   if (pgetc() == '\n') {   if (pgetc() == '\n') {
11619   startlinno = ++plinno;   startlinno = ++g_parsefile->linno;
11620   if (doprompt)   if (doprompt)
11621   setprompt(2);   setprompt(2);
11622   continue;   continue;
# Line 11476  xxreadtoken(void) Line 11624  xxreadtoken(void)
11624   pungetc();   pungetc();
11625   goto breakloop;   goto breakloop;
11626   case '\n':   case '\n':
11627   plinno++;   g_parsefile->linno++;
11628   needprompt = doprompt;   needprompt = doprompt;
11629   RETURN(TNL);   RETURN(TNL);
11630   case PEOF:   case PEOF:
# Line 11586  peektoken(void) Line 11734  peektoken(void)
11734  }  }
11735    
11736  /*  /*
11737   * Read and parse a command.  Returns NEOF on end of file.  (NULL is a   * Read and parse a command.  Returns NODE_EOF on end of file.
11738   * valid parse tree indicating a blank line.)   * (NULL is a valid parse tree indicating a blank line.)
11739   */   */
11740  static union node *  static union node *
11741  parsecmd(int interact)  parsecmd(int interact)
# Line 11601  parsecmd(int interact) Line 11749  parsecmd(int interact)
11749   needprompt = 0;   needprompt = 0;
11750   t = readtoken();   t = readtoken();
11751   if (t == TEOF)   if (t == TEOF)
11752   return NEOF;   return NODE_EOF;
11753   if (t == TNL)   if (t == TNL)
11754   return NULL;   return NULL;
11755   tokpushback = 1;   tokpushback = 1;
# Line 11646  expandstr(const char *ps) Line 11794  expandstr(const char *ps)
11794  {  {
11795   union node n;   union node n;
11796    
11797   /* XXX Fix (char *) cast. */   /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
11798     * and token processing _can_ alter it (delete NULs etc). */
11799   setinputstring((char *)ps);   setinputstring((char *)ps);
11800   readtoken1(pgetc(), PSSYNTAX, nullstr, 0);   readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11801   popfile();   popfile();
# Line 11675  evalstring(char *s, int mask) Line 11824  evalstring(char *s, int mask)
11824   setstackmark(&smark);   setstackmark(&smark);
11825    
11826   skip = 0;   skip = 0;
11827   while ((n = parsecmd(0)) != NEOF) {   while ((n = parsecmd(0)) != NODE_EOF) {
11828   evaltree(n, 0);   evaltree(n, 0);
11829   popstackmark(&smark);   popstackmark(&smark);
11830   skip = evalskip;   skip = evalskip;
# Line 11692  evalstring(char *s, int mask) Line 11841  evalstring(char *s, int mask)
11841  /*  /*
11842   * The eval command.   * The eval command.
11843   */   */
11844  static int  static int FAST_FUNC
11845  evalcmd(int argc UNUSED_PARAM, char **argv)  evalcmd(int argc UNUSED_PARAM, char **argv)
11846  {  {
11847   char *p;   char *p;
# Line 11720  evalcmd(int argc UNUSED_PARAM, char **ar Line 11869  evalcmd(int argc UNUSED_PARAM, char **ar
11869  }  }
11870    
11871  /*  /*
11872   * Read and execute commands.  "Top" is nonzero for the top level command   * Read and execute commands.
11873   * loop; it turns on prompting if the shell is interactive.   * "Top" is nonzero for the top level command loop;
11874     * it turns on prompting if the shell is interactive.
11875   */   */
11876  static int  static int
11877  cmdloop(int top)  cmdloop(int top)
# Line 11748  cmdloop(int top) Line 11898  cmdloop(int top)
11898  #endif  #endif
11899   }   }
11900   n = parsecmd(inter);   n = parsecmd(inter);
11901   /* showtree(n); DEBUG */  #if DEBUG
11902   if (n == NEOF) {   if (DEBUG > 2 && debug && (n != NODE_EOF))
11903     showtree(n);
11904    #endif
11905     if (n == NODE_EOF) {
11906   if (!top || numeof >= 50)   if (!top || numeof >= 50)
11907   break;   break;
11908   if (!stoppedjobs()) {   if (!stoppedjobs()) {
# Line 11790  find_dot_file(char *name) Line 11943  find_dot_file(char *name)
11943   if (strchr(name, '/'))   if (strchr(name, '/'))
11944   return name;   return name;
11945    
11946   while ((fullname = padvance(&path, name)) != NULL) {   /* IIRC standards do not say whether . is to be searched.
11947     * And it is even smaller this way, making it unconditional for now:
11948     */
11949     if (1) { /* ENABLE_ASH_BASH_COMPAT */
11950     fullname = name;
11951     goto try_cur_dir;
11952     }
11953    
11954     while ((fullname = path_advance(&path, name)) != NULL) {
11955     try_cur_dir:
11956   if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {   if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11957   /*   /*
11958   * Don't bother freeing here, since it will   * Don't bother freeing here, since it will
# Line 11798  find_dot_file(char *name) Line 11960  find_dot_file(char *name)
11960   */   */
11961   return fullname;   return fullname;
11962   }   }
11963   stunalloc(fullname);   if (fullname != name)
11964     stunalloc(fullname);
11965   }   }
11966    
11967   /* not found in the PATH */   /* not found in the PATH */
# Line 11806  find_dot_file(char *name) Line 11969  find_dot_file(char *name)
11969   /* NOTREACHED */   /* NOTREACHED */
11970  }  }
11971    
11972  static int  static int FAST_FUNC
11973  dotcmd(int argc, char **argv)  dotcmd(int argc, char **argv)
11974  {  {
11975   struct strlist *sp;   struct strlist *sp;
# Line 11841  dotcmd(int argc, char **argv) Line 12004  dotcmd(int argc, char **argv)
12004   return status;   return status;
12005  }  }
12006    
12007  static int  static int FAST_FUNC
12008  exitcmd(int argc UNUSED_PARAM, char **argv)  exitcmd(int argc UNUSED_PARAM, char **argv)
12009  {  {
12010   if (stoppedjobs())   if (stoppedjobs())
# Line 11972  find_command(char *name, struct cmdentry Line 12135  find_command(char *name, struct cmdentry
12135   e = ENOENT;   e = ENOENT;
12136   idx = -1;   idx = -1;
12137   loop:   loop:
12138   while ((fullname = padvance(&path, name)) != NULL) {   while ((fullname = path_advance(&path, name)) != NULL) {
12139   stunalloc(fullname);   stunalloc(fullname);
12140   /* NB: code below will still use fullname   /* NB: code below will still use fullname
12141   * despite it being "unallocated" */   * despite it being "unallocated" */
# Line 12065  find_command(char *name, struct cmdentry Line 12228  find_command(char *name, struct cmdentry
12228  /*  /*
12229   * The trap builtin.   * The trap builtin.
12230   */   */
12231  static int  static int FAST_FUNC
12232  trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12233  {  {
12234   char *action;   char *action;
# Line 12076  trapcmd(int argc UNUSED_PARAM, char **ar Line 12239  trapcmd(int argc UNUSED_PARAM, char **ar
12239   ap = argptr;   ap = argptr;
12240   if (!*ap) {   if (!*ap) {
12241   for (signo = 0; signo < NSIG; signo++) {   for (signo = 0; signo < NSIG; signo++) {
12242   if (trap[signo] != NULL) {   char *tr = trap_ptr[signo];
12243     if (tr) {
12244     /* note: bash adds "SIG", but only if invoked
12245     * as "bash". If called as "sh", or if set -o posix,
12246     * then it prints short signal names.
12247     * We are printing short names: */
12248   out1fmt("trap -- %s %s\n",   out1fmt("trap -- %s %s\n",
12249   single_quote(trap[signo]),   single_quote(tr),
12250   get_signame(signo));   get_signame(signo));
12251     /* trap_ptr != trap only if we are in special-cased `trap` code.
12252     * In this case, we will exit very soon, no need to free(). */
12253     /* if (trap_ptr != trap && tp[0]) */
12254     /* free(tr); */
12255   }   }
12256   }   }
12257     /*
12258     if (trap_ptr != trap) {
12259     free(trap_ptr);
12260     trap_ptr = trap;
12261     }
12262     */
12263   return 0;   return 0;
12264   }   }
12265    
12266   action = NULL;   action = NULL;
12267   if (ap[1])   if (ap[1])
12268   action = *ap++;   action = *ap++;
# Line 12115  trapcmd(int argc UNUSED_PARAM, char **ar Line 12294  trapcmd(int argc UNUSED_PARAM, char **ar
12294  /*  /*
12295   * Lists available builtins   * Lists available builtins
12296   */   */
12297  static int  static int FAST_FUNC
12298  helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12299  {  {
12300   unsigned col;   unsigned col;
12301   unsigned i;   unsigned i;
12302    
12303   out1fmt("\nBuilt-in commands:\n-------------------\n");   out1fmt(
12304     "Built-in commands:\n"
12305     "------------------\n");
12306   for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {   for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12307   col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),   col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12308   builtintab[i].name + 1);   builtintab[i].name + 1);
# Line 12151  helpcmd(int argc UNUSED_PARAM, char **ar Line 12332  helpcmd(int argc UNUSED_PARAM, char **ar
12332  /*  /*
12333   * The export and readonly commands.   * The export and readonly commands.
12334   */   */
12335  static int  static int FAST_FUNC
12336  exportcmd(int argc UNUSED_PARAM, char **argv)  exportcmd(int argc UNUSED_PARAM, char **argv)
12337  {  {
12338   struct var *vp;   struct var *vp;
# Line 12202  unsetfunc(const char *name) Line 12383  unsetfunc(const char *name)
12383   * variable to allow a function to be unset when there is a readonly variable   * variable to allow a function to be unset when there is a readonly variable
12384   * with the same name.   * with the same name.
12385   */   */
12386  static int  static int FAST_FUNC
12387  unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12388  {  {
12389   char **ap;   char **ap;
# Line 12240  static const unsigned char timescmd_str[ Line 12421  static const unsigned char timescmd_str[
12421   0   0
12422  };  };
12423    
12424  static int  static int FAST_FUNC
12425  timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12426  {  {
12427   long clk_tck, s, t;   long clk_tck, s, t;
# Line 12263  timescmd(int argc UNUSED_PARAM, char **a Line 12444  timescmd(int argc UNUSED_PARAM, char **a
12444   return 0;   return 0;
12445  }  }
12446    
12447  #if ENABLE_ASH_MATH_SUPPORT  #if ENABLE_SH_MATH_SUPPORT
 static arith_t  
 dash_arith(const char *s)  
 {  
  arith_t result;  
  int errcode = 0;  
   
  INT_OFF;  
  result = arith(s, &errcode);  
  if (errcode < 0) {  
  if (errcode == -3)  
  ash_msg_and_raise_error("exponent less than 0");  
  if (errcode == -2)  
  ash_msg_and_raise_error("divide by zero");  
  if (errcode == -5)  
  ash_msg_and_raise_error("expression recursion loop detected");  
  raise_error_syntax(s);  
  }  
  INT_ON;  
   
  return result;  
 }  
   
12448  /*  /*
12449   *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.   * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12450   *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.   * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12451   *   *
12452   *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>   * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12453   */   */
12454  static int  static int FAST_FUNC
12455  letcmd(int argc UNUSED_PARAM, char **argv)  letcmd(int argc UNUSED_PARAM, char **argv)
12456  {  {
12457   arith_t i;   arith_t i;
# Line 12301  letcmd(int argc UNUSED_PARAM, char **arg Line 12460  letcmd(int argc UNUSED_PARAM, char **arg
12460   if (!*argv)   if (!*argv)
12461   ash_msg_and_raise_error("expression expected");   ash_msg_and_raise_error("expression expected");
12462   do {   do {
12463   i = dash_arith(*argv);   i = ash_arith(*argv);
12464   } while (*++argv);   } while (*++argv);
12465    
12466   return !i;   return !i;
12467  }  }
12468  #endif /* ASH_MATH_SUPPORT */  #endif /* SH_MATH_SUPPORT */
12469    
12470    
12471  /* ============ miscbltin.c  /* ============ miscbltin.c
# Line 12334  typedef enum __rlimit_resource rlim_t; Line 12493  typedef enum __rlimit_resource rlim_t;
12493   *      -d DELIM        End on DELIM char, not newline   *      -d DELIM        End on DELIM char, not newline
12494   *      -e              Use line editing (tty only)   *      -e              Use line editing (tty only)
12495   */   */
12496  static int  static int FAST_FUNC
12497  readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12498  {  {
12499   static const char *const arg_REPLY[] = { "REPLY", NULL };   char *opt_n = NULL;
12500     char *opt_p = NULL;
12501   char **ap;   char *opt_t = NULL;
12502   int backslash;   char *opt_u = NULL;
12503   char c;   int read_flags = 0;
12504   int rflag;   const char *r;
  char *prompt;  
  const char *ifs;  
  char *p;  
  int startword;  
  int status;  
12505   int i;   int i;
12506   int fd = 0;  
12507  #if ENABLE_ASH_READ_NCHARS   while ((i = nextopt("p:u:rt:n:s")) != '\0') {
  int nchars = 0; /* if != 0, -n is in effect */  
  int silent = 0;  
  struct termios tty, old_tty;  
 #endif  
 #if ENABLE_ASH_READ_TIMEOUT  
  unsigned end_ms = 0;  
  unsigned timeout = 0;  
 #endif  
   
  rflag = 0;  
  prompt = NULL;  
  while ((i = nextopt("p:u:r"  
  USE_ASH_READ_TIMEOUT("t:")  
  USE_ASH_READ_NCHARS("n:s")  
  )) != '\0') {  
12508   switch (i) {   switch (i) {
12509   case 'p':   case 'p':
12510   prompt = optionarg;   opt_p = optionarg;
12511   break;   break;
 #if ENABLE_ASH_READ_NCHARS  
12512   case 'n':   case 'n':
12513   nchars = bb_strtou(optionarg, NULL, 10);   opt_n = optionarg;
  if (nchars < 0 || errno)  
  ash_msg_and_raise_error("invalid count");  
  /* nchars == 0: off (bash 3.2 does this too) */  
12514   break;   break;
12515   case 's':   case 's':
12516   silent = 1;   read_flags |= BUILTIN_READ_SILENT;
12517   break;   break;
 #endif  
 #if ENABLE_ASH_READ_TIMEOUT  
12518   case 't':   case 't':
12519   timeout = bb_strtou(optionarg, NULL, 10);   opt_t = optionarg;
  if (errno || timeout > UINT_MAX / 2048)  
  ash_msg_and_raise_error("invalid timeout");  
  timeout *= 1000;  
 #if 0 /* even bash have no -t N.NNN support */  
  ts.tv_sec = bb_strtou(optionarg, &p, 10);  
  ts.tv_usec = 0;  
  /* EINVAL means number is ok, but not terminated by NUL */  
  if (*p == '.' && errno == EINVAL) {  
  char *p2;  
  if (*++p) {  
  int scale;  
  ts.tv_usec = bb_strtou(p, &p2, 10);  
  if (errno)  
  ash_msg_and_raise_error("invalid timeout");  
  scale = p2 - p;  
  /* normalize to usec */  
  if (scale > 6)  
  ash_msg_and_raise_error("invalid timeout");  
  while (scale++ < 6)  
  ts.tv_usec *= 10;  
  }  
  } else if (ts.tv_sec < 0 || errno) {  
  ash_msg_and_raise_error("invalid timeout");  
  }  
  if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */  
  ash_msg_and_raise_error("invalid timeout");  
  }  
 #endif /* if 0 */  
12520   break;   break;
 #endif  
12521   case 'r':   case 'r':
12522   rflag = 1;   read_flags |= BUILTIN_READ_RAW;
12523   break;   break;
12524   case 'u':   case 'u':
12525   fd = bb_strtou(optionarg, NULL, 10);   opt_u = optionarg;
  if (fd < 0 || errno)  
  ash_msg_and_raise_error("invalid file descriptor");  
12526   break;   break;
12527   default:   default:
12528   break;   break;
12529   }   }
12530   }   }
  if (prompt && isatty(fd)) {  
  out2str(prompt);  
  }  
  ap = argptr;  
  if (*ap == NULL)  
  ap = (char**)arg_REPLY;  
  ifs = bltinlookup("IFS");  
  if (ifs == NULL)  
  ifs = defifs;  
 #if ENABLE_ASH_READ_NCHARS  
  tcgetattr(fd, &tty);  
  old_tty = tty;  
  if (nchars || silent) {  
  if (nchars) {  
  tty.c_lflag &= ~ICANON;  
  tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;  
  }  
  if (silent) {  
  tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);  
  }  
  /* if tcgetattr failed, tcsetattr will fail too.  
  * Ignoring, it's harmless. */  
  tcsetattr(fd, TCSANOW, &tty);  
  }  
 #endif  
12531    
12532   status = 0;   r = shell_builtin_read(setvar2,
12533   startword = 2;   argptr,
12534   backslash = 0;   bltinlookup("IFS"), /* can be NULL */
12535  #if ENABLE_ASH_READ_TIMEOUT   read_flags,
12536   if (timeout) /* NB: ensuring end_ms is nonzero */   opt_n,
12537   end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;   opt_p,
12538  #endif   opt_t,
12539   STARTSTACKSTR(p);   opt_u
12540   do {   );
  const char *is_ifs;  
   
 #if ENABLE_ASH_READ_TIMEOUT  
  if (end_ms) {  
  struct pollfd pfd[1];  
  pfd[0].fd = fd;  
  pfd[0].events = POLLIN;  
  timeout = end_ms - (unsigned)(monotonic_us() / 1000);  
  if ((int)timeout <= 0 /* already late? */  
  || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */  
  ) { /* timed out! */  
 #if ENABLE_ASH_READ_NCHARS  
  tcsetattr(fd, TCSANOW, &old_tty);  
 #endif  
  return 1;  
  }  
  }  
 #endif  
  if (nonblock_safe_read(fd, &c, 1) != 1) {  
  status = 1;  
  break;  
  }  
  if (c == '\0')  
  continue;  
  if (backslash) {  
  backslash = 0;  
  if (c != '\n')  
  goto put;  
  continue;  
  }  
  if (!rflag && c == '\\') {  
  backslash = 1;  
  continue;  
  }  
  if (c == '\n')  
  break;  
  is_ifs = strchr(ifs, c);  
  if (startword && is_ifs) {  
  if (isspace(c))  
  continue;  
  /* non-space ifs char */  
  startword--;  
  if (startword == 1) /* first one? */  
  continue;  
  }  
  startword = 0;  
  if (ap[1] != NULL && is_ifs) {  
  const char *beg;  
  STACKSTRNUL(p);  
  beg = stackblock();  
  setvar(*ap, beg, 0);  
  ap++;  
  /* can we skip one non-space ifs? (2: yes) */  
  startword = isspace(c) ? 2 : 1;  
  STARTSTACKSTR(p);  
  continue;  
  }  
  put:  
  STPUTC(c, p);  
  }  
 /* end of do {} while: */  
 #if ENABLE_ASH_READ_NCHARS  
  while (--nchars);  
 #else  
  while (1);  
 #endif  
12541    
12542  #if ENABLE_ASH_READ_NCHARS   if ((uintptr_t)r > 1)
12543   tcsetattr(fd, TCSANOW, &old_tty);   ash_msg_and_raise_error(r);
 #endif  
12544    
12545   STACKSTRNUL(p);   return (uintptr_t)r;
  /* Remove trailing space ifs chars */  
  while ((char *)stackblock() <= --p && isspace(*p) && strchr(ifs, *p) != NULL)  
  *p = '\0';  
  setvar(*ap, stackblock(), 0);  
  while (*++ap != NULL)  
  setvar(*ap, nullstr, 0);  
  return status;  
12546  }  }
12547    
12548  static int  static int FAST_FUNC
12549  umaskcmd(int argc UNUSED_PARAM, char **argv)  umaskcmd(int argc UNUSED_PARAM, char **argv)
12550  {  {
12551   static const char permuser[3] ALIGN1 = "ugo";   static const char permuser[3] ALIGN1 = "ugo";
# Line 12553  umaskcmd(int argc UNUSED_PARAM, char **a Line 12556  umaskcmd(int argc UNUSED_PARAM, char **a
12556   S_IROTH, S_IWOTH, S_IXOTH   S_IROTH, S_IWOTH, S_IXOTH
12557   };   };
12558    
12559     /* TODO: use bb_parse_mode() instead */
12560    
12561   char *ap;   char *ap;
12562   mode_t mask;   mode_t mask;
12563   int i;   int i;
# Line 12595  umaskcmd(int argc UNUSED_PARAM, char **a Line 12600  umaskcmd(int argc UNUSED_PARAM, char **a
12600   mask = 0;   mask = 0;
12601   do {   do {
12602   if (*ap >= '8' || *ap < '0')   if (*ap >= '8' || *ap < '0')
12603   ash_msg_and_raise_error(illnum, argv[1]);   ash_msg_and_raise_error(msg_illnum, argv[1]);
12604   mask = (mask << 3) + (*ap - '0');   mask = (mask << 3) + (*ap - '0');
12605   } while (*++ap != '\0');   } while (*++ap != '\0');
12606   umask(mask);   umask(mask);
# Line 12619  umaskcmd(int argc UNUSED_PARAM, char **a Line 12624  umaskcmd(int argc UNUSED_PARAM, char **a
12624   *   *
12625   * Public domain.   * Public domain.
12626   */   */
   
12627  struct limits {  struct limits {
12628   uint8_t cmd;          /* RLIMIT_xxx fit into it */   uint8_t cmd;          /* RLIMIT_xxx fit into it */
12629   uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */   uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
# Line 12717  printlim(enum limtype how, const struct Line 12721  printlim(enum limtype how, const struct
12721   }   }
12722  }  }
12723    
12724  static int  static int FAST_FUNC
12725  ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)  ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12726  {  {
12727   int c;   rlim_t val;
  rlim_t val = 0;  
12728   enum limtype how = SOFT | HARD;   enum limtype how = SOFT | HARD;
12729   const struct limits *l;   const struct limits *l;
12730   int set, all = 0;   int set, all = 0;
# Line 12782  ulimitcmd(int argc UNUSED_PARAM, char ** Line 12785  ulimitcmd(int argc UNUSED_PARAM, char **
12785   continue;   continue;
12786    
12787   set = *argptr ? 1 : 0;   set = *argptr ? 1 : 0;
12788     val = 0;
12789   if (set) {   if (set) {
12790   char *p = *argptr;   char *p = *argptr;
12791    
# Line 12790  ulimitcmd(int argc UNUSED_PARAM, char ** Line 12794  ulimitcmd(int argc UNUSED_PARAM, char **
12794   if (strncmp(p, "unlimited\n", 9) == 0)   if (strncmp(p, "unlimited\n", 9) == 0)
12795   val = RLIM_INFINITY;   val = RLIM_INFINITY;
12796   else {   else {
12797   val = (rlim_t) 0;   if (sizeof(val) == sizeof(int))
12798     val = bb_strtou(p, NULL, 10);
12799   while ((c = *p++) >= '0' && c <= '9') {   else if (sizeof(val) == sizeof(long))
12800   val = (val * 10) + (long)(c - '0');   val = bb_strtoul(p, NULL, 10);
12801   // val is actually 'unsigned long int' and can't get < 0   else
12802   if (val < (rlim_t) 0)   val = bb_strtoull(p, NULL, 10);
12803   break;   if (errno)
  }  
  if (c)  
12804   ash_msg_and_raise_error("bad number");   ash_msg_and_raise_error("bad number");
12805   val <<= l->factor_shift;   val <<= l->factor_shift;
12806   }   }
# Line 12828  ulimitcmd(int argc UNUSED_PARAM, char ** Line 12830  ulimitcmd(int argc UNUSED_PARAM, char **
12830   return 0;   return 0;
12831  }  }
12832    
   
 /* ============ Math support */  
   
 #if ENABLE_ASH_MATH_SUPPORT  
   
 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>  
   
    Permission is hereby granted, free of charge, to any person obtaining  
    a copy of this software and associated documentation files (the  
    "Software"), to deal in the Software without restriction, including  
    without limitation the rights to use, copy, modify, merge, publish,  
    distribute, sublicense, and/or sell copies of the Software, and to  
    permit persons to whom the Software is furnished to do so, subject to  
    the following conditions:  
   
    The above copyright notice and this permission notice shall be  
    included in all copies or substantial portions of the Software.  
   
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
 */  
   
 /* This is my infix parser/evaluator. It is optimized for size, intended  
  * as a replacement for yacc-based parsers. However, it may well be faster  
  * than a comparable parser written in yacc. The supported operators are  
  * listed in #defines below. Parens, order of operations, and error handling  
  * are supported. This code is thread safe. The exact expression format should  
  * be that which POSIX specifies for shells. */  
   
 /* The code uses a simple two-stack algorithm. See  
  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html  
  * for a detailed explanation of the infix-to-postfix algorithm on which  
  * this is based (this code differs in that it applies operators immediately  
  * to the stack instead of adding them to a queue to end up with an  
  * expression). */  
   
 /* To use the routine, call it with an expression string and error return  
  * pointer */  
   
 /*  
  * Aug 24, 2001              Manuel Novoa III  
  *  
  * Reduced the generated code size by about 30% (i386) and fixed several bugs.  
  *  
  * 1) In arith_apply():  
  *    a) Cached values of *numptr and &(numptr[-1]).  
  *    b) Removed redundant test for zero denominator.  
  *  
  * 2) In arith():  
  *    a) Eliminated redundant code for processing operator tokens by moving  
  *       to a table-based implementation.  Also folded handling of parens  
  *       into the table.  
  *    b) Combined all 3 loops which called arith_apply to reduce generated  
  *       code size at the cost of speed.  
  *  
  * 3) The following expressions were treated as valid by the original code:  
  *       1()  ,    0!  ,    1 ( *3 )   .  
  *    These bugs have been fixed by internally enclosing the expression in  
  *    parens and then checking that all binary ops and right parens are  
  *    preceded by a valid expression (NUM_TOKEN).  
  *  
  * Note: It may be desirable to replace Aaron's test for whitespace with  
  * ctype's isspace() if it is used by another busybox applet or if additional  
  * whitespace chars should be considered.  Look below the "#include"s for a  
  * precompiler test.  
  */  
   
 /*  
  * Aug 26, 2001              Manuel Novoa III  
  *  
  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.  
  *  
  * Merge in Aaron's comments previously posted to the busybox list,  
  * modified slightly to take account of my changes to the code.  
  *  
  */  
   
 /*  
  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>  
  *  
  * - allow access to variable,  
  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)  
  * - realize assign syntax (VAR=expr, +=, *= etc)  
  * - realize exponentiation (** operator)  
  * - realize comma separated - expr, expr  
  * - realise ++expr --expr expr++ expr--  
  * - realise expr ? expr : expr (but, second expr calculate always)  
  * - allow hexadecimal and octal numbers  
  * - was restored loses XOR operator  
  * - remove one goto label, added three ;-)  
  * - protect $((num num)) as true zero expr (Manuel`s error)  
  * - always use special isspace(), see comment from bash ;-)  
  */  
   
 #define arith_isspace(arithval) \  
  (arithval == ' ' || arithval == '\n' || arithval == '\t')  
   
 typedef unsigned char operator;  
   
 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the  
  * precedence, and 3 high bits are an ID unique across operators of that  
  * precedence. The ID portion is so that multiple operators can have the  
  * same precedence, ensuring that the leftmost one is evaluated first.  
  * Consider * and /. */  
   
 #define tok_decl(prec,id) (((id)<<5)|(prec))  
 #define PREC(op) ((op) & 0x1F)  
   
 #define TOK_LPAREN tok_decl(0,0)  
   
 #define TOK_COMMA tok_decl(1,0)  
   
 #define TOK_ASSIGN tok_decl(2,0)  
 #define TOK_AND_ASSIGN tok_decl(2,1)  
 #define TOK_OR_ASSIGN tok_decl(2,2)  
 #define TOK_XOR_ASSIGN tok_decl(2,3)  
 #define TOK_PLUS_ASSIGN tok_decl(2,4)  
 #define TOK_MINUS_ASSIGN tok_decl(2,5)  
 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)  
 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)  
   
 #define TOK_MUL_ASSIGN tok_decl(3,0)  
 #define TOK_DIV_ASSIGN tok_decl(3,1)  
 #define TOK_REM_ASSIGN tok_decl(3,2)  
   
 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */  
 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)  
   
 /* conditional is right associativity too */  
 #define TOK_CONDITIONAL tok_decl(4,0)  
 #define TOK_CONDITIONAL_SEP tok_decl(4,1)  
   
 #define TOK_OR tok_decl(5,0)  
   
 #define TOK_AND tok_decl(6,0)  
   
 #define TOK_BOR tok_decl(7,0)  
   
 #define TOK_BXOR tok_decl(8,0)  
   
 #define TOK_BAND tok_decl(9,0)  
   
 #define TOK_EQ tok_decl(10,0)  
 #define TOK_NE tok_decl(10,1)  
   
 #define TOK_LT tok_decl(11,0)  
 #define TOK_GT tok_decl(11,1)  
 #define TOK_GE tok_decl(11,2)  
 #define TOK_LE tok_decl(11,3)  
   
 #define TOK_LSHIFT tok_decl(12,0)  
 #define TOK_RSHIFT tok_decl(12,1)  
   
 #define TOK_ADD tok_decl(13,0)  
 #define TOK_SUB tok_decl(13,1)  
   
 #define TOK_MUL tok_decl(14,0)  
 #define TOK_DIV tok_decl(14,1)  
 #define TOK_REM tok_decl(14,2)  
   
 /* exponent is right associativity */  
 #define TOK_EXPONENT tok_decl(15,1)  
   
 /* For now unary operators. */  
 #define UNARYPREC 16  
 #define TOK_BNOT tok_decl(UNARYPREC,0)  
 #define TOK_NOT tok_decl(UNARYPREC,1)  
   
 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)  
 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)  
   
 #define PREC_PRE (UNARYPREC+2)  
   
 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)  
 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)  
   
 #define PREC_POST (UNARYPREC+3)  
   
 #define TOK_POST_INC tok_decl(PREC_POST, 0)  
 #define TOK_POST_DEC tok_decl(PREC_POST, 1)  
   
 #define SPEC_PREC (UNARYPREC+4)  
   
 #define TOK_NUM tok_decl(SPEC_PREC, 0)  
 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)  
   
 #define NUMPTR (*numstackptr)  
   
 static int  
 tok_have_assign(operator op)  
 {  
  operator prec = PREC(op);  
   
  convert_prec_is_assing(prec);  
  return (prec == PREC(TOK_ASSIGN) ||  
  prec == PREC_PRE || prec == PREC_POST);  
 }  
   
 static int  
 is_right_associativity(operator prec)  
 {  
  return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)  
         || prec == PREC(TOK_CONDITIONAL));  
 }  
   
 typedef struct {  
  arith_t val;  
  arith_t contidional_second_val;  
  char contidional_second_val_initialized;  
  char *var;      /* if NULL then is regular number,  
    else is variable name */  
 } v_n_t;  
   
 typedef struct chk_var_recursive_looped_t {  
  const char *var;  
  struct chk_var_recursive_looped_t *next;  
 } chk_var_recursive_looped_t;  
   
 static chk_var_recursive_looped_t *prev_chk_var_recursive;  
   
 static int  
 arith_lookup_val(v_n_t *t)  
 {  
  if (t->var) {  
  const char * p = lookupvar(t->var);  
   
  if (p) {  
  int errcode;  
   
  /* recursive try as expression */  
  chk_var_recursive_looped_t *cur;  
  chk_var_recursive_looped_t cur_save;  
   
  for (cur = prev_chk_var_recursive; cur; cur = cur->next) {  
  if (strcmp(cur->var, t->var) == 0) {  
  /* expression recursion loop detected */  
  return -5;  
  }  
  }  
  /* save current lookuped var name */  
  cur = prev_chk_var_recursive;  
  cur_save.var = t->var;  
  cur_save.next = cur;  
  prev_chk_var_recursive = &cur_save;  
   
  t->val = arith (p, &errcode);  
  /* restore previous ptr after recursiving */  
  prev_chk_var_recursive = cur;  
  return errcode;  
  }  
  /* allow undefined var as 0 */  
  t->val = 0;  
  }  
  return 0;  
 }  
   
 /* "applying" a token means performing it on the top elements on the integer  
  * stack. For a unary operator it will only change the top element, but a  
  * binary operator will pop two arguments and push a result */  
 static int  
 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)  
 {  
  v_n_t *numptr_m1;  
  arith_t numptr_val, rez;  
  int ret_arith_lookup_val;  
   
  /* There is no operator that can work without arguments */  
  if (NUMPTR == numstack) goto err;  
  numptr_m1 = NUMPTR - 1;  
   
  /* check operand is var with noninteger value */  
  ret_arith_lookup_val = arith_lookup_val(numptr_m1);  
  if (ret_arith_lookup_val)  
  return ret_arith_lookup_val;  
   
  rez = numptr_m1->val;  
  if (op == TOK_UMINUS)  
  rez *= -1;  
  else if (op == TOK_NOT)  
  rez = !rez;  
  else if (op == TOK_BNOT)  
  rez = ~rez;  
  else if (op == TOK_POST_INC || op == TOK_PRE_INC)  
  rez++;  
  else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)  
  rez--;  
  else if (op != TOK_UPLUS) {  
  /* Binary operators */  
   
  /* check and binary operators need two arguments */  
  if (numptr_m1 == numstack) goto err;  
   
  /* ... and they pop one */  
  --NUMPTR;  
  numptr_val = rez;  
  if (op == TOK_CONDITIONAL) {  
  if (!numptr_m1->contidional_second_val_initialized) {  
  /* protect $((expr1 ? expr2)) without ": expr" */  
  goto err;  
  }  
  rez = numptr_m1->contidional_second_val;  
  } else if (numptr_m1->contidional_second_val_initialized) {  
  /* protect $((expr1 : expr2)) without "expr ? " */  
  goto err;  
  }  
  numptr_m1 = NUMPTR - 1;  
  if (op != TOK_ASSIGN) {  
  /* check operand is var with noninteger value for not '=' */  
  ret_arith_lookup_val = arith_lookup_val(numptr_m1);  
  if (ret_arith_lookup_val)  
  return ret_arith_lookup_val;  
  }  
  if (op == TOK_CONDITIONAL) {  
  numptr_m1->contidional_second_val = rez;  
  }  
  rez = numptr_m1->val;  
  if (op == TOK_BOR || op == TOK_OR_ASSIGN)  
  rez |= numptr_val;  
  else if (op == TOK_OR)  
  rez = numptr_val || rez;  
  else if (op == TOK_BAND || op == TOK_AND_ASSIGN)  
  rez &= numptr_val;  
  else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)  
  rez ^= numptr_val;  
  else if (op == TOK_AND)  
  rez = rez && numptr_val;  
  else if (op == TOK_EQ)  
  rez = (rez == numptr_val);  
  else if (op == TOK_NE)  
  rez = (rez != numptr_val);  
  else if (op == TOK_GE)  
  rez = (rez >= numptr_val);  
  else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)  
  rez >>= numptr_val;  
  else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)  
  rez <<= numptr_val;  
  else if (op == TOK_GT)  
  rez = (rez > numptr_val);  
  else if (op == TOK_LT)  
  rez = (rez < numptr_val);  
  else if (op == TOK_LE)  
  rez = (rez <= numptr_val);  
  else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)  
  rez *= numptr_val;  
  else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)  
  rez += numptr_val;  
  else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)  
  rez -= numptr_val;  
  else if (op == TOK_ASSIGN || op == TOK_COMMA)  
  rez = numptr_val;  
  else if (op == TOK_CONDITIONAL_SEP) {  
  if (numptr_m1 == numstack) {  
  /* protect $((expr : expr)) without "expr ? " */  
  goto err;  
  }  
  numptr_m1->contidional_second_val_initialized = op;  
  numptr_m1->contidional_second_val = numptr_val;  
  } else if (op == TOK_CONDITIONAL) {  
  rez = rez ?  
  numptr_val : numptr_m1->contidional_second_val;  
  } else if (op == TOK_EXPONENT) {  
  if (numptr_val < 0)  
  return -3;      /* exponent less than 0 */  
  else {  
  arith_t c = 1;  
   
  if (numptr_val)  
  while (numptr_val--)  
  c *= rez;  
  rez = c;  
  }  
  } else if (numptr_val==0)          /* zero divisor check */  
  return -2;  
  else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)  
  rez /= numptr_val;  
  else if (op == TOK_REM || op == TOK_REM_ASSIGN)  
  rez %= numptr_val;  
  }  
  if (tok_have_assign(op)) {  
  char buf[sizeof(arith_t_type)*3 + 2];  
   
  if (numptr_m1->var == NULL) {  
  /* Hmm, 1=2 ? */  
  goto err;  
  }  
  /* save to shell variable */  
 #if ENABLE_ASH_MATH_SUPPORT_64  
  snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);  
 #else  
  snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);  
 #endif  
  setvar(numptr_m1->var, buf, 0);  
  /* after saving, make previous value for v++ or v-- */  
  if (op == TOK_POST_INC)  
  rez--;  
  else if (op == TOK_POST_DEC)  
  rez++;  
  }  
  numptr_m1->val = rez;  
  /* protect geting var value, is number now */  
  numptr_m1->var = NULL;  
  return 0;  
  err:  
  return -1;  
 }  
   
 /* longest must be first */  
 static const char op_tokens[] ALIGN1 = {  
  '<','<','=',0, TOK_LSHIFT_ASSIGN,  
  '>','>','=',0, TOK_RSHIFT_ASSIGN,  
  '<','<',    0, TOK_LSHIFT,  
  '>','>',    0, TOK_RSHIFT,  
  '|','|',    0, TOK_OR,  
  '&','&',    0, TOK_AND,  
  '!','=',    0, TOK_NE,  
  '<','=',    0, TOK_LE,  
  '>','=',    0, TOK_GE,  
  '=','=',    0, TOK_EQ,  
  '|','=',    0, TOK_OR_ASSIGN,  
  '&','=',    0, TOK_AND_ASSIGN,  
  '*','=',    0, TOK_MUL_ASSIGN,  
  '/','=',    0, TOK_DIV_ASSIGN,  
  '%','=',    0, TOK_REM_ASSIGN,  
  '+','=',    0, TOK_PLUS_ASSIGN,  
  '-','=',    0, TOK_MINUS_ASSIGN,  
  '-','-',    0, TOK_POST_DEC,  
  '^','=',    0, TOK_XOR_ASSIGN,  
  '+','+',    0, TOK_POST_INC,  
  '*','*',    0, TOK_EXPONENT,  
  '!',        0, TOK_NOT,  
  '<',        0, TOK_LT,  
  '>',        0, TOK_GT,  
  '=',        0, TOK_ASSIGN,  
  '|',        0, TOK_BOR,  
  '&',        0, TOK_BAND,  
  '*',        0, TOK_MUL,  
  '/',        0, TOK_DIV,  
  '%',        0, TOK_REM,  
  '+',        0, TOK_ADD,  
  '-',        0, TOK_SUB,  
  '^',        0, TOK_BXOR,  
  /* uniq */  
  '~',        0, TOK_BNOT,  
  ',',        0, TOK_COMMA,  
  '?',        0, TOK_CONDITIONAL,  
  ':',        0, TOK_CONDITIONAL_SEP,  
  ')',        0, TOK_RPAREN,  
  '(',        0, TOK_LPAREN,  
  0  
 };  
 /* ptr to ")" */  
 #define endexpression (&op_tokens[sizeof(op_tokens)-7])  
   
 static arith_t  
 arith(const char *expr, int *perrcode)  
 {  
  char arithval; /* Current character under analysis */  
  operator lasttok, op;  
  operator prec;  
  operator *stack, *stackptr;  
  const char *p = endexpression;  
  int errcode;  
  v_n_t *numstack, *numstackptr;  
  unsigned datasizes = strlen(expr) + 2;  
   
  /* Stack of integers */  
  /* The proof that there can be no more than strlen(startbuf)/2+1 integers  
  * in any given correct or incorrect expression is left as an exercise to  
  * the reader. */  
  numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));  
  /* Stack of operator tokens */  
  stackptr = stack = alloca(datasizes * sizeof(stack[0]));  
   
  *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */  
  *perrcode = errcode = 0;  
   
  while (1) {  
  arithval = *expr;  
  if (arithval == 0) {  
  if (p == endexpression) {  
  /* Null expression. */  
  return 0;  
  }  
   
  /* This is only reached after all tokens have been extracted from the  
  * input stream. If there are still tokens on the operator stack, they  
  * are to be applied in order. At the end, there should be a final  
  * result on the integer stack */  
   
  if (expr != endexpression + 1) {  
  /* If we haven't done so already, */  
  /* append a closing right paren */  
  expr = endexpression;  
  /* and let the loop process it. */  
  continue;  
  }  
  /* At this point, we're done with the expression. */  
  if (numstackptr != numstack+1) {  
  /* ... but if there isn't, it's bad */  
  err:  
  *perrcode = -1;  
  return *perrcode;  
  }  
  if (numstack->var) {  
  /* expression is $((var)) only, lookup now */  
  errcode = arith_lookup_val(numstack);  
  }  
  ret:  
  *perrcode = errcode;  
  return numstack->val;  
  }  
   
  /* Continue processing the expression. */  
  if (arith_isspace(arithval)) {  
  /* Skip whitespace */  
  goto prologue;  
  }  
  p = endofname(expr);  
  if (p != expr) {  
  size_t var_name_size = (p-expr) + 1;  /* trailing zero */  
   
  numstackptr->var = alloca(var_name_size);  
  safe_strncpy(numstackptr->var, expr, var_name_size);  
  expr = p;  
  num:  
  numstackptr->contidional_second_val_initialized = 0;  
  numstackptr++;  
  lasttok = TOK_NUM;  
  continue;  
  }  
  if (isdigit(arithval)) {  
  numstackptr->var = NULL;  
 #if ENABLE_ASH_MATH_SUPPORT_64  
  numstackptr->val = strtoll(expr, (char **) &expr, 0);  
 #else  
  numstackptr->val = strtol(expr, (char **) &expr, 0);  
 #endif  
  goto num;  
  }  
  for (p = op_tokens; ; p++) {  
  const char *o;  
   
  if (*p == 0) {  
  /* strange operator not found */  
  goto err;  
  }  
  for (o = expr; *p && *o == *p; p++)  
  o++;  
  if (!*p) {  
  /* found */  
  expr = o - 1;  
  break;  
  }  
  /* skip tail uncompared token */  
  while (*p)  
  p++;  
  /* skip zero delim */  
  p++;  
  }  
  op = p[1];  
   
  /* post grammar: a++ reduce to num */  
  if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)  
  lasttok = TOK_NUM;  
   
  /* Plus and minus are binary (not unary) _only_ if the last  
  * token was as number, or a right paren (which pretends to be  
  * a number, since it evaluates to one). Think about it.  
  * It makes sense. */  
  if (lasttok != TOK_NUM) {  
  switch (op) {  
  case TOK_ADD:  
  op = TOK_UPLUS;  
  break;  
  case TOK_SUB:  
  op = TOK_UMINUS;  
  break;  
  case TOK_POST_INC:  
  op = TOK_PRE_INC;  
  break;  
  case TOK_POST_DEC:  
  op = TOK_PRE_DEC;  
  break;  
  }  
  }  
  /* We don't want a unary operator to cause recursive descent on the  
  * stack, because there can be many in a row and it could cause an  
  * operator to be evaluated before its argument is pushed onto the  
  * integer stack. */  
  /* But for binary operators, "apply" everything on the operator  
  * stack until we find an operator with a lesser priority than the  
  * one we have just extracted. */  
  /* Left paren is given the lowest priority so it will never be  
  * "applied" in this way.  
  * if associativity is right and priority eq, applied also skip  
  */  
  prec = PREC(op);  
  if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {  
  /* not left paren or unary */  
  if (lasttok != TOK_NUM) {  
  /* binary op must be preceded by a num */  
  goto err;  
  }  
  while (stackptr != stack) {  
  if (op == TOK_RPAREN) {  
  /* The algorithm employed here is simple: while we don't  
  * hit an open paren nor the bottom of the stack, pop  
  * tokens and apply them */  
  if (stackptr[-1] == TOK_LPAREN) {  
  --stackptr;  
  /* Any operator directly after a */  
  lasttok = TOK_NUM;  
  /* close paren should consider itself binary */  
  goto prologue;  
  }  
  } else {  
  operator prev_prec = PREC(stackptr[-1]);  
   
  convert_prec_is_assing(prec);  
  convert_prec_is_assing(prev_prec);  
  if (prev_prec < prec)  
  break;  
  /* check right assoc */  
  if (prev_prec == prec && is_right_associativity(prec))  
  break;  
  }  
  errcode = arith_apply(*--stackptr, numstack, &numstackptr);  
  if (errcode) goto ret;  
  }  
  if (op == TOK_RPAREN) {  
  goto err;  
  }  
  }  
   
  /* Push this operator to the stack and remember it. */  
  *stackptr++ = lasttok = op;  
  prologue:  
  ++expr;  
  } /* while */  
 }  
 #endif /* ASH_MATH_SUPPORT */  
   
   
12833  /* ============ main() and helpers */  /* ============ main() and helpers */
12834    
12835  /*  /*
# Line 13492  exitshell(void) Line 12846  exitshell(void)
12846   status = exitstatus;   status = exitstatus;
12847   TRACE(("pid %d, exitshell(%d)\n", getpid(), status));   TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12848   if (setjmp(loc.loc)) {   if (setjmp(loc.loc)) {
12849   if (exception == EXEXIT)   if (exception_type == EXEXIT)
12850  /* dash bug: it just does _exit(exitstatus) here  /* dash bug: it just does _exit(exitstatus) here
12851   * but we have to do setjobctl(0) first!   * but we have to do setjobctl(0) first!
12852   * (bug is still not fixed in dash-0.5.3 - if you run dash   * (bug is still not fixed in dash-0.5.3 - if you run dash
# Line 13505  exitshell(void) Line 12859  exitshell(void)
12859   if (p) {   if (p) {
12860   trap[0] = NULL;   trap[0] = NULL;
12861   evalstring(p, 0);   evalstring(p, 0);
12862     free(p);
12863   }   }
12864   flush_stdout_stderr();   flush_stdout_stderr();
12865   out:   out:
# Line 13517  static void Line 12872  static void
12872  init(void)  init(void)
12873  {  {
12874   /* from input.c: */   /* from input.c: */
12875   basepf.nextc = basepf.buf = basebuf;   basepf.next_to_pgetc = basepf.buf = basebuf;
12876    
12877   /* from trap.c: */   /* from trap.c: */
12878   signal(SIGCHLD, SIG_DFL);   signal(SIGCHLD, SIG_DFL);
12879     /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12880     * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12881     */
12882            signal(SIGHUP, SIG_DFL);
12883    
12884   /* from var.c: */   /* from var.c: */
12885   {   {
12886   char **envp;   char **envp;
  char ppid[sizeof(int)*3 + 1];  
12887   const char *p;   const char *p;
12888   struct stat st1, st2;   struct stat st1, st2;
12889    
# Line 13536  init(void) Line 12894  init(void)
12894   }   }
12895   }   }
12896    
12897   snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());   setvar("PPID", utoa(getppid()), 0);
  setvar("PPID", ppid, 0);  
12898    
12899   p = lookupvar("PWD");   p = lookupvar("PWD");
12900   if (p)   if (p)
# Line 13638  reset(void) Line 12995  reset(void)
12995   evalskip = 0;   evalskip = 0;
12996   loopnest = 0;   loopnest = 0;
12997   /* from input.c: */   /* from input.c: */
12998   parselleft = parsenleft = 0;      /* clear input buffer */   g_parsefile->left_in_buffer = 0;
12999     g_parsefile->left_in_line = 0;      /* clear input buffer */
13000   popallfiles();   popallfiles();
13001   /* from parser.c: */   /* from parser.c: */
13002   tokpushback = 0;   tokpushback = 0;
# Line 13662  extern int etext(); Line 13020  extern int etext();
13020  int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13021  int ash_main(int argc UNUSED_PARAM, char **argv)  int ash_main(int argc UNUSED_PARAM, char **argv)
13022  {  {
13023   char *shinit;   const char *shinit;
13024   volatile int state;   volatile smallint state;
13025   struct jmploc jmploc;   struct jmploc jmploc;
13026   struct stackmark smark;   struct stackmark smark;
13027    
# Line 13685  int ash_main(int argc UNUSED_PARAM, char Line 13043  int ash_main(int argc UNUSED_PARAM, char
13043  #endif  #endif
13044   state = 0;   state = 0;
13045   if (setjmp(jmploc.loc)) {   if (setjmp(jmploc.loc)) {
13046   int e;   smallint e;
13047   int s;   smallint s;
13048    
13049   reset();   reset();
13050    
13051   e = exception;   e = exception_type;
13052   if (e == EXERROR)   if (e == EXERROR)
13053   exitstatus = 2;   exitstatus = 2;
13054   s = state;   s = state;
13055   if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)   if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13056   exitshell();   exitshell();
13057     if (e == EXINT)
  if (e == EXINT) {  
13058   outcslow('\n', stderr);   outcslow('\n', stderr);
13059   }  
13060   popstackmark(&smark);   popstackmark(&smark);
13061   FORCE_INT_ON; /* enable interrupts */   FORCE_INT_ON; /* enable interrupts */
13062   if (s == 1)   if (s == 1)
# Line 13718  int ash_main(int argc UNUSED_PARAM, char Line 13075  int ash_main(int argc UNUSED_PARAM, char
13075  #endif  #endif
13076   rootpid = getpid();   rootpid = getpid();
13077    
 #if ENABLE_ASH_RANDOM_SUPPORT  
  /* Can use monotonic_ns() for better randomness but for now it is  
  * not used anywhere else in busybox... so avoid bloat */  
  random_galois_LFSR = random_LCG = rootpid + monotonic_us();  
 #endif  
13078   init();   init();
13079   setstackmark(&smark);   setstackmark(&smark);
13080   procargs(argv);   procargs(argv);
# Line 13741  int ash_main(int argc UNUSED_PARAM, char Line 13093  int ash_main(int argc UNUSED_PARAM, char
13093   }   }
13094   }   }
13095  #endif  #endif
13096   if (argv[0] && argv[0][0] == '-')   if (/* argv[0] && */ argv[0][0] == '-')
13097   isloginsh = 1;   isloginsh = 1;
13098   if (isloginsh) {   if (isloginsh) {
13099   state = 1;   state = 1;
# Line 13768  int ash_main(int argc UNUSED_PARAM, char Line 13120  int ash_main(int argc UNUSED_PARAM, char
13120   if (minusc) {   if (minusc) {
13121   /* evalstring pushes parsefile stack.   /* evalstring pushes parsefile stack.
13122   * Ensure we don't falsely claim that 0 (stdin)   * Ensure we don't falsely claim that 0 (stdin)
13123   * is one of stacked source fds */   * is one of stacked source fds.
13124     * Testcase: ash -c 'exec 1>&0' must not complain. */
13125   if (!sflag)   if (!sflag)
13126   g_parsefile->fd = -1;   g_parsefile->fd = -1;
13127   evalstring(minusc, 0);   evalstring(minusc, 0);
13128   }   }
13129    
13130   if (sflag || minusc == NULL) {   if (sflag || minusc == NULL) {
13131  #if ENABLE_FEATURE_EDITING_SAVEHISTORY  #if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13132   if (iflag) {   if (iflag) {
13133   const char *hp = lookupvar("HISTFILE");   const char *hp = lookupvar("HISTFILE");
13134     if (hp)
  if (hp != NULL)  
13135   line_input_state->hist_file = hp;   line_input_state->hist_file = hp;
13136   }   }
13137  #endif  #endif

Legend:
Removed from v.983  
changed lines
  Added in v.984