Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/shell/ash.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/shell/ash.c

    r1772 r2725  
    22/*
    33 * 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.
    49 *
    510 * Copyright (c) 1989, 1991, 1993, 1994
     
    914 * was re-ported from NetBSD and debianized.
    1015 *
    11  *
    12  * This code is derived from software contributed to Berkeley by
    13  * Kenneth Almquist.
    14  *
    15  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    16  *
    17  * Original BSD copyright notice is retained at the end of this file.
    18  */
    19 
    20 /*
    21  * rewrite arith.y to micro stack based cryptic algorithm by
    22  * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
    23  *
    24  * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
    25  * dynamic variables.
    26  *
    27  * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
    28  * used in busybox and size optimizations,
    29  * rewrote arith (see notes to this), added locale support,
    30  * rewrote dynamic variables.
    31  *
    32  */
    33 
    34 /*
    35  * The follow should be set to reflect the type of system you have:
     16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     17 */
     18
     19/*
     20 * The following should be set to reflect the type of system you have:
    3621 *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
    3722 *      define SYSV if you are running under System V.
     
    4328 */
    4429#define DEBUG 0
    45 #define IFS_BROKEN
     30/* Tweak debug output verbosity here */
     31#define DEBUG_TIME 0
     32#define DEBUG_PID 1
     33#define DEBUG_SIG 1
     34
    4635#define PROFILE 0
    47 #if ENABLE_ASH_JOB_CONTROL
    48 #define JOBS 1
    49 #else
    50 #define JOBS 0
    51 #endif
    52 
    53 #if DEBUG
    54 #define _GNU_SOURCE
    55 #endif
    56 #include "busybox.h" /* for struct bb_applet */
     36
     37#define JOBS ENABLE_ASH_JOB_CONTROL
     38
     39#include "busybox.h" /* for applet_names */
    5740#include <paths.h>
    5841#include <setjmp.h>
    5942#include <fnmatch.h>
    60 #if JOBS || ENABLE_ASH_READ_NCHARS
    61 #include <termios.h>
    62 #endif
    63 extern char **environ;
    64 
    65 #if defined(__uClinux__)
    66 #error "Do not even bother, ash will not run on uClinux"
    67 #endif
    68 
    69 
    70 /* ============ Misc helpers */
    71 
    72 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
    73 
    74 /* C99 say: "char" declaration may be signed or unsigned default */
    75 #define signed_char2int(sc) ((int)((signed char)sc))
     43#include <sys/times.h>
     44
     45#include "shell_common.h"
     46#if ENABLE_SH_MATH_SUPPORT
     47# include "math.h"
     48#endif
     49#if ENABLE_ASH_RANDOM_SUPPORT
     50# include "random.h"
     51#else
     52# define CLEAR_RANDOM_T(rnd) ((void)0)
     53#endif
     54
     55#include "NUM_APPLETS.h"
     56#if NUM_APPLETS == 1
     57/* STANDALONE does not make sense, and won't compile */
     58# undef CONFIG_FEATURE_SH_STANDALONE
     59# undef ENABLE_FEATURE_SH_STANDALONE
     60# undef IF_FEATURE_SH_STANDALONE
     61# undef IF_NOT_FEATURE_SH_STANDALONE
     62# define ENABLE_FEATURE_SH_STANDALONE 0
     63# define IF_FEATURE_SH_STANDALONE(...)
     64# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
     65#endif
     66
     67#ifndef PIPE_BUF
     68# define PIPE_BUF 4096           /* amount of buffering in a pipe */
     69#endif
     70
     71#if !BB_MMU
     72# error "Do not even bother, ash will not run on NOMMU machine"
     73#endif
     74
     75//applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP))
     76//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh))
     77//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash))
     78
     79//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
     80//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
     81
     82//config:config ASH
     83//config:   bool "ash"
     84//config:   default y
     85//config:   depends on !NOMMU
     86//config:   help
     87//config:     Tha 'ash' shell adds about 60k in the default configuration and is
     88//config:     the most complete and most pedantically correct shell included with
     89//config:     busybox. This shell is actually a derivative of the Debian 'dash'
     90//config:     shell (by Herbert Xu), which was created by porting the 'ash' shell
     91//config:     (written by Kenneth Almquist) from NetBSD.
     92//config:
     93//config:config ASH_BASH_COMPAT
     94//config:   bool "bash-compatible extensions"
     95//config:   default y
     96//config:   depends on ASH
     97//config:   help
     98//config:     Enable bash-compatible extensions.
     99//config:
     100//config:config ASH_JOB_CONTROL
     101//config:   bool "Job control"
     102//config:   default y
     103//config:   depends on ASH
     104//config:   help
     105//config:     Enable job control in the ash shell.
     106//config:
     107//config:config ASH_ALIAS
     108//config:   bool "alias support"
     109//config:   default y
     110//config:   depends on ASH
     111//config:   help
     112//config:     Enable alias support in the ash shell.
     113//config:
     114//config:config ASH_GETOPTS
     115//config:   bool "Builtin getopt to parse positional parameters"
     116//config:   default y
     117//config:   depends on ASH
     118//config:   help
     119//config:     Enable getopts builtin in the ash shell.
     120//config:
     121//config:config ASH_BUILTIN_ECHO
     122//config:   bool "Builtin version of 'echo'"
     123//config:   default y
     124//config:   depends on ASH
     125//config:   help
     126//config:     Enable support for echo, builtin to ash.
     127//config:
     128//config:config ASH_BUILTIN_PRINTF
     129//config:   bool "Builtin version of 'printf'"
     130//config:   default y
     131//config:   depends on ASH
     132//config:   help
     133//config:     Enable support for printf, builtin to ash.
     134//config:
     135//config:config ASH_BUILTIN_TEST
     136//config:   bool "Builtin version of 'test'"
     137//config:   default y
     138//config:   depends on ASH
     139//config:   help
     140//config:     Enable support for test, builtin to ash.
     141//config:
     142//config:config ASH_CMDCMD
     143//config:   bool "'command' command to override shell builtins"
     144//config:   default y
     145//config:   depends on ASH
     146//config:   help
     147//config:     Enable support for the ash 'command' builtin, which allows
     148//config:     you to run the specified command with the specified arguments,
     149//config:     even when there is an ash builtin command with the same name.
     150//config:
     151//config:config ASH_MAIL
     152//config:   bool "Check for new mail on interactive shells"
     153//config:   default n
     154//config:   depends on ASH
     155//config:   help
     156//config:     Enable "check for new mail" in the ash shell.
     157//config:
     158//config:config ASH_OPTIMIZE_FOR_SIZE
     159//config:   bool "Optimize for size instead of speed"
     160//config:   default y
     161//config:   depends on ASH
     162//config:   help
     163//config:     Compile ash for reduced size at the price of speed.
     164//config:
     165//config:config ASH_RANDOM_SUPPORT
     166//config:   bool "Pseudorandom generator and $RANDOM variable"
     167//config:   default y
     168//config:   depends on ASH
     169//config:   help
     170//config:     Enable pseudorandom generator and dynamic variable "$RANDOM".
     171//config:     Each read of "$RANDOM" will generate a new pseudorandom value.
     172//config:     You can reset the generator by using a specified start value.
     173//config:     After "unset RANDOM" the generator will switch off and this
     174//config:     variable will no longer have special treatment.
     175//config:
     176//config:config ASH_EXPAND_PRMT
     177//config:   bool "Expand prompt string"
     178//config:   default y
     179//config:   depends on ASH
     180//config:   help
     181//config:     "PS#" may contain volatile content, such as backquote commands.
     182//config:     This option recreates the prompt string from the environment
     183//config:     variable each time it is displayed.
     184//config:
     185
     186//usage:#define ash_trivial_usage NOUSAGE_STR
     187//usage:#define ash_full_usage ""
     188//usage:#define sh_trivial_usage NOUSAGE_STR
     189//usage:#define sh_full_usage ""
     190//usage:#define bash_trivial_usage NOUSAGE_STR
     191//usage:#define bash_full_usage ""
     192
     193
     194/* ============ Hash table sizes. Configurable. */
     195
     196#define VTABSIZE 39
     197#define ATABSIZE 39
     198#define CMDTABLESIZE 31         /* should be prime */
    76199
    77200
     
    93216    "u"   "nounset",
    94217    "\0"  "vi"
     218#if ENABLE_ASH_BASH_COMPAT
     219    ,"\0"  "pipefail"
     220#endif
    95221#if DEBUG
    96222    ,"\0"  "nolog"
     
    99225};
    100226
    101 #define optletters(n) optletters_optnames[(n)][0]
    102 #define optnames(n) (&optletters_optnames[(n)][1])
     227#define optletters(n)  optletters_optnames[n][0]
     228#define optnames(n)   (optletters_optnames[n] + 1)
    103229
    104230enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
    105231
    106 static char optlist[NOPTS] ALIGN1;
    107 
     232
     233/* ============ Misc data */
     234
     235#define msg_illnum "Illegal number: %s"
     236
     237/*
     238 * We enclose jmp_buf in a structure so that we can declare pointers to
     239 * jump locations.  The global variable handler contains the location to
     240 * jump to when an exception occurs, and the global variable exception_type
     241 * contains a code identifying the exception.  To implement nested
     242 * exception handlers, the user should save the value of handler on entry
     243 * to an inner scope, set handler to point to a jmploc structure for the
     244 * inner scope, and restore handler on exit from the scope.
     245 */
     246struct jmploc {
     247    jmp_buf loc;
     248};
     249
     250struct globals_misc {
     251    /* pid of main shell */
     252    int rootpid;
     253    /* shell level: 0 for the main shell, 1 for its children, and so on */
     254    int shlvl;
     255#define rootshell (!shlvl)
     256    char *minusc;  /* argument to -c option */
     257
     258    char *curdir; // = nullstr;     /* current working directory */
     259    char *physdir; // = nullstr;    /* physical working directory */
     260
     261    char *arg0; /* value of $0 */
     262
     263    struct jmploc *exception_handler;
     264
     265    volatile int suppress_int; /* counter */
     266    volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
     267    /* last pending signal */
     268    volatile /*sig_atomic_t*/ smallint pending_sig;
     269    smallint exception_type; /* kind of exception (0..5) */
     270    /* exceptions */
     271#define EXINT 0         /* SIGINT received */
     272#define EXERROR 1       /* a generic error */
     273#define EXSHELLPROC 2   /* execute a shell procedure */
     274#define EXEXEC 3        /* command execution failed */
     275#define EXEXIT 4        /* exit the shell */
     276#define EXSIG 5         /* trapped signal in wait(1) */
     277
     278    smallint isloginsh;
     279    char nullstr[1];        /* zero length string */
     280
     281    char optlist[NOPTS];
    108282#define eflag optlist[0]
    109283#define fflag optlist[1]
     
    120294#define uflag optlist[12]
    121295#define viflag optlist[13]
     296#if ENABLE_ASH_BASH_COMPAT
     297# define pipefail optlist[14]
     298#else
     299# define pipefail 0
     300#endif
    122301#if DEBUG
    123 #define nolog optlist[14]
    124 #define debug optlist[15]
    125 #endif
    126 
    127 
    128 /* ============ Misc data */
    129 
    130 static char nullstr[1] ALIGN1;  /* zero length string */
    131 static const char homestr[] ALIGN1 = "HOME";
    132 static const char snlfmt[] ALIGN1 = "%s\n";
    133 static const char illnum[] ALIGN1 = "Illegal number: %s";
    134 
    135 static char *minusc;  /* argument to -c option */
    136 
    137 /* pid of main shell */
    138 static int rootpid;
    139 /* shell level: 0 for the main shell, 1 for its children, and so on */
    140 static int shlvl;
    141 #define rootshell (!shlvl)
    142 /* trap handler commands */
    143 static char *trap[NSIG];
    144 static smallint isloginsh;
    145 /* current value of signal */
    146 static char sigmode[NSIG - 1];
    147 /* indicates specified signal received */
    148 static char gotsig[NSIG - 1];
    149 static char *arg0; /* value of $0 */
     302# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
     303# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
     304#endif
     305
     306    /* trap handler commands */
     307    /*
     308     * Sigmode records the current value of the signal handlers for the various
     309     * modes.  A value of zero means that the current handler is not known.
     310     * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
     311     */
     312    char sigmode[NSIG - 1];
     313#define S_DFL      1            /* default signal handling (SIG_DFL) */
     314#define S_CATCH    2            /* signal is caught */
     315#define S_IGN      3            /* signal is ignored (SIG_IGN) */
     316#define S_HARD_IGN 4            /* signal is ignored permenantly */
     317
     318    /* indicates specified signal received */
     319    uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
     320    uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
     321    char *trap[NSIG];
     322    char **trap_ptr;        /* used only by "trap hack" */
     323
     324    /* Rarely referenced stuff */
     325#if ENABLE_ASH_RANDOM_SUPPORT
     326    random_t random_gen;
     327#endif
     328    pid_t backgndpid;        /* pid of last background process */
     329    smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */
     330};
     331extern struct globals_misc *const ash_ptr_to_globals_misc;
     332#define G_misc (*ash_ptr_to_globals_misc)
     333#define rootpid     (G_misc.rootpid    )
     334#define shlvl       (G_misc.shlvl      )
     335#define minusc      (G_misc.minusc     )
     336#define curdir      (G_misc.curdir     )
     337#define physdir     (G_misc.physdir    )
     338#define arg0        (G_misc.arg0       )
     339#define exception_handler (G_misc.exception_handler)
     340#define exception_type    (G_misc.exception_type   )
     341#define suppress_int      (G_misc.suppress_int     )
     342#define pending_int       (G_misc.pending_int      )
     343#define pending_sig       (G_misc.pending_sig      )
     344#define isloginsh   (G_misc.isloginsh  )
     345#define nullstr     (G_misc.nullstr    )
     346#define optlist     (G_misc.optlist    )
     347#define sigmode     (G_misc.sigmode    )
     348#define gotsig      (G_misc.gotsig     )
     349#define may_have_traps    (G_misc.may_have_traps   )
     350#define trap        (G_misc.trap       )
     351#define trap_ptr    (G_misc.trap_ptr   )
     352#define random_gen  (G_misc.random_gen )
     353#define backgndpid  (G_misc.backgndpid )
     354#define job_warning (G_misc.job_warning)
     355#define INIT_G_misc() do { \
     356    (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
     357    barrier(); \
     358    curdir = nullstr; \
     359    physdir = nullstr; \
     360    trap_ptr = trap; \
     361} while (0)
     362
     363
     364/* ============ DEBUG */
     365#if DEBUG
     366static void trace_printf(const char *fmt, ...);
     367static void trace_vprintf(const char *fmt, va_list va);
     368# define TRACE(param)    trace_printf param
     369# define TRACEV(param)   trace_vprintf param
     370# define close(fd) do { \
     371    int dfd = (fd); \
     372    if (close(dfd) < 0) \
     373        bb_error_msg("bug on %d: closing %d(0x%x)", \
     374            __LINE__, dfd, dfd); \
     375} while (0)
     376#else
     377# define TRACE(param)
     378# define TRACEV(param)
     379#endif
     380
     381
     382/* ============ Utility functions */
     383#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
     384
     385static int isdigit_str9(const char *str)
     386{
     387    int maxlen = 9 + 1; /* max 9 digits: 999999999 */
     388    while (--maxlen && isdigit(*str))
     389        str++;
     390    return (*str == '\0');
     391}
     392
     393static const char *var_end(const char *var)
     394{
     395    while (*var)
     396        if (*var++ == '=')
     397            break;
     398    return var;
     399}
    150400
    151401
    152402/* ============ Interrupts / exceptions */
    153 
    154 /*
    155  * We enclose jmp_buf in a structure so that we can declare pointers to
    156  * jump locations.  The global variable handler contains the location to
    157  * jump to when an exception occurs, and the global variable exception
    158  * contains a code identifying the exception.  To implement nested
    159  * exception handlers, the user should save the value of handler on entry
    160  * to an inner scope, set handler to point to a jmploc structure for the
    161  * inner scope, and restore handler on exit from the scope.
    162  */
    163 struct jmploc {
    164     jmp_buf loc;
    165 };
    166 static struct jmploc *exception_handler;
    167 static int exception;
    168 /* exceptions */
    169 #define EXINT 0         /* SIGINT received */
    170 #define EXERROR 1       /* a generic error */
    171 #define EXSHELLPROC 2   /* execute a shell procedure */
    172 #define EXEXEC 3        /* command execution failed */
    173 #define EXEXIT 4        /* exit the shell */
    174 #define EXSIG 5         /* trapped signal in wait(1) */
    175 static volatile int suppressint;
    176 static volatile sig_atomic_t intpending;
    177 /* do we generate EXSIG events */
    178 static int exsig;
    179 /* last pending signal */
    180 static volatile sig_atomic_t pendingsig;
    181 
    182 /*
    183  * Sigmode records the current value of the signal handlers for the various
    184  * modes.  A value of zero means that the current handler is not known.
    185  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
    186  */
    187 
    188 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
    189 #define S_CATCH 2               /* signal is caught */
    190 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
    191 #define S_HARD_IGN 4            /* signal is ignored permenantly */
    192 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
    193 
    194403/*
    195404 * These macros allow the user to suspend the handling of interrupt signals
    196  * over a period of time.  This is similar to SIGHOLD to or sigblock, but
     405 * over a period of time.  This is similar to SIGHOLD or to sigblock, but
    197406 * much more efficient and portable.  (But hacking the kernel is so much
    198407 * more fun than worrying about efficiency and portability. :-))
    199408 */
    200 #define INT_OFF \
    201     do { \
    202         suppressint++; \
    203         xbarrier(); \
    204     } while (0)
     409#define INT_OFF do { \
     410    suppress_int++; \
     411    xbarrier(); \
     412} while (0)
    205413
    206414/*
    207415 * Called to raise an exception.  Since C doesn't include exceptions, we
    208416 * just do a longjmp to the exception handler.  The type of exception is
    209  * stored in the global variable "exception".
    210  */
    211 static void raise_exception(int) ATTRIBUTE_NORETURN;
     417 * stored in the global variable "exception_type".
     418 */
     419static void raise_exception(int) NORETURN;
    212420static void
    213421raise_exception(int e)
     
    218426#endif
    219427    INT_OFF;
    220     exception = e;
     428    exception_type = e;
    221429    longjmp(exception_handler->loc, 1);
    222430}
     431#if DEBUG
     432#define raise_exception(e) do { \
     433    TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
     434    raise_exception(e); \
     435} while (0)
     436#endif
    223437
    224438/*
     
    229443 * defensive programming.)
    230444 */
    231 static void raise_interrupt(void) ATTRIBUTE_NORETURN;
     445static void raise_interrupt(void) NORETURN;
    232446static void
    233447raise_interrupt(void)
    234448{
    235     int i;
    236     sigset_t mask;
    237 
    238     intpending = 0;
    239     /* Signal is not automatically re-enabled after it is raised,
    240      * do it ourself */
    241     sigemptyset(&mask);
    242     sigprocmask(SIG_SETMASK, &mask, 0);
    243     /* pendingsig = 0; - now done in onsig() */
    244 
    245     i = EXSIG;
     449    int ex_type;
     450
     451    pending_int = 0;
     452    /* Signal is not automatically unmasked after it is raised,
     453     * do it ourself - unmask all signals */
     454    sigprocmask_allsigs(SIG_UNBLOCK);
     455    /* pending_sig = 0; - now done in signal_handler() */
     456
     457    ex_type = EXSIG;
    246458    if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
    247459        if (!(rootshell && iflag)) {
     460            /* Kill ourself with SIGINT */
    248461            signal(SIGINT, SIG_DFL);
    249462            raise(SIGINT);
    250463        }
    251         i = EXINT;
    252     }
    253     raise_exception(i);
     464        ex_type = EXINT;
     465    }
     466    raise_exception(ex_type);
    254467    /* NOTREACHED */
    255468}
    256 
    257 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
    258 static void
     469#if DEBUG
     470#define raise_interrupt() do { \
     471    TRACE(("raising interrupt on line %d\n", __LINE__)); \
     472    raise_interrupt(); \
     473} while (0)
     474#endif
     475
     476static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
    259477int_on(void)
    260478{
    261     if (--suppressint == 0 && intpending) {
     479    xbarrier();
     480    if (--suppress_int == 0 && pending_int) {
    262481        raise_interrupt();
    263482    }
    264483}
    265484#define INT_ON int_on()
    266 static void
     485static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
    267486force_int_on(void)
    268487{
    269     suppressint = 0;
    270     if (intpending)
     488    xbarrier();
     489    suppress_int = 0;
     490    if (pending_int)
    271491        raise_interrupt();
    272492}
    273493#define FORCE_INT_ON force_int_on()
    274 #else
    275 #define INT_ON \
    276     do { \
    277         xbarrier(); \
    278         if (--suppressint == 0 && intpending) \
    279             raise_interrupt(); \
    280     } while (0)
    281 #define FORCE_INT_ON \
    282     do { \
    283         xbarrier(); \
    284         suppressint = 0; \
    285         if (intpending) \
    286             raise_interrupt(); \
    287     } while (0)
    288 #endif /* ASH_OPTIMIZE_FOR_SIZE */
    289 
    290 #define SAVE_INT(v) ((v) = suppressint)
    291 
    292 #define RESTORE_INT(v) \
    293     do { \
    294         xbarrier(); \
    295         suppressint = (v); \
    296         if (suppressint == 0 && intpending) \
    297             raise_interrupt(); \
    298     } while (0)
    299 
    300 #define EXSIGON \
    301     do { \
    302         exsig++; \
    303         xbarrier(); \
    304         if (pendingsig) \
    305             raise_exception(EXSIG); \
    306     } while (0)
    307 /* EXSIG is turned off by evalbltin(). */
    308 
    309 /*
    310  * Ignore a signal. Only one usage site - in forkchild()
    311  */
    312 static void
    313 ignoresig(int signo)
    314 {
    315     if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
    316         signal(signo, SIG_IGN);
    317     }
    318     sigmode[signo - 1] = S_HARD_IGN;
    319 }
    320 
    321 /*
    322  * Signal handler. Only one usage site - in setsignal()
    323  */
    324 static void
    325 onsig(int signo)
    326 {
    327     gotsig[signo - 1] = 1;
    328     pendingsig = signo;
    329 
    330     if (exsig || (signo == SIGINT && !trap[SIGINT])) {
    331         if (!suppressint) {
    332             pendingsig = 0;
    333             raise_interrupt();
    334         }
    335         intpending = 1;
    336     }
    337 }
     494
     495#define SAVE_INT(v) ((v) = suppress_int)
     496
     497#define RESTORE_INT(v) do { \
     498    xbarrier(); \
     499    suppress_int = (v); \
     500    if (suppress_int == 0 && pending_int) \
     501        raise_interrupt(); \
     502} while (0)
    338503
    339504
     
    352517{
    353518    INT_OFF;
    354     fflush(stdout);
    355     fflush(stderr);
    356     INT_ON;
    357 }
    358 
    359 static void
    360 flush_stderr(void)
    361 {
    362     INT_OFF;
    363     fflush(stderr);
     519    fflush_all();
    364520    INT_ON;
    365521}
     
    414570{
    415571    outstr(p, stderr);
    416     flush_stderr();
     572    flush_stdout_stderr();
    417573}
    418574
     
    421577
    422578/* control characters in argument strings */
    423 #define CTLESC '\201'           /* escape next character */
    424 #define CTLVAR '\202'           /* variable defn */
    425 #define CTLENDVAR '\203'
    426 #define CTLBACKQ '\204'
     579#define CTL_FIRST CTLESC
     580#define CTLESC       ((unsigned char)'\201')    /* escape next character */
     581#define CTLVAR       ((unsigned char)'\202')    /* variable defn */
     582#define CTLENDVAR    ((unsigned char)'\203')
     583#define CTLBACKQ     ((unsigned char)'\204')
    427584#define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
    428585/*      CTLBACKQ | CTLQUOTE == '\205' */
    429 #define CTLARI  '\206'          /* arithmetic expression */
    430 #define CTLENDARI '\207'
    431 #define CTLQUOTEMARK '\210'
     586#define CTLARI       ((unsigned char)'\206')    /* arithmetic expression */
     587#define CTLENDARI    ((unsigned char)'\207')
     588#define CTLQUOTEMARK ((unsigned char)'\210')
     589#define CTL_LAST CTLQUOTEMARK
    432590
    433591/* variable substitution byte (follows CTLVAR) */
     
    437595
    438596/* values of VSTYPE field */
    439 #define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
    440 #define VSMINUS         0x2             /* ${var-text} */
    441 #define VSPLUS          0x3             /* ${var+text} */
    442 #define VSQUESTION      0x4             /* ${var?message} */
    443 #define VSASSIGN        0x5             /* ${var=text} */
    444 #define VSTRIMRIGHT     0x6             /* ${var%pattern} */
    445 #define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
    446 #define VSTRIMLEFT      0x8             /* ${var#pattern} */
    447 #define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
    448 #define VSLENGTH        0xa             /* ${#var} */
     597#define VSNORMAL        0x1     /* normal variable:  $var or ${var} */
     598#define VSMINUS         0x2     /* ${var-text} */
     599#define VSPLUS          0x3     /* ${var+text} */
     600#define VSQUESTION      0x4     /* ${var?message} */
     601#define VSASSIGN        0x5     /* ${var=text} */
     602#define VSTRIMRIGHT     0x6     /* ${var%pattern} */
     603#define VSTRIMRIGHTMAX  0x7     /* ${var%%pattern} */
     604#define VSTRIMLEFT      0x8     /* ${var#pattern} */
     605#define VSTRIMLEFTMAX   0x9     /* ${var##pattern} */
     606#define VSLENGTH        0xa     /* ${#var} */
     607#if ENABLE_ASH_BASH_COMPAT
     608#define VSSUBSTR        0xc     /* ${var:position:length} */
     609#define VSREPLACE       0xd     /* ${var/pattern/replacement} */
     610#define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
     611#endif
    449612
    450613static const char dolatstr[] ALIGN1 = {
     
    452615};
    453616
    454 #define NCMD 0
    455 #define NPIPE 1
    456 #define NREDIR 2
    457 #define NBACKGND 3
     617#define NCMD      0
     618#define NPIPE     1
     619#define NREDIR    2
     620#define NBACKGND  3
    458621#define NSUBSHELL 4
    459 #define NAND 5
    460 #define NOR 6
    461 #define NSEMI 7
    462 #define NIF 8
    463 #define NWHILE 9
    464 #define NUNTIL 10
    465 #define NFOR 11
    466 #define NCASE 12
    467 #define NCLIST 13
    468 #define NDEFUN 14
    469 #define NARG 15
    470 #define NTO 16
    471 #define NCLOBBER 17
    472 #define NFROM 18
    473 #define NFROMTO 19
    474 #define NAPPEND 20
    475 #define NTOFD 21
    476 #define NFROMFD 22
    477 #define NHERE 23
    478 #define NXHERE 24
    479 #define NNOT 25
     622#define NAND      5
     623#define NOR       6
     624#define NSEMI     7
     625#define NIF       8
     626#define NWHILE    9
     627#define NUNTIL   10
     628#define NFOR     11
     629#define NCASE    12
     630#define NCLIST   13
     631#define NDEFUN   14
     632#define NARG     15
     633#define NTO      16
     634#if ENABLE_ASH_BASH_COMPAT
     635#define NTO2     17
     636#endif
     637#define NCLOBBER 18
     638#define NFROM    19
     639#define NFROMTO  20
     640#define NAPPEND  21
     641#define NTOFD    22
     642#define NFROMFD  23
     643#define NHERE    24
     644#define NXHERE   25
     645#define NNOT     26
     646#define N_NUMBER 27
    480647
    481648union node;
    482649
    483650struct ncmd {
    484     int type;
     651    smallint type; /* Nxxxx */
    485652    union node *assign;
    486653    union node *args;
     
    489656
    490657struct npipe {
    491     int type;
    492     int backgnd;
     658    smallint type;
     659    smallint pipe_backgnd;
    493660    struct nodelist *cmdlist;
    494661};
    495662
    496663struct nredir {
    497     int type;
     664    smallint type;
    498665    union node *n;
    499666    union node *redirect;
     
    501668
    502669struct nbinary {
    503     int type;
     670    smallint type;
    504671    union node *ch1;
    505672    union node *ch2;
     
    507674
    508675struct nif {
    509     int type;
     676    smallint type;
    510677    union node *test;
    511678    union node *ifpart;
     
    514681
    515682struct nfor {
    516     int type;
     683    smallint type;
    517684    union node *args;
    518685    union node *body;
     
    521688
    522689struct ncase {
    523     int type;
     690    smallint type;
    524691    union node *expr;
    525692    union node *cases;
     
    527694
    528695struct nclist {
    529     int type;
     696    smallint type;
    530697    union node *next;
    531698    union node *pattern;
     
    534701
    535702struct narg {
    536     int type;
     703    smallint type;
    537704    union node *next;
    538705    char *text;
     
    540707};
    541708
     709/* nfile and ndup layout must match!
     710 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
     711 * that it is actually NTO2 (>&file), and change its type.
     712 */
    542713struct nfile {
    543     int type;
     714    smallint type;
    544715    union node *next;
    545716    int fd;
     717    int _unused_dupfd;
    546718    union node *fname;
    547719    char *expfname;
     
    549721
    550722struct ndup {
    551     int type;
     723    smallint type;
    552724    union node *next;
    553725    int fd;
    554726    int dupfd;
    555727    union node *vname;
     728    char *_unused_expfname;
    556729};
    557730
    558731struct nhere {
    559     int type;
     732    smallint type;
    560733    union node *next;
    561734    int fd;
     
    564737
    565738struct nnot {
    566     int type;
     739    smallint type;
    567740    union node *com;
    568741};
    569742
    570743union node {
    571     int type;
     744    smallint type;
    572745    struct ncmd ncmd;
    573746    struct npipe npipe;
     
    585758};
    586759
     760/*
     761 * NODE_EOF is returned by parsecmd when it encounters an end of file.
     762 * It must be distinct from NULL.
     763 */
     764#define NODE_EOF ((union node *) -1L)
     765
    587766struct nodelist {
    588767    struct nodelist *next;
     
    619798    if (debug != 1)
    620799        return;
     800    if (DEBUG_TIME)
     801        fprintf(tracefile, "%u ", (int) time(NULL));
     802    if (DEBUG_PID)
     803        fprintf(tracefile, "[%u] ", (int) getpid());
     804    if (DEBUG_SIG)
     805        fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
    621806    va_start(va, fmt);
    622807    vfprintf(tracefile, fmt, va);
     
    629814    if (debug != 1)
    630815        return;
     816    if (DEBUG_TIME)
     817        fprintf(tracefile, "%u ", (int) time(NULL));
     818    if (DEBUG_PID)
     819        fprintf(tracefile, "[%u] ", (int) getpid());
     820    if (DEBUG_SIG)
     821        fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
    631822    vfprintf(tracefile, fmt, va);
    632823}
     
    650841    putc('"', tracefile);
    651842    for (p = s; *p; p++) {
    652         switch (*p) {
    653         case '\n':  c = 'n'; goto backslash;
    654         case '\t':  c = 't'; goto backslash;
    655         case '\r':  c = 'r'; goto backslash;
    656         case '"':  c = '"'; goto backslash;
    657         case '\\':  c = '\\'; goto backslash;
    658         case CTLESC:  c = 'e'; goto backslash;
    659         case CTLVAR:  c = 'v'; goto backslash;
    660         case CTLVAR+CTLQUOTE:  c = 'V'; goto backslash;
    661         case CTLBACKQ:  c = 'q'; goto backslash;
    662         case CTLBACKQ+CTLQUOTE:  c = 'Q'; goto backslash;
     843        switch ((unsigned char)*p) {
     844        case '\n': c = 'n'; goto backslash;
     845        case '\t': c = 't'; goto backslash;
     846        case '\r': c = 'r'; goto backslash;
     847        case '\"': c = '\"'; goto backslash;
     848        case '\\': c = '\\'; goto backslash;
     849        case CTLESC: c = 'e'; goto backslash;
     850        case CTLVAR: c = 'v'; goto backslash;
     851        case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
     852        case CTLBACKQ: c = 'q'; goto backslash;
     853        case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
    663854 backslash:
    664855            putc('\\', tracefile);
     
    670861            else {
    671862                putc('\\', tracefile);
    672                 putc(*p >> 6 & 03, tracefile);
    673                 putc(*p >> 3 & 07, tracefile);
     863                putc((*p >> 6) & 03, tracefile);
     864                putc((*p >> 3) & 07, tracefile);
    674865                putc(*p & 07, tracefile);
    675866            }
     
    755946    char *p;
    756947    struct nodelist *bqlist;
    757     int subtype;
     948    unsigned char subtype;
    758949
    759950    if (arg->type != NARG) {
     
    763954    bqlist = arg->narg.backquote;
    764955    for (p = arg->narg.text; *p; p++) {
    765         switch (*p) {
     956        switch ((unsigned char)*p) {
    766957        case CTLESC:
    767             putc(*++p, fp);
     958            p++;
     959            putc(*p, fp);
    768960            break;
    769961        case CTLVAR:
     
    774966                putc('#', fp);
    775967
    776             while (*p != '=')
    777                 putc(*p++, fp);
     968            while (*p != '=') {
     969                putc(*p, fp);
     970                p++;
     971            }
    778972
    779973            if (subtype & VSNUL)
     
    8561050        case NCLOBBER: s = ">|"; dftfd = 1; break;
    8571051        case NAPPEND:  s = ">>"; dftfd = 1; break;
     1052#if ENABLE_ASH_BASH_COMPAT
     1053        case NTO2:
     1054#endif
    8581055        case NTOFD:    s = ">&"; dftfd = 1; break;
    859         case NFROM:    s = "<";  break;
     1056        case NFROM:    s = "<"; break;
    8601057        case NFROMFD:  s = "<&"; break;
    8611058        case NFROMTO:  s = "<>"; break;
     
    8841081
    8851082    indent(ind, pfx, fp);
     1083
     1084    if (n == NODE_EOF) {
     1085        fputs("<EOF>", fp);
     1086        return;
     1087    }
     1088
    8861089    switch (n->type) {
    8871090    case NSEMI:
     
    9061109    case NPIPE:
    9071110        for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
    908             shcmd(lp->n, fp);
     1111            shtree(lp->n, 0, NULL, fp);
    9091112            if (lp->next)
    9101113                fputs(" | ", fp);
    9111114        }
    912         if (n->npipe.backgnd)
     1115        if (n->npipe.pipe_backgnd)
    9131116            fputs(" &", fp);
    9141117        if (ind >= 0)
     
    9271130{
    9281131    trace_puts("showtree called\n");
    929     shtree(n, 1, NULL, stdout);
    930 }
    931 
    932 #define TRACE(param)    trace_printf param
    933 #define TRACEV(param)   trace_vprintf param
    934 
    935 #else
    936 
    937 #define TRACE(param)
    938 #define TRACEV(param)
     1132    shtree(n, 1, NULL, stderr);
     1133}
    9391134
    9401135#endif /* DEBUG */
     
    9511146};
    9521147
    953 #if ENABLE_ASH_ALIAS
    9541148struct alias;
    955 #endif
    9561149
    9571150struct strpush {
    9581151    struct strpush *prev;   /* preceding string on stack */
    959     char *prevstring;
    960     int prevnleft;
     1152    char *prev_string;
     1153    int prev_left_in_line;
    9611154#if ENABLE_ASH_ALIAS
    9621155    struct alias *ap;       /* if push was associated with an alias */
     
    9681161    struct parsefile *prev; /* preceding file on stack */
    9691162    int linno;              /* current line */
    970     int fd;                 /* file descriptor (or -1 if string) */
    971     int nleft;              /* number of chars left in this line */
    972     int lleft;              /* number of chars left in this buffer */
    973     char *nextc;            /* next char in buffer */
     1163    int pf_fd;              /* file descriptor (or -1 if string) */
     1164    int left_in_line;       /* number of chars left in this line */
     1165    int left_in_buffer;     /* number of chars left in this buffer past the line */
     1166    char *next_to_pgetc;    /* next char in buffer */
    9741167    char *buf;              /* input buffer */
    9751168    struct strpush *strpush; /* for pushing strings at this level */
     
    9771170};
    9781171
    979 static struct parsefile basepf;         /* top level input file */
    980 static struct parsefile *parsefile = &basepf;  /* current input file */
     1172static struct parsefile basepf;        /* top level input file */
     1173static struct parsefile *g_parsefile = &basepf;  /* current input file */
    9811174static int startlinno;                 /* line # where last token started */
    9821175static char *commandname;              /* currently executing command */
    9831176static struct strlist *cmdenviron;     /* environment for builtin command */
    984 static int exitstatus;                 /* exit status of last command */
     1177static uint8_t exitstatus;             /* exit status of last command */
    9851178
    9861179
     
    9941187        if (strcmp(arg0, commandname))
    9951188            fprintf(stderr, "%s: ", commandname);
    996         if (!iflag || parsefile->fd)
     1189        if (!iflag || g_parsefile->pf_fd > 0)
    9971190            fprintf(stderr, "line %d: ", startlinno);
    9981191    }
     
    10061199 * formatting.  It then raises the error exception.
    10071200 */
    1008 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
     1201static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
    10091202static void
    10101203ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
     
    10261219}
    10271220
    1028 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
     1221static void ash_msg_and_raise_error(const char *, ...) NORETURN;
    10291222static void
    10301223ash_msg_and_raise_error(const char *msg, ...)
     
    10381231}
    10391232
    1040 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
     1233static void raise_error_syntax(const char *) NORETURN;
     1234static void
     1235raise_error_syntax(const char *msg)
     1236{
     1237    ash_msg_and_raise_error("syntax error: %s", msg);
     1238    /* NOTREACHED */
     1239}
     1240
     1241static void ash_msg_and_raise(int, const char *, ...) NORETURN;
    10411242static void
    10421243ash_msg_and_raise(int cond, const char *msg, ...)
     
    10791280
    10801281/* ============ Memory allocation */
     1282
     1283#if 0
     1284/* I consider these wrappers nearly useless:
     1285 * ok, they return you to nearest exception handler, but
     1286 * how much memory do you leak in the process, making
     1287 * memory starvation worse?
     1288 */
     1289static void *
     1290ckrealloc(void * p, size_t nbytes)
     1291{
     1292    p = realloc(p, nbytes);
     1293    if (!p)
     1294        ash_msg_and_raise_error(bb_msg_memory_exhausted);
     1295    return p;
     1296}
     1297
     1298static void *
     1299ckmalloc(size_t nbytes)
     1300{
     1301    return ckrealloc(NULL, nbytes);
     1302}
     1303
     1304static void *
     1305ckzalloc(size_t nbytes)
     1306{
     1307    return memset(ckmalloc(nbytes), 0, nbytes);
     1308}
     1309
     1310static char *
     1311ckstrdup(const char *s)
     1312{
     1313    char *p = strdup(s);
     1314    if (!p)
     1315        ash_msg_and_raise_error(bb_msg_memory_exhausted);
     1316    return p;
     1317}
     1318#else
     1319/* Using bbox equivalents. They exit if out of memory */
     1320# define ckrealloc xrealloc
     1321# define ckmalloc  xmalloc
     1322# define ckzalloc  xzalloc
     1323# define ckstrdup  xstrdup
     1324#endif
    10811325
    10821326/*
     
    10891333     * in some way.  The following macro will get this right
    10901334     * on many machines.  */
    1091     SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
     1335    SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
    10921336    /* Minimum size of a block */
    1093     MINSIZE  = SHELL_ALIGN(504),
     1337    MINSIZE = SHELL_ALIGN(504),
    10941338};
    10951339
     
    11061350};
    11071351
    1108 static struct stack_block stackbase;
    1109 static struct stack_block *stackp = &stackbase;
    1110 static struct stackmark *markp;
    1111 static char *stacknxt = stackbase.space;
    1112 static size_t stacknleft = MINSIZE;
    1113 static char *sstrend = stackbase.space + MINSIZE;
    1114 static int herefd = -1;
    1115 
    1116 #define stackblock() ((void *)stacknxt)
    1117 #define stackblocksize() stacknleft
    1118 
    1119 static void *
    1120 ckrealloc(void * p, size_t nbytes)
    1121 {
    1122     p = realloc(p, nbytes);
    1123     if (!p)
    1124         ash_msg_and_raise_error(bb_msg_memory_exhausted);
    1125     return p;
    1126 }
    1127 
    1128 static void *
    1129 ckmalloc(size_t nbytes)
    1130 {
    1131     return ckrealloc(NULL, nbytes);
    1132 }
    1133 
    1134 /*
    1135  * Make a copy of a string in safe storage.
    1136  */
    1137 static char *
    1138 ckstrdup(const char *s)
    1139 {
    1140     char *p = strdup(s);
    1141     if (!p)
    1142         ash_msg_and_raise_error(bb_msg_memory_exhausted);
    1143     return p;
    1144 }
     1352
     1353struct globals_memstack {
     1354    struct stack_block *g_stackp; // = &stackbase;
     1355    struct stackmark *markp;
     1356    char *g_stacknxt; // = stackbase.space;
     1357    char *sstrend; // = stackbase.space + MINSIZE;
     1358    size_t g_stacknleft; // = MINSIZE;
     1359    int    herefd; // = -1;
     1360    struct stack_block stackbase;
     1361};
     1362extern struct globals_memstack *const ash_ptr_to_globals_memstack;
     1363#define G_memstack (*ash_ptr_to_globals_memstack)
     1364#define g_stackp     (G_memstack.g_stackp    )
     1365#define markp        (G_memstack.markp       )
     1366#define g_stacknxt   (G_memstack.g_stacknxt  )
     1367#define sstrend      (G_memstack.sstrend     )
     1368#define g_stacknleft (G_memstack.g_stacknleft)
     1369#define herefd       (G_memstack.herefd      )
     1370#define stackbase    (G_memstack.stackbase   )
     1371#define INIT_G_memstack() do { \
     1372    (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
     1373    barrier(); \
     1374    g_stackp = &stackbase; \
     1375    g_stacknxt = stackbase.space; \
     1376    g_stacknleft = MINSIZE; \
     1377    sstrend = stackbase.space + MINSIZE; \
     1378    herefd = -1; \
     1379} while (0)
     1380
     1381
     1382#define stackblock()     ((void *)g_stacknxt)
     1383#define stackblocksize() g_stacknleft
    11451384
    11461385/*
     
    11591398
    11601399    aligned = SHELL_ALIGN(nbytes);
    1161     if (aligned > stacknleft) {
     1400    if (aligned > g_stacknleft) {
    11621401        size_t len;
    11631402        size_t blocksize;
     
    11721411        INT_OFF;
    11731412        sp = ckmalloc(len);
    1174         sp->prev = stackp;
    1175         stacknxt = sp->space;
    1176         stacknleft = blocksize;
    1177         sstrend = stacknxt + blocksize;
    1178         stackp = sp;
     1413        sp->prev = g_stackp;
     1414        g_stacknxt = sp->space;
     1415        g_stacknleft = blocksize;
     1416        sstrend = g_stacknxt + blocksize;
     1417        g_stackp = sp;
    11791418        INT_ON;
    11801419    }
    1181     p = stacknxt;
    1182     stacknxt += aligned;
    1183     stacknleft -= aligned;
     1420    p = g_stacknxt;
     1421    g_stacknxt += aligned;
     1422    g_stacknleft -= aligned;
    11841423    return p;
     1424}
     1425
     1426static void *
     1427stzalloc(size_t nbytes)
     1428{
     1429    return memset(stalloc(nbytes), 0, nbytes);
    11851430}
    11861431
     
    11891434{
    11901435#if DEBUG
    1191     if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
    1192         write(2, "stunalloc\n", 10);
     1436    if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
     1437        write(STDERR_FILENO, "stunalloc\n", 10);
    11931438        abort();
    11941439    }
    11951440#endif
    1196     stacknleft += stacknxt - (char *)p;
    1197     stacknxt = p;
     1441    g_stacknleft += g_stacknxt - (char *)p;
     1442    g_stacknxt = p;
    11981443}
    11991444
     
    12111456setstackmark(struct stackmark *mark)
    12121457{
    1213     mark->stackp = stackp;
    1214     mark->stacknxt = stacknxt;
    1215     mark->stacknleft = stacknleft;
     1458    mark->stackp = g_stackp;
     1459    mark->stacknxt = g_stacknxt;
     1460    mark->stacknleft = g_stacknleft;
    12161461    mark->marknext = markp;
    12171462    markp = mark;
     
    12281473    INT_OFF;
    12291474    markp = mark->marknext;
    1230     while (stackp != mark->stackp) {
    1231         sp = stackp;
    1232         stackp = sp->prev;
     1475    while (g_stackp != mark->stackp) {
     1476        sp = g_stackp;
     1477        g_stackp = sp->prev;
    12331478        free(sp);
    12341479    }
    1235     stacknxt = mark->stacknxt;
    1236     stacknleft = mark->stacknleft;
     1480    g_stacknxt = mark->stacknxt;
     1481    g_stacknleft = mark->stacknleft;
    12371482    sstrend = mark->stacknxt + mark->stacknleft;
    12381483    INT_ON;
     
    12531498    size_t newlen;
    12541499
    1255     newlen = stacknleft * 2;
    1256     if (newlen < stacknleft)
     1500    newlen = g_stacknleft * 2;
     1501    if (newlen < g_stacknleft)
    12571502        ash_msg_and_raise_error(bb_msg_memory_exhausted);
    12581503    if (newlen < 128)
    12591504        newlen += 128;
    12601505
    1261     if (stacknxt == stackp->space && stackp != &stackbase) {
     1506    if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
    12621507        struct stack_block *oldstackp;
    12631508        struct stackmark *xmark;
     
    12671512
    12681513        INT_OFF;
    1269         oldstackp = stackp;
    1270         sp = stackp;
     1514        oldstackp = g_stackp;
     1515        sp = g_stackp;
    12711516        prevstackp = sp->prev;
    12721517        grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
    12731518        sp = ckrealloc(sp, grosslen);
    12741519        sp->prev = prevstackp;
    1275         stackp = sp;
    1276         stacknxt = sp->space;
    1277         stacknleft = newlen;
     1520        g_stackp = sp;
     1521        g_stacknxt = sp->space;
     1522        g_stacknleft = newlen;
    12781523        sstrend = sp->space + newlen;
    12791524
     
    12841529        xmark = markp;
    12851530        while (xmark != NULL && xmark->stackp == oldstackp) {
    1286             xmark->stackp = stackp;
    1287             xmark->stacknxt = stacknxt;
    1288             xmark->stacknleft = stacknleft;
     1531            xmark->stackp = g_stackp;
     1532            xmark->stacknxt = g_stacknxt;
     1533            xmark->stacknleft = g_stacknleft;
    12891534            xmark = xmark->marknext;
    12901535        }
    12911536        INT_ON;
    12921537    } else {
    1293         char *oldspace = stacknxt;
    1294         int oldlen = stacknleft;
     1538        char *oldspace = g_stacknxt;
     1539        size_t oldlen = g_stacknleft;
    12951540        char *p = stalloc(newlen);
    12961541
    12971542        /* free the space we just allocated */
    1298         stacknxt = memcpy(p, oldspace, oldlen);
    1299         stacknleft += newlen;
     1543        g_stacknxt = memcpy(p, oldspace, oldlen);
     1544        g_stacknleft += newlen;
    13001545    }
    13011546}
     
    13051550{
    13061551    len = SHELL_ALIGN(len);
    1307     stacknxt += len;
    1308     stacknleft -= len;
     1552    g_stacknxt += len;
     1553    g_stacknleft -= len;
    13091554}
    13101555
     
    13351580    }
    13361581    growstackblock();
    1337     return stackblock() + len;
     1582    return (char *)stackblock() + len;
    13381583}
    13391584
     
    13441589makestrspace(size_t newlen, char *p)
    13451590{
    1346     size_t len = p - stacknxt;
     1591    size_t len = p - g_stacknxt;
    13471592    size_t size = stackblocksize();
    13481593
     
    13561601        growstackblock();
    13571602    }
    1358     return stackblock() + len;
     1603    return (char *)stackblock() + len;
    13591604}
    13601605
     
    13631608{
    13641609    p = makestrspace(n, p);
    1365     p = memcpy(p, s, n) + n;
     1610    p = (char *)memcpy(p, s, n) + n;
    13661611    return p;
    13671612}
     
    13841629#define STARTSTACKSTR(p)        ((p) = stackblock())
    13851630#define STPUTC(c, p)            ((p) = _STPUTC((c), (p)))
    1386 #define CHECKSTRSPACE(n, p) \
    1387     do { \
    1388         char *q = (p); \
    1389         size_t l = (n); \
    1390         size_t m = sstrend - q; \
    1391         if (l > m) \
    1392             (p) = makestrspace(l, q); \
    1393     } while (0)
    1394 #define USTPUTC(c, p)           (*p++ = (c))
    1395 #define STACKSTRNUL(p) \
    1396     do { \
    1397         if ((p) == sstrend) \
    1398             p = growstackstr(); \
    1399         *p = '\0'; \
    1400     } while (0)
    1401 #define STUNPUTC(p)             (--p)
    1402 #define STTOPC(p)               (p[-1])
    1403 #define STADJUST(amount, p)     (p += (amount))
     1631#define CHECKSTRSPACE(n, p) do { \
     1632    char *q = (p); \
     1633    size_t l = (n); \
     1634    size_t m = sstrend - q; \
     1635    if (l > m) \
     1636        (p) = makestrspace(l, q); \
     1637} while (0)
     1638#define USTPUTC(c, p)           (*(p)++ = (c))
     1639#define STACKSTRNUL(p) do { \
     1640    if ((p) == sstrend) \
     1641        (p) = growstackstr(); \
     1642    *(p) = '\0'; \
     1643} while (0)
     1644#define STUNPUTC(p)             (--(p))
     1645#define STTOPC(p)               ((p)[-1])
     1646#define STADJUST(amount, p)     ((p) += (amount))
    14041647
    14051648#define grabstackstr(p)         stalloc((char *)(p) - (char *)stackblock())
    1406 #define ungrabstackstr(s, p)    stunalloc((s))
     1649#define ungrabstackstr(s, p)    stunalloc(s)
    14071650#define stackstrend()           ((void *)sstrend)
    14081651
     
    14181661    while (*pfx) {
    14191662        if (*pfx++ != *string++)
    1420             return 0;
     1663            return NULL;
    14211664    }
    14221665    return (char *) string;
     
    14441687{
    14451688    if (!is_number(s))
    1446         ash_msg_and_raise_error(illnum, s);
     1689        ash_msg_and_raise_error(msg_illnum, s);
    14471690    return atoi(s);
    14481691}
     
    14681711
    14691712        *q++ = '\'';
    1470         q = memcpy(q, s, len) + len;
     1713        q = (char *)memcpy(q, s, len) + len;
    14711714        *q++ = '\'';
    14721715        s += len;
     
    14741717        STADJUST(q - p, p);
    14751718
    1476         len = strspn(s, "'");
    1477         if (!len)
     1719        if (*s != '\'')
    14781720            break;
     1721        len = 0;
     1722        do len++; while (*++s == '\'');
    14791723
    14801724        q = p = makestrspace(len + 3, p);
    14811725
    14821726        *q++ = '"';
    1483         q = memcpy(q, s, len) + len;
     1727        q = (char *)memcpy(q, s - len, len) + len;
    14841728        *q++ = '"';
    1485         s += len;
    14861729
    14871730        STADJUST(q - p, p);
    14881731    } while (*s);
    14891732
    1490     USTPUTC(0, p);
     1733    USTPUTC('\0', p);
    14911734
    14921735    return stackblock();
     
    15011744
    15021745/*
    1503  * XXX - should get rid of.  have all builtins use getopt(3).  the
    1504  * library getopt must have the BSD extension static variable "optreset"
    1505  * otherwise it can't be used within the shell safely.
     1746 * XXX - should get rid of. Have all builtins use getopt(3).
     1747 * The library getopt must have the BSD extension static variable
     1748 * "optreset", otherwise it can't be used within the shell safely.
    15061749 *
    1507  * Standard option processing (a la getopt) for builtin routines.  The
    1508  * only argument that is passed to nextopt is the option string; the
    1509  * other arguments are unnecessary.  It return the character, or '\0' on
    1510  * end of input.
     1750 * Standard option processing (a la getopt) for builtin routines.
     1751 * The only argument that is passed to nextopt is the option string;
     1752 * the other arguments are unnecessary. It returns the character,
     1753 * or '\0' on end of input.
    15111754 */
    15121755static int
     
    15191762    p = optptr;
    15201763    if (p == NULL || *p == '\0') {
     1764        /* We ate entire "-param", take next one */
    15211765        p = *argptr;
    1522         if (p == NULL || *p != '-' || *++p == '\0')
     1766        if (p == NULL)
     1767            return '\0';
     1768        if (*p != '-')
     1769            return '\0';
     1770        if (*++p == '\0') /* just "-" ? */
    15231771            return '\0';
    15241772        argptr++;
    1525         if (LONE_DASH(p))        /* check for "--" */
     1773        if (LONE_DASH(p)) /* "--" ? */
    15261774            return '\0';
    1527     }
     1775        /* p => next "-param" */
     1776    }
     1777    /* p => some option char in the middle of a "-param" */
    15281778    c = *p++;
    1529     for (q = optstring; *q != c; ) {
     1779    for (q = optstring; *q != c;) {
    15301780        if (*q == '\0')
    15311781            ash_msg_and_raise_error("illegal option -%c", c);
     
    15341784    }
    15351785    if (*++q == ':') {
    1536         if (*p == '\0' && (p = *argptr++) == NULL)
    1537             ash_msg_and_raise_error("no arg for -%c option", c);
     1786        if (*p == '\0') {
     1787            p = *argptr++;
     1788            if (p == NULL)
     1789                ash_msg_and_raise_error("no arg for -%c option", c);
     1790        }
    15381791        optionarg = p;
    15391792        p = NULL;
     
    15441797
    15451798
    1546 /* ============ Math support definitions */
    1547 
    1548 #if ENABLE_ASH_MATH_SUPPORT_64
    1549 typedef int64_t arith_t;
    1550 #define arith_t_type long long
    1551 #else
    1552 typedef long arith_t;
    1553 #define arith_t_type long
    1554 #endif
    1555 
    1556 #if ENABLE_ASH_MATH_SUPPORT
    1557 static arith_t dash_arith(const char *);
    1558 static arith_t arith(const char *expr, int *perrcode);
    1559 #endif
    1560 
    1561 #if ENABLE_ASH_RANDOM_SUPPORT
    1562 static unsigned long rseed;
    1563 #ifndef DYNAMIC_VAR
    1564 #define DYNAMIC_VAR
    1565 #endif
    1566 #endif
    1567 
    1568 
    15691799/* ============ Shell variables */
     1800
     1801/*
     1802 * The parsefile structure pointed to by the global variable parsefile
     1803 * contains information about the current file being read.
     1804 */
     1805struct shparam {
     1806    int nparam;             /* # of positional parameters (without $0) */
     1807#if ENABLE_ASH_GETOPTS
     1808    int optind;             /* next parameter to be processed by getopts */
     1809    int optoff;             /* used by getopts */
     1810#endif
     1811    unsigned char malloced; /* if parameter list dynamically allocated */
     1812    char **p;               /* parameter list */
     1813};
     1814
     1815/*
     1816 * Free the list of positional parameters.
     1817 */
     1818static void
     1819freeparam(volatile struct shparam *param)
     1820{
     1821    if (param->malloced) {
     1822        char **ap, **ap1;
     1823        ap = ap1 = param->p;
     1824        while (*ap)
     1825            free(*ap++);
     1826        free(ap1);
     1827    }
     1828}
     1829
     1830#if ENABLE_ASH_GETOPTS
     1831static void FAST_FUNC getoptsreset(const char *value);
     1832#endif
     1833
     1834struct var {
     1835    struct var *next;               /* next entry in hash list */
     1836    int flags;                      /* flags are defined above */
     1837    const char *var_text;           /* name=value */
     1838    void (*var_func)(const char *) FAST_FUNC; /* function to be called when  */
     1839                    /* the variable gets set/unset */
     1840};
     1841
     1842struct localvar {
     1843    struct localvar *next;          /* next local variable in list */
     1844    struct var *vp;                 /* the variable that was made local */
     1845    int flags;                      /* saved flags */
     1846    const char *text;               /* saved text */
     1847};
    15701848
    15711849/* flags */
     
    15791857#define VNOSET          0x80    /* do not set variable - just readonly test */
    15801858#define VNOSAVE         0x100   /* when text is on the heap before setvareq */
    1581 #ifdef DYNAMIC_VAR
     1859#if ENABLE_ASH_RANDOM_SUPPORT
    15821860# define VDYNAMIC       0x200   /* dynamic variable */
    15831861#else
     
    15851863#endif
    15861864
    1587 #ifdef IFS_BROKEN
    1588 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
    1589 #define defifs (defifsvar + 4)
    1590 #else
    1591 static const char defifs[] ALIGN1 = " \t\n";
    1592 #endif
    1593 
    1594 struct shparam {
    1595     int nparam;             /* # of positional parameters (without $0) */
    1596     unsigned char malloc;   /* if parameter list dynamically allocated */
    1597     char **p;               /* parameter list */
    1598 #if ENABLE_ASH_GETOPTS
    1599     int optind;             /* next parameter to be processed by getopts */
    1600     int optoff;             /* used by getopts */
    1601 #endif
    1602 };
    1603 
    1604 static struct shparam shellparam;      /* $@ current positional parameters */
    1605 
    1606 /*
    1607  * Free the list of positional parameters.
    1608  */
    1609 static void
    1610 freeparam(volatile struct shparam *param)
    1611 {
    1612     char **ap;
    1613 
    1614     if (param->malloc) {
    1615         for (ap = param->p; *ap; ap++)
    1616             free(*ap);
    1617         free(param->p);
    1618     }
    1619 }
    1620 
    1621 #if ENABLE_ASH_GETOPTS
    1622 static void
    1623 getoptsreset(const char *value)
    1624 {
    1625     shellparam.optind = number(value);
    1626     shellparam.optoff = -1;
    1627 }
    1628 #endif
    1629 
    1630 struct var {
    1631     struct var *next;               /* next entry in hash list */
    1632     int flags;                      /* flags are defined above */
    1633     const char *text;               /* name=value */
    1634     void (*func)(const char *);     /* function to be called when  */
    1635                     /* the variable gets set/unset */
    1636 };
    1637 
    1638 struct localvar {
    1639     struct localvar *next;          /* next local variable in list */
    1640     struct var *vp;                 /* the variable that was made local */
    1641     int flags;                      /* saved flags */
    1642     const char *text;               /* saved text */
    1643 };
    1644 
    1645 /* Forward decls for varinit[] */
     1865
     1866/* Need to be before varinit_data[] */
    16461867#if ENABLE_LOCALE_SUPPORT
    1647 static void
     1868static void FAST_FUNC
    16481869change_lc_all(const char *value)
    16491870{
     
    16511872        setlocale(LC_ALL, value);
    16521873}
    1653 static void
     1874static void FAST_FUNC
    16541875change_lc_ctype(const char *value)
    16551876{
     
    16601881#if ENABLE_ASH_MAIL
    16611882static void chkmail(void);
    1662 static void changemail(const char *);
    1663 #endif
    1664 static void changepath(const char *);
     1883static void changemail(const char *) FAST_FUNC;
     1884#endif
     1885static void changepath(const char *) FAST_FUNC;
    16651886#if ENABLE_ASH_RANDOM_SUPPORT
    1666 static void change_random(const char *);
    1667 #endif
    1668 
    1669 static struct var varinit[] = {
    1670 #ifdef IFS_BROKEN
    1671     { NULL, VSTRFIXED|VTEXTFIXED,           defifsvar,      NULL },
     1887static void change_random(const char *) FAST_FUNC;
     1888#endif
     1889
     1890static const struct {
     1891    int flags;
     1892    const char *var_text;
     1893    void (*var_func)(const char *) FAST_FUNC;
     1894} varinit_data[] = {
     1895    { VSTRFIXED|VTEXTFIXED       , defifsvar   , NULL            },
     1896#if ENABLE_ASH_MAIL
     1897    { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL"      , changemail      },
     1898    { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH"  , changemail      },
     1899#endif
     1900    { VSTRFIXED|VTEXTFIXED       , bb_PATH_root_path, changepath },
     1901    { VSTRFIXED|VTEXTFIXED       , "PS1=$ "    , NULL            },
     1902    { VSTRFIXED|VTEXTFIXED       , "PS2=> "    , NULL            },
     1903    { VSTRFIXED|VTEXTFIXED       , "PS4=+ "    , NULL            },
     1904#if ENABLE_ASH_GETOPTS
     1905    { VSTRFIXED|VTEXTFIXED       , "OPTIND=1"  , getoptsreset    },
     1906#endif
     1907#if ENABLE_ASH_RANDOM_SUPPORT
     1908    { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
     1909#endif
     1910#if ENABLE_LOCALE_SUPPORT
     1911    { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL"    , change_lc_all   },
     1912    { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE"  , change_lc_ctype },
     1913#endif
     1914#if ENABLE_FEATURE_EDITING_SAVEHISTORY
     1915    { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE"  , NULL            },
     1916#endif
     1917};
     1918
     1919struct redirtab;
     1920
     1921struct globals_var {
     1922    struct shparam shellparam;      /* $@ current positional parameters */
     1923    struct redirtab *redirlist;
     1924    int g_nullredirs;
     1925    int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
     1926    struct var *vartab[VTABSIZE];
     1927    struct var varinit[ARRAY_SIZE(varinit_data)];
     1928};
     1929extern struct globals_var *const ash_ptr_to_globals_var;
     1930#define G_var (*ash_ptr_to_globals_var)
     1931#define shellparam    (G_var.shellparam   )
     1932//#define redirlist     (G_var.redirlist    )
     1933#define g_nullredirs  (G_var.g_nullredirs )
     1934#define preverrout_fd (G_var.preverrout_fd)
     1935#define vartab        (G_var.vartab       )
     1936#define varinit       (G_var.varinit      )
     1937#define INIT_G_var() do { \
     1938    unsigned i; \
     1939    (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
     1940    barrier(); \
     1941    for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
     1942        varinit[i].flags    = varinit_data[i].flags; \
     1943        varinit[i].var_text = varinit_data[i].var_text; \
     1944        varinit[i].var_func = varinit_data[i].var_func; \
     1945    } \
     1946} while (0)
     1947
     1948#define vifs      varinit[0]
     1949#if ENABLE_ASH_MAIL
     1950# define vmail    (&vifs)[1]
     1951# define vmpath   (&vmail)[1]
     1952# define vpath    (&vmpath)[1]
    16721953#else
    1673     { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        NULL },
    1674 #endif
    1675 #if ENABLE_ASH_MAIL
    1676     { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
    1677     { NULL, VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
    1678 #endif
    1679     { NULL, VSTRFIXED|VTEXTFIXED,           bb_PATH_root_path, changepath },
    1680     { NULL, VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       NULL },
    1681     { NULL, VSTRFIXED|VTEXTFIXED,           "PS2=> ",       NULL },
    1682     { NULL, VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       NULL },
     1954# define vpath    (&vifs)[1]
     1955#endif
     1956#define vps1      (&vpath)[1]
     1957#define vps2      (&vps1)[1]
     1958#define vps4      (&vps2)[1]
    16831959#if ENABLE_ASH_GETOPTS
    1684     { NULL, VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
    1685 #endif
    1686 #if ENABLE_ASH_RANDOM_SUPPORT
    1687     { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
    1688 #endif
    1689 #if ENABLE_LOCALE_SUPPORT
    1690     { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0",    change_lc_all },
    1691     { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0",  change_lc_ctype },
    1692 #endif
    1693 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
    1694     { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0",  NULL },
    1695 #endif
    1696 };
    1697 
    1698 #define vifs varinit[0]
    1699 #if ENABLE_ASH_MAIL
    1700 #define vmail (&vifs)[1]
    1701 #define vmpath (&vmail)[1]
     1960# define voptind  (&vps4)[1]
     1961# if ENABLE_ASH_RANDOM_SUPPORT
     1962#  define vrandom (&voptind)[1]
     1963# endif
    17021964#else
    1703 #define vmpath vifs
    1704 #endif
    1705 #define vpath (&vmpath)[1]
    1706 #define vps1 (&vpath)[1]
    1707 #define vps2 (&vps1)[1]
    1708 #define vps4 (&vps2)[1]
    1709 #define voptind (&vps4)[1]
    1710 #if ENABLE_ASH_GETOPTS
    1711 #define vrandom (&voptind)[1]
    1712 #else
    1713 #define vrandom (&vps4)[1]
     1965# if ENABLE_ASH_RANDOM_SUPPORT
     1966#  define vrandom (&vps4)[1]
     1967# endif
    17141968#endif
    17151969
     
    17191973 * for unset variables.
    17201974 */
    1721 #define ifsval()        (vifs.text + 4)
     1975#define ifsval()        (vifs.var_text + 4)
    17221976#define ifsset()        ((vifs.flags & VUNSET) == 0)
    1723 #define mailval()       (vmail.text + 5)
    1724 #define mpathval()      (vmpath.text + 9)
    1725 #define pathval()       (vpath.text + 5)
    1726 #define ps1val()        (vps1.text + 4)
    1727 #define ps2val()        (vps2.text + 4)
    1728 #define ps4val()        (vps4.text + 4)
    1729 #define optindval()     (voptind.text + 7)
    1730 
    1731 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
    1732 
    1733 /*
    1734  * The parsefile structure pointed to by the global variable parsefile
    1735  * contains information about the current file being read.
    1736  */
    1737 struct redirtab {
    1738     struct redirtab *next;
    1739     int renamed[10];
    1740     int nullredirs;
    1741 };
    1742 
    1743 static struct redirtab *redirlist;
    1744 static int nullredirs;
    1745 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
    1746 
    1747 #define VTABSIZE 39
    1748 
    1749 static struct var *vartab[VTABSIZE];
    1750 
     1977#if ENABLE_ASH_MAIL
     1978# define mailval()      (vmail.var_text + 5)
     1979# define mpathval()     (vmpath.var_text + 9)
     1980# define mpathset()     ((vmpath.flags & VUNSET) == 0)
     1981#endif
     1982#define pathval()       (vpath.var_text + 5)
     1983#define ps1val()        (vps1.var_text + 4)
     1984#define ps2val()        (vps2.var_text + 4)
     1985#define ps4val()        (vps4.var_text + 4)
     1986#if ENABLE_ASH_GETOPTS
     1987# define optindval()    (voptind.var_text + 7)
     1988#endif
     1989
     1990#if ENABLE_ASH_GETOPTS
     1991static void FAST_FUNC
     1992getoptsreset(const char *value)
     1993{
     1994    shellparam.optind = number(value);
     1995    shellparam.optoff = -1;
     1996}
     1997#endif
     1998
     1999/* math.h has these, otherwise define our private copies */
     2000#if !ENABLE_SH_MATH_SUPPORT
    17512001#define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
    17522002#define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
    1753 
    1754 /*
    1755  * Return of a legal variable name (a letter or underscore followed by zero or
    1756  * more letters, underscores, and digits).
    1757  */
    1758 static char *
     2003/*
     2004 * Return the pointer to the first char which is not part of a legal variable name
     2005 * (a letter or underscore followed by letters, underscores, and digits).
     2006 */
     2007static const char*
    17592008endofname(const char *name)
    17602009{
    1761     char *p;
    1762 
    1763     p = (char *) name;
    1764     if (!is_name(*p))
    1765         return p;
    1766     while (*++p) {
    1767         if (!is_in_name(*p))
     2010    if (!is_name(*name))
     2011        return name;
     2012    while (*++name) {
     2013        if (!is_in_name(*name))
    17682014            break;
    17692015    }
    1770     return p;
    1771 }
     2016    return name;
     2017}
     2018#endif
    17722019
    17732020/*
     
    17952042}
    17962043
    1797 static int
    1798 varequal(const char *a, const char *b)
    1799 {
    1800     return !varcmp(a, b);
    1801 }
    1802 
    18032044/*
    18042045 * Find the appropriate entry in the hash table from the name.
     
    18352076     */
    18362077#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
    1837     vps1.text = "PS1=\\w \\$ ";
     2078    vps1.var_text = "PS1=\\w \\$ ";
    18382079#else
    18392080    if (!geteuid())
    1840         vps1.text = "PS1=# ";
     2081        vps1.var_text = "PS1=# ";
    18412082#endif
    18422083    vp = varinit;
    18432084    end = vp + ARRAY_SIZE(varinit);
    18442085    do {
    1845         vpp = hashvar(vp->text);
     2086        vpp = hashvar(vp->var_text);
    18462087        vp->next = *vpp;
    18472088        *vpp = vp;
     
    18532094{
    18542095    for (; *vpp; vpp = &(*vpp)->next) {
    1855         if (varequal((*vpp)->text, name)) {
     2096        if (varcmp((*vpp)->var_text, name) == 0) {
    18562097            break;
    18572098        }
     
    18632104 * Find the value of a variable.  Returns NULL if not set.
    18642105 */
    1865 static char *
     2106static const char* FAST_FUNC
    18662107lookupvar(const char *name)
    18672108{
     
    18702111    v = *findvar(hashvar(name), name);
    18712112    if (v) {
    1872 #ifdef DYNAMIC_VAR
     2113#if ENABLE_ASH_RANDOM_SUPPORT
    18732114    /*
    18742115     * Dynamic variables are implemented roughly the same way they are
     
    18772118     * lookup will no longer happen at that point. -- PFM.
    18782119     */
    1879         if ((v->flags & VDYNAMIC))
    1880             (*v->func)(NULL);
     2120        if (v->flags & VDYNAMIC)
     2121            v->var_func(NULL);
    18812122#endif
    18822123        if (!(v->flags & VUNSET))
    1883             return strchrnul(v->text, '=') + 1;
     2124            return var_end(v->var_text);
    18842125    }
    18852126    return NULL;
     
    18892130 * Search the environment of a builtin command.
    18902131 */
    1891 static char *
     2132static const char *
    18922133bltinlookup(const char *name)
    18932134{
     
    18952136
    18962137    for (sp = cmdenviron; sp; sp = sp->next) {
    1897         if (varequal(sp->text, name))
    1898             return strchrnul(sp->text, '=') + 1;
     2138        if (varcmp(sp->text, name) == 0)
     2139            return var_end(sp->text);
    18992140    }
    19002141    return lookupvar(name);
     
    19222163            if (flags & VNOSAVE)
    19232164                free(s);
    1924             n = vp->text;
     2165            n = vp->var_text;
    19252166            ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
    19262167        }
     
    19292170            return;
    19302171
    1931         if (vp->func && (flags & VNOFUNC) == 0)
    1932             (*vp->func)(strchrnul(s, '=') + 1);
    1933 
    1934         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    1935             free((char*)vp->text);
     2172        if (vp->var_func && !(flags & VNOFUNC))
     2173            vp->var_func(var_end(s));
     2174
     2175        if (!(vp->flags & (VTEXTFIXED|VSTACK)))
     2176            free((char*)vp->var_text);
    19362177
    19372178        flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
    19382179    } else {
     2180        /* variable s is not found */
    19392181        if (flags & VNOSET)
    19402182            return;
    1941         /* not found */
    1942         vp = ckmalloc(sizeof(*vp));
     2183        vp = ckzalloc(sizeof(*vp));
    19432184        vp->next = *vpp;
    1944         vp->func = NULL;
     2185        /*vp->func = NULL; - ckzalloc did it */
    19452186        *vpp = vp;
    19462187    }
    19472188    if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
    19482189        s = ckstrdup(s);
    1949     vp->text = s;
     2190    vp->var_text = s;
    19502191    vp->flags = flags;
    19512192}
     
    19582199setvar(const char *name, const char *val, int flags)
    19592200{
    1960     char *p, *q;
     2201    const char *q;
     2202    char *p;
     2203    char *nameeq;
    19612204    size_t namelen;
    1962     char *nameeq;
    19632205    size_t vallen;
    19642206
     
    19742216        vallen = strlen(val);
    19752217    }
     2218
    19762219    INT_OFF;
    19772220    nameeq = ckmalloc(namelen + vallen + 2);
     
    19842227    setvareq(nameeq, flags | VNOSAVE);
    19852228    INT_ON;
     2229}
     2230
     2231static void FAST_FUNC
     2232setvar2(const char *name, const char *val)
     2233{
     2234    setvar(name, val, 0);
    19862235}
    19872236
     
    20312280        if (flags & VREADONLY)
    20322281            goto out;
    2033 #ifdef DYNAMIC_VAR
     2282#if ENABLE_ASH_RANDOM_SUPPORT
    20342283        vp->flags &= ~VDYNAMIC;
    20352284#endif
     
    20392288            INT_OFF;
    20402289            if ((flags & (VTEXTFIXED|VSTACK)) == 0)
    2041                 free((char*)vp->text);
     2290                free((char*)vp->var_text);
    20422291            *vpp = vp->next;
    20432292            free(vp);
     
    20912340                if (ep == stackstrend())
    20922341                    ep = growstackstr();
    2093                 *ep++ = (char *) vp->text;
     2342                *ep++ = (char*)vp->var_text;
    20942343            }
    20952344        }
     
    21072356 *
    21082357 * The variable path (passed by reference) should be set to the start
    2109  * of the path before the first call; padvance will update
    2110  * this value as it proceeds.  Successive calls to padvance will return
     2358 * of the path before the first call; path_advance will update
     2359 * this value as it proceeds.  Successive calls to path_advance will return
    21112360 * the possible path expansions in sequence.  If an option (indicated by
    21122361 * a percent sign) appears in the path entry then the global variable
     
    21142363 * NULL.
    21152364 */
    2116 static const char *pathopt;     /* set by padvance */
     2365static const char *pathopt;     /* set by path_advance */
    21172366
    21182367static char *
    2119 padvance(const char **path, const char *name)
     2368path_advance(const char **path, const char *name)
    21202369{
    21212370    const char *p;
     
    21272376        return NULL;
    21282377    start = *path;
    2129     for (p = start; *p && *p != ':' && *p != '%'; p++);
     2378    for (p = start; *p && *p != ':' && *p != '%'; p++)
     2379        continue;
    21302380    len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
    21312381    while (stackblocksize() < len)
     
    21412391    if (*p == '%') {
    21422392        pathopt = ++p;
    2143         while (*p && *p != ':') p++;
     2393        while (*p && *p != ':')
     2394            p++;
    21442395    }
    21452396    if (*p == ':')
     
    21532404/* ============ Prompt */
    21542405
    2155 static int doprompt;                   /* if set, prompt the user */
    2156 static int needprompt;                 /* true if interactive and at start of line */
     2406static smallint doprompt;                   /* if set, prompt the user */
     2407static smallint needprompt;                 /* true if interactive and at start of line */
    21572408
    21582409#if ENABLE_FEATURE_EDITING
     
    21852436
    21862437static void
    2187 setprompt(int whichprompt)
     2438setprompt_if(smallint do_set, int whichprompt)
    21882439{
    21892440    const char *prompt;
    2190 #if ENABLE_ASH_EXPAND_PRMT
    2191     struct stackmark smark;
    2192 #endif
     2441    IF_ASH_EXPAND_PRMT(struct stackmark smark;)
     2442
     2443    if (!do_set)
     2444        return;
    21932445
    21942446    needprompt = 0;
     
    22202472#define CD_PRINT 2
    22212473
    2222 static int docd(const char *, int);
    2223 
    2224 static char *curdir = nullstr;          /* current working directory */
    2225 static char *physdir = nullstr;         /* physical working directory */
    2226 
    22272474static int
    22282475cdopt(void)
     
    22322479
    22332480    j = 'L';
    2234     while ((i = nextopt("LP"))) {
     2481    while ((i = nextopt("LP")) != '\0') {
    22352482        if (i != j) {
    22362483            flags ^= CD_PHYSICAL;
     
    22622509    }
    22632510    new = makestrspace(strlen(dir) + 2, new);
    2264     lim = stackblock() + 1;
     2511    lim = (char *)stackblock() + 1;
    22652512    if (*dir != '/') {
    22662513        if (new[-1] != '/')
     
    23112558getpwd(void)
    23122559{
    2313     char *dir = getcwd(0, 0);
     2560    char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
    23142561    return dir ? dir : nullstr;
    23152562}
     
    23552602docd(const char *dest, int flags)
    23562603{
    2357     const char *dir = 0;
     2604    const char *dir = NULL;
    23582605    int err;
    23592606
     
    23762623}
    23772624
    2378 static int
    2379 cdcmd(int argc, char **argv)
     2625static int FAST_FUNC
     2626cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    23802627{
    23812628    const char *dest;
     
    23892636    dest = *argptr;
    23902637    if (!dest)
    2391         dest = bltinlookup(homestr);
     2638        dest = bltinlookup("HOME");
    23922639    else if (LONE_DASH(dest)) {
    23932640        dest = bltinlookup("OLDPWD");
     
    24222669    do {
    24232670        c = *path;
    2424         p = padvance(&path, dest);
     2671        p = path_advance(&path, dest);
    24252672        if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
    24262673            if (c && c != ':')
     
    24362683 out:
    24372684    if (flags & CD_PRINT)
    2438         out1fmt(snlfmt, curdir);
     2685        out1fmt("%s\n", curdir);
    24392686    return 0;
    24402687}
    24412688
    2442 static int
    2443 pwdcmd(int argc, char **argv)
     2689static int FAST_FUNC
     2690pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    24442691{
    24452692    int flags;
     
    24522699        dir = physdir;
    24532700    }
    2454     out1fmt(snlfmt, dir);
     2701    out1fmt("%s\n", dir);
    24552702    return 0;
    24562703}
     
    24592706/* ============ ... */
    24602707
    2461 #define IBUFSIZ (BUFSIZ + 1)
    2462 #define basebuf bb_common_bufsiz1       /* buffer for top level input file */
     2708
     2709#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
    24632710
    24642711/* Syntax classes */
    2465 #define CWORD 0                 /* character is nothing special */
    2466 #define CNL 1                   /* newline character */
    2467 #define CBACK 2                 /* a backslash character */
    2468 #define CSQUOTE              /* single quote */
    2469 #define CDQUOTE              /* double quote */
     2712#define CWORD     0             /* character is nothing special */
     2713#define CNL       1             /* newline character */
     2714#define CBACK     2             /* a backslash character */
     2715#define CSQUOTE   3             /* single quote */
     2716#define CDQUOTE   4             /* double quote */
    24702717#define CENDQUOTE 5             /* a terminating quote */
    2471 #define CBQUOTE              /* backwards single quote */
    2472 #define CVAR 7                  /* a dollar sign */
    2473 #define CENDVAR              /* a '}' character */
    2474 #define CLP 9                   /* a left paren in arithmetic */
    2475 #define CRP 10                  /* a right paren in arithmetic */
     2718#define CBQUOTE   6             /* backwards single quote */
     2719#define CVAR      7             /* a dollar sign */
     2720#define CENDVAR   8             /* a '}' character */
     2721#define CLP       9             /* a left paren in arithmetic */
     2722#define CRP      10             /* a right paren in arithmetic */
    24762723#define CENDFILE 11             /* end of file */
    2477 #define CCTL 12                 /* like CWORD, except it must be escaped */
    2478 #define CSPCL 13                /* these terminate a word */
    2479 #define CIGN 14                 /* character should be ignored */
    2480 
     2724#define CCTL     12             /* like CWORD, except it must be escaped */
     2725#define CSPCL    13             /* these terminate a word */
     2726#define CIGN     14             /* character should be ignored */
     2727
     2728#define PEOF     256
    24812729#if ENABLE_ASH_ALIAS
    2482 #define SYNBASE 130
    2483 #define PEOF -130
    2484 #define PEOA -129
    2485 #define PEOA_OR_PEOF PEOA
     2730# define PEOA    257
     2731#endif
     2732
     2733#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
     2734
     2735#if ENABLE_SH_MATH_SUPPORT
     2736# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
    24862737#else
    2487 #define SYNBASE 129
    2488 #define PEOF -129
    2489 #define PEOA_OR_PEOF PEOF
    2490 #endif
    2491 
    2492 /* number syntax index */
     2738# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
     2739#endif
     2740static const uint16_t S_I_T[] = {
     2741#if ENABLE_ASH_ALIAS
     2742    SIT_ITEM(CSPCL   , CIGN     , CIGN , CIGN   ),    /* 0, PEOA */
     2743#endif
     2744    SIT_ITEM(CSPCL   , CWORD    , CWORD, CWORD  ),    /* 1, ' ' */
     2745    SIT_ITEM(CNL     , CNL      , CNL  , CNL    ),    /* 2, \n */
     2746    SIT_ITEM(CWORD   , CCTL     , CCTL , CWORD  ),    /* 3, !*-/:=?[]~ */
     2747    SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD  ),    /* 4, '"' */
     2748    SIT_ITEM(CVAR    , CVAR     , CWORD, CVAR   ),    /* 5, $ */
     2749    SIT_ITEM(CSQUOTE , CWORD    , CENDQUOTE, CWORD),  /* 6, "'" */
     2750    SIT_ITEM(CSPCL   , CWORD    , CWORD, CLP    ),    /* 7, ( */
     2751    SIT_ITEM(CSPCL   , CWORD    , CWORD, CRP    ),    /* 8, ) */
     2752    SIT_ITEM(CBACK   , CBACK    , CCTL , CBACK  ),    /* 9, \ */
     2753    SIT_ITEM(CBQUOTE , CBQUOTE  , CWORD, CBQUOTE),    /* 10, ` */
     2754    SIT_ITEM(CENDVAR , CENDVAR  , CWORD, CENDVAR),    /* 11, } */
     2755#if !USE_SIT_FUNCTION
     2756    SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
     2757    SIT_ITEM(CWORD   , CWORD    , CWORD, CWORD  ),    /* 13, 0-9A-Za-z */
     2758    SIT_ITEM(CCTL    , CCTL     , CCTL , CCTL   )     /* 14, CTLESC ... */
     2759#endif
     2760#undef SIT_ITEM
     2761};
     2762/* Constants below must match table above */
     2763enum {
     2764#if ENABLE_ASH_ALIAS
     2765    CSPCL_CIGN_CIGN_CIGN               , /*  0 */
     2766#endif
     2767    CSPCL_CWORD_CWORD_CWORD            , /*  1 */
     2768    CNL_CNL_CNL_CNL                    , /*  2 */
     2769    CWORD_CCTL_CCTL_CWORD              , /*  3 */
     2770    CDQUOTE_CENDQUOTE_CWORD_CWORD      , /*  4 */
     2771    CVAR_CVAR_CWORD_CVAR               , /*  5 */
     2772    CSQUOTE_CWORD_CENDQUOTE_CWORD      , /*  6 */
     2773    CSPCL_CWORD_CWORD_CLP              , /*  7 */
     2774    CSPCL_CWORD_CWORD_CRP              , /*  8 */
     2775    CBACK_CBACK_CCTL_CBACK             , /*  9 */
     2776    CBQUOTE_CBQUOTE_CWORD_CBQUOTE      , /* 10 */
     2777    CENDVAR_CENDVAR_CWORD_CENDVAR      , /* 11 */
     2778    CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
     2779    CWORD_CWORD_CWORD_CWORD            , /* 13 */
     2780    CCTL_CCTL_CCTL_CCTL                , /* 14 */
     2781};
     2782
     2783/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
     2784 * caller must ensure proper cast on it if c is *char_ptr!
     2785 */
     2786/* Values for syntax param */
    24932787#define BASESYNTAX 0    /* not in quotes */
    24942788#define DQSYNTAX   1    /* in double quotes */
    24952789#define SQSYNTAX   2    /* in single quotes */
    24962790#define ARISYNTAX  3    /* in arithmetic */
    2497 
    2498 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
    2499 #define USE_SIT_FUNCTION
    2500 #endif
    2501 
    2502 #if ENABLE_ASH_MATH_SUPPORT
    2503 static const char S_I_T[][4] = {
    2504 #if ENABLE_ASH_ALIAS
    2505     { CSPCL, CIGN, CIGN, CIGN },            /* 0, PEOA */
    2506 #endif
    2507     { CSPCL, CWORD, CWORD, CWORD },         /* 1, ' ' */
    2508     { CNL, CNL, CNL, CNL },                 /* 2, \n */
    2509     { CWORD, CCTL, CCTL, CWORD },           /* 3, !*-/:=?[]~ */
    2510     { CDQUOTE, CENDQUOTE, CWORD, CWORD },   /* 4, '"' */
    2511     { CVAR, CVAR, CWORD, CVAR },            /* 5, $ */
    2512     { CSQUOTE, CWORD, CENDQUOTE, CWORD },   /* 6, "'" */
    2513     { CSPCL, CWORD, CWORD, CLP },           /* 7, ( */
    2514     { CSPCL, CWORD, CWORD, CRP },           /* 8, ) */
    2515     { CBACK, CBACK, CCTL, CBACK },          /* 9, \ */
    2516     { CBQUOTE, CBQUOTE, CWORD, CBQUOTE },   /* 10, ` */
    2517     { CENDVAR, CENDVAR, CWORD, CENDVAR },   /* 11, } */
    2518 #ifndef USE_SIT_FUNCTION
    2519     { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
    2520     { CWORD, CWORD, CWORD, CWORD },         /* 13, 0-9A-Za-z */
    2521     { CCTL, CCTL, CCTL, CCTL }              /* 14, CTLESC ... */
    2522 #endif
    2523 };
    2524 #else
    2525 static const char S_I_T[][3] = {
    2526 #if ENABLE_ASH_ALIAS
    2527     { CSPCL, CIGN, CIGN },                  /* 0, PEOA */
    2528 #endif
    2529     { CSPCL, CWORD, CWORD },                /* 1, ' ' */
    2530     { CNL, CNL, CNL },                      /* 2, \n */
    2531     { CWORD, CCTL, CCTL },                  /* 3, !*-/:=?[]~ */
    2532     { CDQUOTE, CENDQUOTE, CWORD },          /* 4, '"' */
    2533     { CVAR, CVAR, CWORD },                  /* 5, $ */
    2534     { CSQUOTE, CWORD, CENDQUOTE },          /* 6, "'" */
    2535     { CSPCL, CWORD, CWORD },                /* 7, ( */
    2536     { CSPCL, CWORD, CWORD },                /* 8, ) */
    2537     { CBACK, CBACK, CCTL },                 /* 9, \ */
    2538     { CBQUOTE, CBQUOTE, CWORD },            /* 10, ` */
    2539     { CENDVAR, CENDVAR, CWORD },            /* 11, } */
    2540 #ifndef USE_SIT_FUNCTION
    2541     { CENDFILE, CENDFILE, CENDFILE },       /* 12, PEOF */
    2542     { CWORD, CWORD, CWORD },                /* 13, 0-9A-Za-z */
    2543     { CCTL, CCTL, CCTL }                    /* 14, CTLESC ... */
    2544 #endif
    2545 };
    2546 #endif /* ASH_MATH_SUPPORT */
    2547 
    2548 #ifdef USE_SIT_FUNCTION
     2791#define PSSYNTAX   4    /* prompt. never passed to SIT() */
     2792
     2793#if USE_SIT_FUNCTION
    25492794
    25502795static int
     
    25522797{
    25532798    static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
    2554 #if ENABLE_ASH_ALIAS
    2555     static const char syntax_index_table[] ALIGN1 = {
     2799# if ENABLE_ASH_ALIAS
     2800    static const uint8_t syntax_index_table[] ALIGN1 = {
    25562801        1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
    25572802        7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
     
    25592804        11, 3                           /* "}~" */
    25602805    };
    2561 #else
    2562     static const char syntax_index_table[] ALIGN1 = {
     2806# else
     2807    static const uint8_t syntax_index_table[] ALIGN1 = {
    25632808        0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
    25642809        6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
     
    25662811        10, 2                           /* "}~" */
    25672812    };
    2568 #endif
     2813# endif
    25692814    const char *s;
    25702815    int indx;
    25712816
    2572     if (c == PEOF)          /* 2^8+2 */
     2817    if (c == PEOF)
    25732818        return CENDFILE;
    2574 #if ENABLE_ASH_ALIAS
    2575     if (c == PEOA)          /* 2^8+1 */
     2819# if ENABLE_ASH_ALIAS
     2820    if (c == PEOA)
    25762821        indx = 0;
    25772822    else
    2578 #endif
    2579 #define U_C(c) ((unsigned char)(c))
    2580 
    2581     if ((unsigned char)c >= (unsigned char)(CTLESC)
    2582      && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
    2583     ) {
    2584         return CCTL;
    2585     } else {
    2586         s = strchr(spec_symbls, c);
    2587         if (s == NULL || *s == '\0')
     2823# endif
     2824    {
     2825        /* Cast is purely for paranoia here,
     2826         * just in case someone passed signed char to us */
     2827        if ((unsigned char)c >= CTL_FIRST
     2828         && (unsigned char)c <= CTL_LAST
     2829        ) {
     2830            return CCTL;
     2831        }
     2832        s = strchrnul(spec_symbls, c);
     2833        if (*s == '\0')
    25882834            return CWORD;
    2589         indx = syntax_index_table[(s - spec_symbls)];
    2590     }
    2591     return S_I_T[indx][syntax];
     2835        indx = syntax_index_table[s - spec_symbls];
     2836    }
     2837    return (S_I_T[indx] >> (syntax*4)) & 0xf;
    25922838}
    25932839
    25942840#else   /* !USE_SIT_FUNCTION */
    25952841
    2596 #if ENABLE_ASH_ALIAS
    2597 #define CSPCL_CIGN_CIGN_CIGN                     0
    2598 #define CSPCL_CWORD_CWORD_CWORD                  1
    2599 #define CNL_CNL_CNL_CNL                          2
    2600 #define CWORD_CCTL_CCTL_CWORD                    3
    2601 #define CDQUOTE_CENDQUOTE_CWORD_CWORD            4
    2602 #define CVAR_CVAR_CWORD_CVAR                     5
    2603 #define CSQUOTE_CWORD_CENDQUOTE_CWORD            6
    2604 #define CSPCL_CWORD_CWORD_CLP                    7
    2605 #define CSPCL_CWORD_CWORD_CRP                    8
    2606 #define CBACK_CBACK_CCTL_CBACK                   9
    2607 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE           10
    2608 #define CENDVAR_CENDVAR_CWORD_CENDVAR           11
    2609 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE     12
    2610 #define CWORD_CWORD_CWORD_CWORD                 13
    2611 #define CCTL_CCTL_CCTL_CCTL                     14
    2612 #else
    2613 #define CSPCL_CWORD_CWORD_CWORD                  0
    2614 #define CNL_CNL_CNL_CNL                          1
    2615 #define CWORD_CCTL_CCTL_CWORD                    2
    2616 #define CDQUOTE_CENDQUOTE_CWORD_CWORD            3
    2617 #define CVAR_CVAR_CWORD_CVAR                     4
    2618 #define CSQUOTE_CWORD_CENDQUOTE_CWORD            5
    2619 #define CSPCL_CWORD_CWORD_CLP                    6
    2620 #define CSPCL_CWORD_CWORD_CRP                    7
    2621 #define CBACK_CBACK_CCTL_CBACK                   8
    2622 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE            9
    2623 #define CENDVAR_CENDVAR_CWORD_CENDVAR           10
    2624 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE     11
    2625 #define CWORD_CWORD_CWORD_CWORD                 12
    2626 #define CCTL_CCTL_CCTL_CCTL                     13
    2627 #endif
    2628 
    2629 static const char syntax_index_table[258] = {
     2842static const uint8_t syntax_index_table[] = {
    26302843    /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
    2631     /*   0  PEOF */      CENDFILE_CENDFILE_CENDFILE_CENDFILE,
    2632 #if ENABLE_ASH_ALIAS
    2633     /*   1  PEOA */      CSPCL_CIGN_CIGN_CIGN,
    2634 #endif
    2635     /*   2  -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
    2636     /*   3  -127 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
    2637     /*   4  -126 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
    2638     /*   5  -125 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
    2639     /*   6  -124 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
    2640     /*   7  -123 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
    2641     /*   8  -122 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
    2642     /*   9  -121 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
    2643     /*  10  -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
    2644     /*  11  -119      */ CWORD_CWORD_CWORD_CWORD,
    2645     /*  12  -118      */ CWORD_CWORD_CWORD_CWORD,
    2646     /*  13  -117      */ CWORD_CWORD_CWORD_CWORD,
    2647     /*  14  -116      */ CWORD_CWORD_CWORD_CWORD,
    2648     /*  15  -115      */ CWORD_CWORD_CWORD_CWORD,
    2649     /*  16  -114      */ CWORD_CWORD_CWORD_CWORD,
    2650     /*  17  -113      */ CWORD_CWORD_CWORD_CWORD,
    2651     /*  18  -112      */ CWORD_CWORD_CWORD_CWORD,
    2652     /*  19  -111      */ CWORD_CWORD_CWORD_CWORD,
    2653     /*  20  -110      */ CWORD_CWORD_CWORD_CWORD,
    2654     /*  21  -109      */ CWORD_CWORD_CWORD_CWORD,
    2655     /*  22  -108      */ CWORD_CWORD_CWORD_CWORD,
    2656     /*  23  -107      */ CWORD_CWORD_CWORD_CWORD,
    2657     /*  24  -106      */ CWORD_CWORD_CWORD_CWORD,
    2658     /*  25  -105      */ CWORD_CWORD_CWORD_CWORD,
    2659     /*  26  -104      */ CWORD_CWORD_CWORD_CWORD,
    2660     /*  27  -103      */ CWORD_CWORD_CWORD_CWORD,
    2661     /*  28  -102      */ CWORD_CWORD_CWORD_CWORD,
    2662     /*  29  -101      */ CWORD_CWORD_CWORD_CWORD,
    2663     /*  30  -100      */ CWORD_CWORD_CWORD_CWORD,
    2664     /*  31   -99      */ CWORD_CWORD_CWORD_CWORD,
    2665     /*  32   -98      */ CWORD_CWORD_CWORD_CWORD,
    2666     /*  33   -97      */ CWORD_CWORD_CWORD_CWORD,
    2667     /*  34   -96      */ CWORD_CWORD_CWORD_CWORD,
    2668     /*  35   -95      */ CWORD_CWORD_CWORD_CWORD,
    2669     /*  36   -94      */ CWORD_CWORD_CWORD_CWORD,
    2670     /*  37   -93      */ CWORD_CWORD_CWORD_CWORD,
    2671     /*  38   -92      */ CWORD_CWORD_CWORD_CWORD,
    2672     /*  39   -91      */ CWORD_CWORD_CWORD_CWORD,
    2673     /*  40   -90      */ CWORD_CWORD_CWORD_CWORD,
    2674     /*  41   -89      */ CWORD_CWORD_CWORD_CWORD,
    2675     /*  42   -88      */ CWORD_CWORD_CWORD_CWORD,
    2676     /*  43   -87      */ CWORD_CWORD_CWORD_CWORD,
    2677     /*  44   -86      */ CWORD_CWORD_CWORD_CWORD,
    2678     /*  45   -85      */ CWORD_CWORD_CWORD_CWORD,
    2679     /*  46   -84      */ CWORD_CWORD_CWORD_CWORD,
    2680     /*  47   -83      */ CWORD_CWORD_CWORD_CWORD,
    2681     /*  48   -82      */ CWORD_CWORD_CWORD_CWORD,
    2682     /*  49   -81      */ CWORD_CWORD_CWORD_CWORD,
    2683     /*  50   -80      */ CWORD_CWORD_CWORD_CWORD,
    2684     /*  51   -79      */ CWORD_CWORD_CWORD_CWORD,
    2685     /*  52   -78      */ CWORD_CWORD_CWORD_CWORD,
    2686     /*  53   -77      */ CWORD_CWORD_CWORD_CWORD,
    2687     /*  54   -76      */ CWORD_CWORD_CWORD_CWORD,
    2688     /*  55   -75      */ CWORD_CWORD_CWORD_CWORD,
    2689     /*  56   -74      */ CWORD_CWORD_CWORD_CWORD,
    2690     /*  57   -73      */ CWORD_CWORD_CWORD_CWORD,
    2691     /*  58   -72      */ CWORD_CWORD_CWORD_CWORD,
    2692     /*  59   -71      */ CWORD_CWORD_CWORD_CWORD,
    2693     /*  60   -70      */ CWORD_CWORD_CWORD_CWORD,
    2694     /*  61   -69      */ CWORD_CWORD_CWORD_CWORD,
    2695     /*  62   -68      */ CWORD_CWORD_CWORD_CWORD,
    2696     /*  63   -67      */ CWORD_CWORD_CWORD_CWORD,
    2697     /*  64   -66      */ CWORD_CWORD_CWORD_CWORD,
    2698     /*  65   -65      */ CWORD_CWORD_CWORD_CWORD,
    2699     /*  66   -64      */ CWORD_CWORD_CWORD_CWORD,
    2700     /*  67   -63      */ CWORD_CWORD_CWORD_CWORD,
    2701     /*  68   -62      */ CWORD_CWORD_CWORD_CWORD,
    2702     /*  69   -61      */ CWORD_CWORD_CWORD_CWORD,
    2703     /*  70   -60      */ CWORD_CWORD_CWORD_CWORD,
    2704     /*  71   -59      */ CWORD_CWORD_CWORD_CWORD,
    2705     /*  72   -58      */ CWORD_CWORD_CWORD_CWORD,
    2706     /*  73   -57      */ CWORD_CWORD_CWORD_CWORD,
    2707     /*  74   -56      */ CWORD_CWORD_CWORD_CWORD,
    2708     /*  75   -55      */ CWORD_CWORD_CWORD_CWORD,
    2709     /*  76   -54      */ CWORD_CWORD_CWORD_CWORD,
    2710     /*  77   -53      */ CWORD_CWORD_CWORD_CWORD,
    2711     /*  78   -52      */ CWORD_CWORD_CWORD_CWORD,
    2712     /*  79   -51      */ CWORD_CWORD_CWORD_CWORD,
    2713     /*  80   -50      */ CWORD_CWORD_CWORD_CWORD,
    2714     /*  81   -49      */ CWORD_CWORD_CWORD_CWORD,
    2715     /*  82   -48      */ CWORD_CWORD_CWORD_CWORD,
    2716     /*  83   -47      */ CWORD_CWORD_CWORD_CWORD,
    2717     /*  84   -46      */ CWORD_CWORD_CWORD_CWORD,
    2718     /*  85   -45      */ CWORD_CWORD_CWORD_CWORD,
    2719     /*  86   -44      */ CWORD_CWORD_CWORD_CWORD,
    2720     /*  87   -43      */ CWORD_CWORD_CWORD_CWORD,
    2721     /*  88   -42      */ CWORD_CWORD_CWORD_CWORD,
    2722     /*  89   -41      */ CWORD_CWORD_CWORD_CWORD,
    2723     /*  90   -40      */ CWORD_CWORD_CWORD_CWORD,
    2724     /*  91   -39      */ CWORD_CWORD_CWORD_CWORD,
    2725     /*  92   -38      */ CWORD_CWORD_CWORD_CWORD,
    2726     /*  93   -37      */ CWORD_CWORD_CWORD_CWORD,
    2727     /*  94   -36      */ CWORD_CWORD_CWORD_CWORD,
    2728     /*  95   -35      */ CWORD_CWORD_CWORD_CWORD,
    2729     /*  96   -34      */ CWORD_CWORD_CWORD_CWORD,
    2730     /*  97   -33      */ CWORD_CWORD_CWORD_CWORD,
    2731     /*  98   -32      */ CWORD_CWORD_CWORD_CWORD,
    2732     /*  99   -31      */ CWORD_CWORD_CWORD_CWORD,
    2733     /* 100   -30      */ CWORD_CWORD_CWORD_CWORD,
    2734     /* 101   -29      */ CWORD_CWORD_CWORD_CWORD,
    2735     /* 102   -28      */ CWORD_CWORD_CWORD_CWORD,
    2736     /* 103   -27      */ CWORD_CWORD_CWORD_CWORD,
    2737     /* 104   -26      */ CWORD_CWORD_CWORD_CWORD,
    2738     /* 105   -25      */ CWORD_CWORD_CWORD_CWORD,
    2739     /* 106   -24      */ CWORD_CWORD_CWORD_CWORD,
    2740     /* 107   -23      */ CWORD_CWORD_CWORD_CWORD,
    2741     /* 108   -22      */ CWORD_CWORD_CWORD_CWORD,
    2742     /* 109   -21      */ CWORD_CWORD_CWORD_CWORD,
    2743     /* 110   -20      */ CWORD_CWORD_CWORD_CWORD,
    2744     /* 111   -19      */ CWORD_CWORD_CWORD_CWORD,
    2745     /* 112   -18      */ CWORD_CWORD_CWORD_CWORD,
    2746     /* 113   -17      */ CWORD_CWORD_CWORD_CWORD,
    2747     /* 114   -16      */ CWORD_CWORD_CWORD_CWORD,
    2748     /* 115   -15      */ CWORD_CWORD_CWORD_CWORD,
    2749     /* 116   -14      */ CWORD_CWORD_CWORD_CWORD,
    2750     /* 117   -13      */ CWORD_CWORD_CWORD_CWORD,
    2751     /* 118   -12      */ CWORD_CWORD_CWORD_CWORD,
    2752     /* 119   -11      */ CWORD_CWORD_CWORD_CWORD,
    2753     /* 120   -10      */ CWORD_CWORD_CWORD_CWORD,
    2754     /* 121    -9      */ CWORD_CWORD_CWORD_CWORD,
    2755     /* 122    -8      */ CWORD_CWORD_CWORD_CWORD,
    2756     /* 123    -7      */ CWORD_CWORD_CWORD_CWORD,
    2757     /* 124    -6      */ CWORD_CWORD_CWORD_CWORD,
    2758     /* 125    -5      */ CWORD_CWORD_CWORD_CWORD,
    2759     /* 126    -4      */ CWORD_CWORD_CWORD_CWORD,
    2760     /* 127    -3      */ CWORD_CWORD_CWORD_CWORD,
    2761     /* 128    -2      */ CWORD_CWORD_CWORD_CWORD,
    2762     /* 129    -1      */ CWORD_CWORD_CWORD_CWORD,
    2763     /* 130     0      */ CWORD_CWORD_CWORD_CWORD,
    2764     /* 131     1      */ CWORD_CWORD_CWORD_CWORD,
    2765     /* 132     2      */ CWORD_CWORD_CWORD_CWORD,
    2766     /* 133     3      */ CWORD_CWORD_CWORD_CWORD,
    2767     /* 134     4      */ CWORD_CWORD_CWORD_CWORD,
    2768     /* 135     5      */ CWORD_CWORD_CWORD_CWORD,
    2769     /* 136     6      */ CWORD_CWORD_CWORD_CWORD,
    2770     /* 137     7      */ CWORD_CWORD_CWORD_CWORD,
    2771     /* 138     8      */ CWORD_CWORD_CWORD_CWORD,
    2772     /* 139     9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
    2773     /* 140    10 "\n" */ CNL_CNL_CNL_CNL,
    2774     /* 141    11      */ CWORD_CWORD_CWORD_CWORD,
    2775     /* 142    12      */ CWORD_CWORD_CWORD_CWORD,
    2776     /* 143    13      */ CWORD_CWORD_CWORD_CWORD,
    2777     /* 144    14      */ CWORD_CWORD_CWORD_CWORD,
    2778     /* 145    15      */ CWORD_CWORD_CWORD_CWORD,
    2779     /* 146    16      */ CWORD_CWORD_CWORD_CWORD,
    2780     /* 147    17      */ CWORD_CWORD_CWORD_CWORD,
    2781     /* 148    18      */ CWORD_CWORD_CWORD_CWORD,
    2782     /* 149    19      */ CWORD_CWORD_CWORD_CWORD,
    2783     /* 150    20      */ CWORD_CWORD_CWORD_CWORD,
    2784     /* 151    21      */ CWORD_CWORD_CWORD_CWORD,
    2785     /* 152    22      */ CWORD_CWORD_CWORD_CWORD,
    2786     /* 153    23      */ CWORD_CWORD_CWORD_CWORD,
    2787     /* 154    24      */ CWORD_CWORD_CWORD_CWORD,
    2788     /* 155    25      */ CWORD_CWORD_CWORD_CWORD,
    2789     /* 156    26      */ CWORD_CWORD_CWORD_CWORD,
    2790     /* 157    27      */ CWORD_CWORD_CWORD_CWORD,
    2791     /* 158    28      */ CWORD_CWORD_CWORD_CWORD,
    2792     /* 159    29      */ CWORD_CWORD_CWORD_CWORD,
    2793     /* 160    30      */ CWORD_CWORD_CWORD_CWORD,
    2794     /* 161    31      */ CWORD_CWORD_CWORD_CWORD,
    2795     /* 162    32  " " */ CSPCL_CWORD_CWORD_CWORD,
    2796     /* 163    33  "!" */ CWORD_CCTL_CCTL_CWORD,
    2797     /* 164    34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
    2798     /* 165    35  "#" */ CWORD_CWORD_CWORD_CWORD,
    2799     /* 166    36  "$" */ CVAR_CVAR_CWORD_CVAR,
    2800     /* 167    37  "%" */ CWORD_CWORD_CWORD_CWORD,
    2801     /* 168    38  "&" */ CSPCL_CWORD_CWORD_CWORD,
    2802     /* 169    39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
    2803     /* 170    40  "(" */ CSPCL_CWORD_CWORD_CLP,
    2804     /* 171    41  ")" */ CSPCL_CWORD_CWORD_CRP,
    2805     /* 172    42  "*" */ CWORD_CCTL_CCTL_CWORD,
    2806     /* 173    43  "+" */ CWORD_CWORD_CWORD_CWORD,
    2807     /* 174    44  "," */ CWORD_CWORD_CWORD_CWORD,
    2808     /* 175    45  "-" */ CWORD_CCTL_CCTL_CWORD,
    2809     /* 176    46  "." */ CWORD_CWORD_CWORD_CWORD,
    2810     /* 177    47  "/" */ CWORD_CCTL_CCTL_CWORD,
    2811     /* 178    48  "0" */ CWORD_CWORD_CWORD_CWORD,
    2812     /* 179    49  "1" */ CWORD_CWORD_CWORD_CWORD,
    2813     /* 180    50  "2" */ CWORD_CWORD_CWORD_CWORD,
    2814     /* 181    51  "3" */ CWORD_CWORD_CWORD_CWORD,
    2815     /* 182    52  "4" */ CWORD_CWORD_CWORD_CWORD,
    2816     /* 183    53  "5" */ CWORD_CWORD_CWORD_CWORD,
    2817     /* 184    54  "6" */ CWORD_CWORD_CWORD_CWORD,
    2818     /* 185    55  "7" */ CWORD_CWORD_CWORD_CWORD,
    2819     /* 186    56  "8" */ CWORD_CWORD_CWORD_CWORD,
    2820     /* 187    57  "9" */ CWORD_CWORD_CWORD_CWORD,
    2821     /* 188    58  ":" */ CWORD_CCTL_CCTL_CWORD,
    2822     /* 189    59  ";" */ CSPCL_CWORD_CWORD_CWORD,
    2823     /* 190    60  "<" */ CSPCL_CWORD_CWORD_CWORD,
    2824     /* 191    61  "=" */ CWORD_CCTL_CCTL_CWORD,
    2825     /* 192    62  ">" */ CSPCL_CWORD_CWORD_CWORD,
    2826     /* 193    63  "?" */ CWORD_CCTL_CCTL_CWORD,
    2827     /* 194    64  "@" */ CWORD_CWORD_CWORD_CWORD,
    2828     /* 195    65  "A" */ CWORD_CWORD_CWORD_CWORD,
    2829     /* 196    66  "B" */ CWORD_CWORD_CWORD_CWORD,
    2830     /* 197    67  "C" */ CWORD_CWORD_CWORD_CWORD,
    2831     /* 198    68  "D" */ CWORD_CWORD_CWORD_CWORD,
    2832     /* 199    69  "E" */ CWORD_CWORD_CWORD_CWORD,
    2833     /* 200    70  "F" */ CWORD_CWORD_CWORD_CWORD,
    2834     /* 201    71  "G" */ CWORD_CWORD_CWORD_CWORD,
    2835     /* 202    72  "H" */ CWORD_CWORD_CWORD_CWORD,
    2836     /* 203    73  "I" */ CWORD_CWORD_CWORD_CWORD,
    2837     /* 204    74  "J" */ CWORD_CWORD_CWORD_CWORD,
    2838     /* 205    75  "K" */ CWORD_CWORD_CWORD_CWORD,
    2839     /* 206    76  "L" */ CWORD_CWORD_CWORD_CWORD,
    2840     /* 207    77  "M" */ CWORD_CWORD_CWORD_CWORD,
    2841     /* 208    78  "N" */ CWORD_CWORD_CWORD_CWORD,
    2842     /* 209    79  "O" */ CWORD_CWORD_CWORD_CWORD,
    2843     /* 210    80  "P" */ CWORD_CWORD_CWORD_CWORD,
    2844     /* 211    81  "Q" */ CWORD_CWORD_CWORD_CWORD,
    2845     /* 212    82  "R" */ CWORD_CWORD_CWORD_CWORD,
    2846     /* 213    83  "S" */ CWORD_CWORD_CWORD_CWORD,
    2847     /* 214    84  "T" */ CWORD_CWORD_CWORD_CWORD,
    2848     /* 215    85  "U" */ CWORD_CWORD_CWORD_CWORD,
    2849     /* 216    86  "V" */ CWORD_CWORD_CWORD_CWORD,
    2850     /* 217    87  "W" */ CWORD_CWORD_CWORD_CWORD,
    2851     /* 218    88  "X" */ CWORD_CWORD_CWORD_CWORD,
    2852     /* 219    89  "Y" */ CWORD_CWORD_CWORD_CWORD,
    2853     /* 220    90  "Z" */ CWORD_CWORD_CWORD_CWORD,
    2854     /* 221    91  "[" */ CWORD_CCTL_CCTL_CWORD,
    2855     /* 222    92  "\" */ CBACK_CBACK_CCTL_CBACK,
    2856     /* 223    93  "]" */ CWORD_CCTL_CCTL_CWORD,
    2857     /* 224    94  "^" */ CWORD_CWORD_CWORD_CWORD,
    2858     /* 225    95  "_" */ CWORD_CWORD_CWORD_CWORD,
    2859     /* 226    96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
    2860     /* 227    97  "a" */ CWORD_CWORD_CWORD_CWORD,
    2861     /* 228    98  "b" */ CWORD_CWORD_CWORD_CWORD,
    2862     /* 229    99  "c" */ CWORD_CWORD_CWORD_CWORD,
    2863     /* 230   100  "d" */ CWORD_CWORD_CWORD_CWORD,
    2864     /* 231   101  "e" */ CWORD_CWORD_CWORD_CWORD,
    2865     /* 232   102  "f" */ CWORD_CWORD_CWORD_CWORD,
    2866     /* 233   103  "g" */ CWORD_CWORD_CWORD_CWORD,
    2867     /* 234   104  "h" */ CWORD_CWORD_CWORD_CWORD,
    2868     /* 235   105  "i" */ CWORD_CWORD_CWORD_CWORD,
    2869     /* 236   106  "j" */ CWORD_CWORD_CWORD_CWORD,
    2870     /* 237   107  "k" */ CWORD_CWORD_CWORD_CWORD,
    2871     /* 238   108  "l" */ CWORD_CWORD_CWORD_CWORD,
    2872     /* 239   109  "m" */ CWORD_CWORD_CWORD_CWORD,
    2873     /* 240   110  "n" */ CWORD_CWORD_CWORD_CWORD,
    2874     /* 241   111  "o" */ CWORD_CWORD_CWORD_CWORD,
    2875     /* 242   112  "p" */ CWORD_CWORD_CWORD_CWORD,
    2876     /* 243   113  "q" */ CWORD_CWORD_CWORD_CWORD,
    2877     /* 244   114  "r" */ CWORD_CWORD_CWORD_CWORD,
    2878     /* 245   115  "s" */ CWORD_CWORD_CWORD_CWORD,
    2879     /* 246   116  "t" */ CWORD_CWORD_CWORD_CWORD,
    2880     /* 247   117  "u" */ CWORD_CWORD_CWORD_CWORD,
    2881     /* 248   118  "v" */ CWORD_CWORD_CWORD_CWORD,
    2882     /* 249   119  "w" */ CWORD_CWORD_CWORD_CWORD,
    2883     /* 250   120  "x" */ CWORD_CWORD_CWORD_CWORD,
    2884     /* 251   121  "y" */ CWORD_CWORD_CWORD_CWORD,
    2885     /* 252   122  "z" */ CWORD_CWORD_CWORD_CWORD,
    2886     /* 253   123  "{" */ CWORD_CWORD_CWORD_CWORD,
    2887     /* 254   124  "|" */ CSPCL_CWORD_CWORD_CWORD,
    2888     /* 255   125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
    2889     /* 256   126  "~" */ CWORD_CCTL_CCTL_CWORD,
    2890     /* 257   127      */ CWORD_CWORD_CWORD_CWORD,
     2844    /*   0      */ CWORD_CWORD_CWORD_CWORD,
     2845    /*   1      */ CWORD_CWORD_CWORD_CWORD,
     2846    /*   2      */ CWORD_CWORD_CWORD_CWORD,
     2847    /*   3      */ CWORD_CWORD_CWORD_CWORD,
     2848    /*   4      */ CWORD_CWORD_CWORD_CWORD,
     2849    /*   5      */ CWORD_CWORD_CWORD_CWORD,
     2850    /*   6      */ CWORD_CWORD_CWORD_CWORD,
     2851    /*   7      */ CWORD_CWORD_CWORD_CWORD,
     2852    /*   8      */ CWORD_CWORD_CWORD_CWORD,
     2853    /*   9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
     2854    /*  10 "\n" */ CNL_CNL_CNL_CNL,
     2855    /*  11      */ CWORD_CWORD_CWORD_CWORD,
     2856    /*  12      */ CWORD_CWORD_CWORD_CWORD,
     2857    /*  13      */ CWORD_CWORD_CWORD_CWORD,
     2858    /*  14      */ CWORD_CWORD_CWORD_CWORD,
     2859    /*  15      */ CWORD_CWORD_CWORD_CWORD,
     2860    /*  16      */ CWORD_CWORD_CWORD_CWORD,
     2861    /*  17      */ CWORD_CWORD_CWORD_CWORD,
     2862    /*  18      */ CWORD_CWORD_CWORD_CWORD,
     2863    /*  19      */ CWORD_CWORD_CWORD_CWORD,
     2864    /*  20      */ CWORD_CWORD_CWORD_CWORD,
     2865    /*  21      */ CWORD_CWORD_CWORD_CWORD,
     2866    /*  22      */ CWORD_CWORD_CWORD_CWORD,
     2867    /*  23      */ CWORD_CWORD_CWORD_CWORD,
     2868    /*  24      */ CWORD_CWORD_CWORD_CWORD,
     2869    /*  25      */ CWORD_CWORD_CWORD_CWORD,
     2870    /*  26      */ CWORD_CWORD_CWORD_CWORD,
     2871    /*  27      */ CWORD_CWORD_CWORD_CWORD,
     2872    /*  28      */ CWORD_CWORD_CWORD_CWORD,
     2873    /*  29      */ CWORD_CWORD_CWORD_CWORD,
     2874    /*  30      */ CWORD_CWORD_CWORD_CWORD,
     2875    /*  31      */ CWORD_CWORD_CWORD_CWORD,
     2876    /*  32  " " */ CSPCL_CWORD_CWORD_CWORD,
     2877    /*  33  "!" */ CWORD_CCTL_CCTL_CWORD,
     2878    /*  34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
     2879    /*  35  "#" */ CWORD_CWORD_CWORD_CWORD,
     2880    /*  36  "$" */ CVAR_CVAR_CWORD_CVAR,
     2881    /*  37  "%" */ CWORD_CWORD_CWORD_CWORD,
     2882    /*  38  "&" */ CSPCL_CWORD_CWORD_CWORD,
     2883    /*  39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
     2884    /*  40  "(" */ CSPCL_CWORD_CWORD_CLP,
     2885    /*  41  ")" */ CSPCL_CWORD_CWORD_CRP,
     2886    /*  42  "*" */ CWORD_CCTL_CCTL_CWORD,
     2887    /*  43  "+" */ CWORD_CWORD_CWORD_CWORD,
     2888    /*  44  "," */ CWORD_CWORD_CWORD_CWORD,
     2889    /*  45  "-" */ CWORD_CCTL_CCTL_CWORD,
     2890    /*  46  "." */ CWORD_CWORD_CWORD_CWORD,
     2891    /*  47  "/" */ CWORD_CCTL_CCTL_CWORD,
     2892    /*  48  "0" */ CWORD_CWORD_CWORD_CWORD,
     2893    /*  49  "1" */ CWORD_CWORD_CWORD_CWORD,
     2894    /*  50  "2" */ CWORD_CWORD_CWORD_CWORD,
     2895    /*  51  "3" */ CWORD_CWORD_CWORD_CWORD,
     2896    /*  52  "4" */ CWORD_CWORD_CWORD_CWORD,
     2897    /*  53  "5" */ CWORD_CWORD_CWORD_CWORD,
     2898    /*  54  "6" */ CWORD_CWORD_CWORD_CWORD,
     2899    /*  55  "7" */ CWORD_CWORD_CWORD_CWORD,
     2900    /*  56  "8" */ CWORD_CWORD_CWORD_CWORD,
     2901    /*  57  "9" */ CWORD_CWORD_CWORD_CWORD,
     2902    /*  58  ":" */ CWORD_CCTL_CCTL_CWORD,
     2903    /*  59  ";" */ CSPCL_CWORD_CWORD_CWORD,
     2904    /*  60  "<" */ CSPCL_CWORD_CWORD_CWORD,
     2905    /*  61  "=" */ CWORD_CCTL_CCTL_CWORD,
     2906    /*  62  ">" */ CSPCL_CWORD_CWORD_CWORD,
     2907    /*  63  "?" */ CWORD_CCTL_CCTL_CWORD,
     2908    /*  64  "@" */ CWORD_CWORD_CWORD_CWORD,
     2909    /*  65  "A" */ CWORD_CWORD_CWORD_CWORD,
     2910    /*  66  "B" */ CWORD_CWORD_CWORD_CWORD,
     2911    /*  67  "C" */ CWORD_CWORD_CWORD_CWORD,
     2912    /*  68  "D" */ CWORD_CWORD_CWORD_CWORD,
     2913    /*  69  "E" */ CWORD_CWORD_CWORD_CWORD,
     2914    /*  70  "F" */ CWORD_CWORD_CWORD_CWORD,
     2915    /*  71  "G" */ CWORD_CWORD_CWORD_CWORD,
     2916    /*  72  "H" */ CWORD_CWORD_CWORD_CWORD,
     2917    /*  73  "I" */ CWORD_CWORD_CWORD_CWORD,
     2918    /*  74  "J" */ CWORD_CWORD_CWORD_CWORD,
     2919    /*  75  "K" */ CWORD_CWORD_CWORD_CWORD,
     2920    /*  76  "L" */ CWORD_CWORD_CWORD_CWORD,
     2921    /*  77  "M" */ CWORD_CWORD_CWORD_CWORD,
     2922    /*  78  "N" */ CWORD_CWORD_CWORD_CWORD,
     2923    /*  79  "O" */ CWORD_CWORD_CWORD_CWORD,
     2924    /*  80  "P" */ CWORD_CWORD_CWORD_CWORD,
     2925    /*  81  "Q" */ CWORD_CWORD_CWORD_CWORD,
     2926    /*  82  "R" */ CWORD_CWORD_CWORD_CWORD,
     2927    /*  83  "S" */ CWORD_CWORD_CWORD_CWORD,
     2928    /*  84  "T" */ CWORD_CWORD_CWORD_CWORD,
     2929    /*  85  "U" */ CWORD_CWORD_CWORD_CWORD,
     2930    /*  86  "V" */ CWORD_CWORD_CWORD_CWORD,
     2931    /*  87  "W" */ CWORD_CWORD_CWORD_CWORD,
     2932    /*  88  "X" */ CWORD_CWORD_CWORD_CWORD,
     2933    /*  89  "Y" */ CWORD_CWORD_CWORD_CWORD,
     2934    /*  90  "Z" */ CWORD_CWORD_CWORD_CWORD,
     2935    /*  91  "[" */ CWORD_CCTL_CCTL_CWORD,
     2936    /*  92  "\" */ CBACK_CBACK_CCTL_CBACK,
     2937    /*  93  "]" */ CWORD_CCTL_CCTL_CWORD,
     2938    /*  94  "^" */ CWORD_CWORD_CWORD_CWORD,
     2939    /*  95  "_" */ CWORD_CWORD_CWORD_CWORD,
     2940    /*  96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
     2941    /*  97  "a" */ CWORD_CWORD_CWORD_CWORD,
     2942    /*  98  "b" */ CWORD_CWORD_CWORD_CWORD,
     2943    /*  99  "c" */ CWORD_CWORD_CWORD_CWORD,
     2944    /* 100  "d" */ CWORD_CWORD_CWORD_CWORD,
     2945    /* 101  "e" */ CWORD_CWORD_CWORD_CWORD,
     2946    /* 102  "f" */ CWORD_CWORD_CWORD_CWORD,
     2947    /* 103  "g" */ CWORD_CWORD_CWORD_CWORD,
     2948    /* 104  "h" */ CWORD_CWORD_CWORD_CWORD,
     2949    /* 105  "i" */ CWORD_CWORD_CWORD_CWORD,
     2950    /* 106  "j" */ CWORD_CWORD_CWORD_CWORD,
     2951    /* 107  "k" */ CWORD_CWORD_CWORD_CWORD,
     2952    /* 108  "l" */ CWORD_CWORD_CWORD_CWORD,
     2953    /* 109  "m" */ CWORD_CWORD_CWORD_CWORD,
     2954    /* 110  "n" */ CWORD_CWORD_CWORD_CWORD,
     2955    /* 111  "o" */ CWORD_CWORD_CWORD_CWORD,
     2956    /* 112  "p" */ CWORD_CWORD_CWORD_CWORD,
     2957    /* 113  "q" */ CWORD_CWORD_CWORD_CWORD,
     2958    /* 114  "r" */ CWORD_CWORD_CWORD_CWORD,
     2959    /* 115  "s" */ CWORD_CWORD_CWORD_CWORD,
     2960    /* 116  "t" */ CWORD_CWORD_CWORD_CWORD,
     2961    /* 117  "u" */ CWORD_CWORD_CWORD_CWORD,
     2962    /* 118  "v" */ CWORD_CWORD_CWORD_CWORD,
     2963    /* 119  "w" */ CWORD_CWORD_CWORD_CWORD,
     2964    /* 120  "x" */ CWORD_CWORD_CWORD_CWORD,
     2965    /* 121  "y" */ CWORD_CWORD_CWORD_CWORD,
     2966    /* 122  "z" */ CWORD_CWORD_CWORD_CWORD,
     2967    /* 123  "{" */ CWORD_CWORD_CWORD_CWORD,
     2968    /* 124  "|" */ CSPCL_CWORD_CWORD_CWORD,
     2969    /* 125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
     2970    /* 126  "~" */ CWORD_CCTL_CCTL_CWORD,
     2971    /* 127  del */ CWORD_CWORD_CWORD_CWORD,
     2972    /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
     2973    /* 129 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
     2974    /* 130 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
     2975    /* 131 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
     2976    /* 132 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
     2977    /* 133 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
     2978    /* 134 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
     2979    /* 135 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
     2980    /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
     2981    /* 137      */ CWORD_CWORD_CWORD_CWORD,
     2982    /* 138      */ CWORD_CWORD_CWORD_CWORD,
     2983    /* 139      */ CWORD_CWORD_CWORD_CWORD,
     2984    /* 140      */ CWORD_CWORD_CWORD_CWORD,
     2985    /* 141      */ CWORD_CWORD_CWORD_CWORD,
     2986    /* 142      */ CWORD_CWORD_CWORD_CWORD,
     2987    /* 143      */ CWORD_CWORD_CWORD_CWORD,
     2988    /* 144      */ CWORD_CWORD_CWORD_CWORD,
     2989    /* 145      */ CWORD_CWORD_CWORD_CWORD,
     2990    /* 146      */ CWORD_CWORD_CWORD_CWORD,
     2991    /* 147      */ CWORD_CWORD_CWORD_CWORD,
     2992    /* 148      */ CWORD_CWORD_CWORD_CWORD,
     2993    /* 149      */ CWORD_CWORD_CWORD_CWORD,
     2994    /* 150      */ CWORD_CWORD_CWORD_CWORD,
     2995    /* 151      */ CWORD_CWORD_CWORD_CWORD,
     2996    /* 152      */ CWORD_CWORD_CWORD_CWORD,
     2997    /* 153      */ CWORD_CWORD_CWORD_CWORD,
     2998    /* 154      */ CWORD_CWORD_CWORD_CWORD,
     2999    /* 155      */ CWORD_CWORD_CWORD_CWORD,
     3000    /* 156      */ CWORD_CWORD_CWORD_CWORD,
     3001    /* 157      */ CWORD_CWORD_CWORD_CWORD,
     3002    /* 158      */ CWORD_CWORD_CWORD_CWORD,
     3003    /* 159      */ CWORD_CWORD_CWORD_CWORD,
     3004    /* 160      */ CWORD_CWORD_CWORD_CWORD,
     3005    /* 161      */ CWORD_CWORD_CWORD_CWORD,
     3006    /* 162      */ CWORD_CWORD_CWORD_CWORD,
     3007    /* 163      */ CWORD_CWORD_CWORD_CWORD,
     3008    /* 164      */ CWORD_CWORD_CWORD_CWORD,
     3009    /* 165      */ CWORD_CWORD_CWORD_CWORD,
     3010    /* 166      */ CWORD_CWORD_CWORD_CWORD,
     3011    /* 167      */ CWORD_CWORD_CWORD_CWORD,
     3012    /* 168      */ CWORD_CWORD_CWORD_CWORD,
     3013    /* 169      */ CWORD_CWORD_CWORD_CWORD,
     3014    /* 170      */ CWORD_CWORD_CWORD_CWORD,
     3015    /* 171      */ CWORD_CWORD_CWORD_CWORD,
     3016    /* 172      */ CWORD_CWORD_CWORD_CWORD,
     3017    /* 173      */ CWORD_CWORD_CWORD_CWORD,
     3018    /* 174      */ CWORD_CWORD_CWORD_CWORD,
     3019    /* 175      */ CWORD_CWORD_CWORD_CWORD,
     3020    /* 176      */ CWORD_CWORD_CWORD_CWORD,
     3021    /* 177      */ CWORD_CWORD_CWORD_CWORD,
     3022    /* 178      */ CWORD_CWORD_CWORD_CWORD,
     3023    /* 179      */ CWORD_CWORD_CWORD_CWORD,
     3024    /* 180      */ CWORD_CWORD_CWORD_CWORD,
     3025    /* 181      */ CWORD_CWORD_CWORD_CWORD,
     3026    /* 182      */ CWORD_CWORD_CWORD_CWORD,
     3027    /* 183      */ CWORD_CWORD_CWORD_CWORD,
     3028    /* 184      */ CWORD_CWORD_CWORD_CWORD,
     3029    /* 185      */ CWORD_CWORD_CWORD_CWORD,
     3030    /* 186      */ CWORD_CWORD_CWORD_CWORD,
     3031    /* 187      */ CWORD_CWORD_CWORD_CWORD,
     3032    /* 188      */ CWORD_CWORD_CWORD_CWORD,
     3033    /* 189      */ CWORD_CWORD_CWORD_CWORD,
     3034    /* 190      */ CWORD_CWORD_CWORD_CWORD,
     3035    /* 191      */ CWORD_CWORD_CWORD_CWORD,
     3036    /* 192      */ CWORD_CWORD_CWORD_CWORD,
     3037    /* 193      */ CWORD_CWORD_CWORD_CWORD,
     3038    /* 194      */ CWORD_CWORD_CWORD_CWORD,
     3039    /* 195      */ CWORD_CWORD_CWORD_CWORD,
     3040    /* 196      */ CWORD_CWORD_CWORD_CWORD,
     3041    /* 197      */ CWORD_CWORD_CWORD_CWORD,
     3042    /* 198      */ CWORD_CWORD_CWORD_CWORD,
     3043    /* 199      */ CWORD_CWORD_CWORD_CWORD,
     3044    /* 200      */ CWORD_CWORD_CWORD_CWORD,
     3045    /* 201      */ CWORD_CWORD_CWORD_CWORD,
     3046    /* 202      */ CWORD_CWORD_CWORD_CWORD,
     3047    /* 203      */ CWORD_CWORD_CWORD_CWORD,
     3048    /* 204      */ CWORD_CWORD_CWORD_CWORD,
     3049    /* 205      */ CWORD_CWORD_CWORD_CWORD,
     3050    /* 206      */ CWORD_CWORD_CWORD_CWORD,
     3051    /* 207      */ CWORD_CWORD_CWORD_CWORD,
     3052    /* 208      */ CWORD_CWORD_CWORD_CWORD,
     3053    /* 209      */ CWORD_CWORD_CWORD_CWORD,
     3054    /* 210      */ CWORD_CWORD_CWORD_CWORD,
     3055    /* 211      */ CWORD_CWORD_CWORD_CWORD,
     3056    /* 212      */ CWORD_CWORD_CWORD_CWORD,
     3057    /* 213      */ CWORD_CWORD_CWORD_CWORD,
     3058    /* 214      */ CWORD_CWORD_CWORD_CWORD,
     3059    /* 215      */ CWORD_CWORD_CWORD_CWORD,
     3060    /* 216      */ CWORD_CWORD_CWORD_CWORD,
     3061    /* 217      */ CWORD_CWORD_CWORD_CWORD,
     3062    /* 218      */ CWORD_CWORD_CWORD_CWORD,
     3063    /* 219      */ CWORD_CWORD_CWORD_CWORD,
     3064    /* 220      */ CWORD_CWORD_CWORD_CWORD,
     3065    /* 221      */ CWORD_CWORD_CWORD_CWORD,
     3066    /* 222      */ CWORD_CWORD_CWORD_CWORD,
     3067    /* 223      */ CWORD_CWORD_CWORD_CWORD,
     3068    /* 224      */ CWORD_CWORD_CWORD_CWORD,
     3069    /* 225      */ CWORD_CWORD_CWORD_CWORD,
     3070    /* 226      */ CWORD_CWORD_CWORD_CWORD,
     3071    /* 227      */ CWORD_CWORD_CWORD_CWORD,
     3072    /* 228      */ CWORD_CWORD_CWORD_CWORD,
     3073    /* 229      */ CWORD_CWORD_CWORD_CWORD,
     3074    /* 230      */ CWORD_CWORD_CWORD_CWORD,
     3075    /* 231      */ CWORD_CWORD_CWORD_CWORD,
     3076    /* 232      */ CWORD_CWORD_CWORD_CWORD,
     3077    /* 233      */ CWORD_CWORD_CWORD_CWORD,
     3078    /* 234      */ CWORD_CWORD_CWORD_CWORD,
     3079    /* 235      */ CWORD_CWORD_CWORD_CWORD,
     3080    /* 236      */ CWORD_CWORD_CWORD_CWORD,
     3081    /* 237      */ CWORD_CWORD_CWORD_CWORD,
     3082    /* 238      */ CWORD_CWORD_CWORD_CWORD,
     3083    /* 239      */ CWORD_CWORD_CWORD_CWORD,
     3084    /* 230      */ CWORD_CWORD_CWORD_CWORD,
     3085    /* 241      */ CWORD_CWORD_CWORD_CWORD,
     3086    /* 242      */ CWORD_CWORD_CWORD_CWORD,
     3087    /* 243      */ CWORD_CWORD_CWORD_CWORD,
     3088    /* 244      */ CWORD_CWORD_CWORD_CWORD,
     3089    /* 245      */ CWORD_CWORD_CWORD_CWORD,
     3090    /* 246      */ CWORD_CWORD_CWORD_CWORD,
     3091    /* 247      */ CWORD_CWORD_CWORD_CWORD,
     3092    /* 248      */ CWORD_CWORD_CWORD_CWORD,
     3093    /* 249      */ CWORD_CWORD_CWORD_CWORD,
     3094    /* 250      */ CWORD_CWORD_CWORD_CWORD,
     3095    /* 251      */ CWORD_CWORD_CWORD_CWORD,
     3096    /* 252      */ CWORD_CWORD_CWORD_CWORD,
     3097    /* 253      */ CWORD_CWORD_CWORD_CWORD,
     3098    /* 254      */ CWORD_CWORD_CWORD_CWORD,
     3099    /* 255      */ CWORD_CWORD_CWORD_CWORD,
     3100    /* PEOF */     CENDFILE_CENDFILE_CENDFILE_CENDFILE,
     3101# if ENABLE_ASH_ALIAS
     3102    /* PEOA */     CSPCL_CIGN_CIGN_CIGN,
     3103# endif
    28913104};
    28923105
    2893 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
    2894 
    2895 #endif  /* USE_SIT_FUNCTION */
     3106# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
     3107
     3108#endif  /* !USE_SIT_FUNCTION */
    28963109
    28973110
     
    29023115#define ALIASINUSE 1
    29033116#define ALIASDEAD  2
    2904 
    2905 #define ATABSIZE 39
    29063117
    29073118struct alias {
     
    29123123};
    29133124
    2914 static struct alias *atab[ATABSIZE];
     3125
     3126static struct alias **atab; // [ATABSIZE];
     3127#define INIT_G_alias() do { \
     3128    atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
     3129} while (0)
     3130
    29153131
    29163132static struct alias **
     
    29833199    } else {
    29843200        /* not found */
    2985         ap = ckmalloc(sizeof(struct alias));
     3201        ap = ckzalloc(sizeof(struct alias));
    29863202        ap->name = ckstrdup(name);
    29873203        ap->val = ckstrdup(val);
    2988         ap->flag = 0;
    2989         ap->next = 0;
     3204        /*ap->flag = 0; - ckzalloc did it */
     3205        /*ap->next = NULL;*/
    29903206        *app = ap;
    29913207    }
     
    30383254 * TODO - sort output
    30393255 */
    3040 static int
    3041 aliascmd(int argc, char **argv)
     3256static int FAST_FUNC
     3257aliascmd(int argc UNUSED_PARAM, char **argv)
    30423258{
    30433259    char *n, *v;
     
    30453261    struct alias *ap;
    30463262
    3047     if (argc == 1) {
     3263    if (!argv[1]) {
    30483264        int i;
    30493265
    3050         for (i = 0; i < ATABSIZE; i++)
     3266        for (i = 0; i < ATABSIZE; i++) {
    30513267            for (ap = atab[i]; ap; ap = ap->next) {
    30523268                printalias(ap);
    30533269            }
     3270        }
    30543271        return 0;
    30553272    }
     
    30723289}
    30733290
    3074 static int
    3075 unaliascmd(int argc, char **argv)
     3291static int FAST_FUNC
     3292unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    30763293{
    30773294    int i;
     
    30993316
    31003317/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
    3101 #define FORK_FG 0
    3102 #define FORK_BG 1
     3318#define FORK_FG    0
     3319#define FORK_BG    1
    31033320#define FORK_NOJOB 2
    31043321
    31053322/* mode flags for showjob(s) */
    3106 #define SHOW_PGID       0x01    /* only show pgid - for jobs -p */
    3107 #define SHOW_PID        0x04    /* include process pid */
    3108 #define SHOW_CHANGED    0x08    /* only jobs whose state has changed */
     3323#define SHOW_ONLY_PGID  0x01    /* show only pgid (jobs -p) */
     3324#define SHOW_PIDS       0x02    /* show individual pids, not just one line per job */
     3325#define SHOW_CHANGED    0x04    /* only jobs whose state has changed */
    31093326
    31103327/*
     
    31143331 * array of pids.
    31153332 */
    3116 
    31173333struct procstat {
    3118     pid_t   pid;            /* process id */
    3119     int     status;         /* last process status from wait() */
    3120     char    *cmd;           /* text of command being run */
     3334    pid_t   ps_pid;         /* process id */
     3335    int     ps_status;      /* last process status from wait() */
     3336    char    *ps_cmd;        /* text of command being run */
    31213337};
    31223338
     
    31433359};
    31443360
    3145 static pid_t backgndpid;        /* pid of last background process */
    3146 static smallint job_warning;    /* user was warned about stopped jobs (can be 2, 1 or 0). */
    3147 
    3148 static struct job *makejob(union node *, int);
     3361static struct job *makejob(/*union node *,*/ int);
    31493362static int forkshell(struct job *, union node *, int);
    31503363static int waitforjob(struct job *);
    31513364
    31523365#if !JOBS
    3153 enum { jobctl = 0 };
     3366enum { doing_jobctl = 0 };
    31543367#define setjobctl(on) do {} while (0)
    31553368#else
    3156 static smallint jobctl;              /* true if doing job control */
     3369static smallint doing_jobctl; //references:8
    31573370static void setjobctl(int);
    31583371#endif
     3372
     3373/*
     3374 * Ignore a signal.
     3375 */
     3376static void
     3377ignoresig(int signo)
     3378{
     3379    /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
     3380    if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
     3381        /* No, need to do it */
     3382        signal(signo, SIG_IGN);
     3383    }
     3384    sigmode[signo - 1] = S_HARD_IGN;
     3385}
     3386
     3387/*
     3388 * Only one usage site - in setsignal()
     3389 */
     3390static void
     3391signal_handler(int signo)
     3392{
     3393    gotsig[signo - 1] = 1;
     3394
     3395    if (signo == SIGINT && !trap[SIGINT]) {
     3396        if (!suppress_int) {
     3397            pending_sig = 0;
     3398            raise_interrupt(); /* does not return */
     3399        }
     3400        pending_int = 1;
     3401    } else {
     3402        pending_sig = signo;
     3403    }
     3404}
    31593405
    31603406/*
     
    31653411setsignal(int signo)
    31663412{
    3167     int action;
    3168     char *t, tsig;
     3413    char *t;
     3414    char cur_act, new_act;
    31693415    struct sigaction act;
    31703416
    31713417    t = trap[signo];
    3172     if (t == NULL)
    3173         action = S_DFL;
    3174     else if (*t != '\0')
    3175         action = S_CATCH;
    3176     else
    3177         action = S_IGN;
    3178     if (rootshell && action == S_DFL) {
     3418    new_act = S_DFL;
     3419    if (t != NULL) { /* trap for this sig is set */
     3420        new_act = S_CATCH;
     3421        if (t[0] == '\0') /* trap is "": ignore this sig */
     3422            new_act = S_IGN;
     3423    }
     3424
     3425    if (rootshell && new_act == S_DFL) {
    31793426        switch (signo) {
    31803427        case SIGINT:
    31813428            if (iflag || minusc || sflag == 0)
    3182                 action = S_CATCH;
     3429                new_act = S_CATCH;
    31833430            break;
    31843431        case SIGQUIT:
     
    31873434                break;
    31883435#endif
    3189             /* FALLTHROUGH */
     3436            /* man bash:
     3437             * "In all cases, bash ignores SIGQUIT. Non-builtin
     3438             * commands run by bash have signal handlers
     3439             * set to the values inherited by the shell
     3440             * from its parent". */
     3441            new_act = S_IGN;
     3442            break;
    31903443        case SIGTERM:
    31913444            if (iflag)
    3192                 action = S_IGN;
     3445                new_act = S_IGN;
    31933446            break;
    31943447#if JOBS
     
    31963449        case SIGTTOU:
    31973450            if (mflag)
    3198                 action = S_IGN;
     3451                new_act = S_IGN;
    31993452            break;
    32003453#endif
    32013454        }
    32023455    }
     3456//TODO: if !rootshell, we reset SIGQUIT to DFL,
     3457//whereas we have to restore it to what shell got on entry
     3458//from the parent. See comment above
    32033459
    32043460    t = &sigmode[signo - 1];
    3205     tsig = *t;
    3206     if (tsig == 0) {
    3207         /*
    3208          * current setting unknown
    3209          */
    3210         if (sigaction(signo, 0, &act) == -1) {
    3211             /*
    3212              * Pretend it worked; maybe we should give a warning
    3213              * here, but other shells don't. We don't alter
    3214              * sigmode, so that we retry every time.
    3215              */
     3461    cur_act = *t;
     3462    if (cur_act == 0) {
     3463        /* current setting is not yet known */
     3464        if (sigaction(signo, NULL, &act)) {
     3465            /* pretend it worked; maybe we should give a warning,
     3466             * but other shells don't. We don't alter sigmode,
     3467             * so we retry every time.
     3468             * btw, in Linux it never fails. --vda */
    32163469            return;
    32173470        }
    32183471        if (act.sa_handler == SIG_IGN) {
     3472            cur_act = S_HARD_IGN;
    32193473            if (mflag
    32203474             && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
    32213475            ) {
    3222                 tsig = S_IGN;   /* don't hard ignore these */
    3223             } else
    3224                 tsig = S_HARD_IGN;
    3225         } else {
    3226             tsig = S_RESET; /* force to be set */
    3227         }
    3228     }
    3229     if (tsig == S_HARD_IGN || tsig == action)
     3476                cur_act = S_IGN;   /* don't hard ignore these */
     3477            }
     3478        }
     3479    }
     3480    if (cur_act == S_HARD_IGN || cur_act == new_act)
    32303481        return;
    3231     switch (action) {
     3482
     3483    act.sa_handler = SIG_DFL;
     3484    switch (new_act) {
    32323485    case S_CATCH:
    3233         act.sa_handler = onsig;
     3486        act.sa_handler = signal_handler;
     3487        act.sa_flags = 0; /* matters only if !DFL and !IGN */
     3488        sigfillset(&act.sa_mask); /* ditto */
    32343489        break;
    32353490    case S_IGN:
    32363491        act.sa_handler = SIG_IGN;
    32373492        break;
    3238     default:
    3239         act.sa_handler = SIG_DFL;
    3240     }
    3241     *t = action;
    3242     act.sa_flags = 0;
    3243     sigfillset(&act.sa_mask);
    3244     sigaction(signo, &act, 0);
     3493    }
     3494    sigaction_set(signo, &act);
     3495
     3496    *t = new_act;
    32453497}
    32463498
     
    32513503
    32523504/* mode flags for dowait */
    3253 #define DOWAIT_NORMAL 0
    3254 #define DOWAIT_BLOCK 1
     3505#define DOWAIT_NONBLOCK WNOHANG
     3506#define DOWAIT_BLOCK    0
    32553507
    32563508#if JOBS
    32573509/* pgrp of shell on invocation */
    3258 static int initialpgrp;
    3259 static int ttyfd = -1;
     3510static int initialpgrp; //references:2
     3511static int ttyfd = -1; //5
    32603512#endif
    32613513/* array of jobs */
    3262 static struct job *jobtab;
     3514static struct job *jobtab; //5
    32633515/* size of array */
    3264 static unsigned njobs;
     3516static unsigned njobs; //4
    32653517/* current job */
    3266 static struct job *curjob;
     3518static struct job *curjob; //lots
    32673519/* number of presumed living untracked jobs */
    3268 static int jobless;
     3520static int jobless; //4
    32693521
    32703522static void
     
    33273579 * Convert a job name to a job structure.
    33283580 */
     3581#if !JOBS
     3582#define getjob(name, getctl) getjob(name)
     3583#endif
    33293584static struct job *
    33303585getjob(const char *name, int getctl)
     
    33323587    struct job *jp;
    33333588    struct job *found;
    3334     const char *err_msg = "No such job: %s";
     3589    const char *err_msg = "%s: no such job";
    33353590    unsigned num;
    33363591    int c;
     
    33833638    }
    33843639
    3385     found = 0;
    3386     while (1) {
    3387         if (!jp)
    3388             goto err;
    3389         if (match(jp->ps[0].cmd, p)) {
     3640    found = NULL;
     3641    while (jp) {
     3642        if (match(jp->ps[0].ps_cmd, p)) {
    33903643            if (found)
    33913644                goto err;
     
    33953648        jp = jp->prev_job;
    33963649    }
     3650    if (!found)
     3651        goto err;
     3652    jp = found;
    33973653
    33983654 gotit:
     
    34183674    INT_OFF;
    34193675    for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
    3420         if (ps->cmd != nullstr)
    3421             free(ps->cmd);
     3676        if (ps->ps_cmd != nullstr)
     3677            free(ps->ps_cmd);
    34223678    }
    34233679    if (jp->ps != &jp->ps0)
     
    34333689{
    34343690    if (tcsetpgrp(fd, pgrp))
    3435         ash_msg_and_raise_error("cannot set tty process group (%m)");
     3691        ash_msg_and_raise_error("can't set tty process group (%m)");
    34363692}
    34373693
     
    34513707    int pgrp;
    34523708
    3453     if (on == jobctl || rootshell == 0)
     3709    if (on == doing_jobctl || rootshell == 0)
    34543710        return;
    34553711    if (on) {
     
    34613717     * Obviously, a workaround for bugs when someone
    34623718     * failed to provide a controlling tty to bash! :) */
    3463             fd += 3;
    3464             while (!isatty(fd) && --fd >= 0)
    3465                 ;
     3719            fd = 2;
     3720            while (!isatty(fd))
     3721                if (--fd < 0)
     3722                    goto out;
    34663723        }
    34673724        fd = fcntl(fd, F_DUPFD, 10);
    3468         close(ofd);
     3725        if (ofd >= 0)
     3726            close(ofd);
    34693727        if (fd < 0)
    34703728            goto out;
    3471         fcntl(fd, F_SETFD, FD_CLOEXEC);
     3729        /* fd is a tty at this point */
     3730        close_on_exec_on(fd);
    34723731        do { /* while we are in the background */
    34733732            pgrp = tcgetpgrp(fd);
     
    34953754        pgrp = initialpgrp;
    34963755        /* was xtcsetpgrp, but this can make exiting ash
    3497          * with pty already deleted loop forever */
     3756         * loop forever if pty is already deleted */
    34983757        tcsetpgrp(fd, pgrp);
    34993758        setpgid(0, pgrp);
     
    35023761        setsignal(SIGTTIN);
    35033762 close:
    3504         close(fd);
     3763        if (fd >= 0)
     3764            close(fd);
    35053765        fd = -1;
    35063766    }
    35073767    ttyfd = fd;
    3508     jobctl = on;
    3509 }
    3510 
    3511 static int
     3768    doing_jobctl = on;
     3769}
     3770
     3771static int FAST_FUNC
    35123772killcmd(int argc, char **argv)
    35133773{
     3774    int i = 1;
    35143775    if (argv[1] && strcmp(argv[1], "-l") != 0) {
    3515         int i = 1;
    35163776        do {
    35173777            if (argv[i][0] == '%') {
    35183778                struct job *jp = getjob(argv[i], 0);
    3519                 unsigned pid = jp->ps[0].pid;
     3779                unsigned pid = jp->ps[0].ps_pid;
    35203780                /* Enough space for ' -NNN<nul>' */
    35213781                argv[i] = alloca(sizeof(int)*3 + 3);
     
    35313791
    35323792static void
    3533 showpipe(struct job *jp, FILE *out)
    3534 {
    3535     struct procstat *sp;
    3536     struct procstat *spend;
    3537 
    3538     spend = jp->ps + jp->nprocs;
    3539     for (sp = jp->ps + 1; sp < spend; sp++)
    3540         fprintf(out, " | %s", sp->cmd);
    3541     outcslow('\n', out);
     3793showpipe(struct job *jp /*, FILE *out*/)
     3794{
     3795    struct procstat *ps;
     3796    struct procstat *psend;
     3797
     3798    psend = jp->ps + jp->nprocs;
     3799    for (ps = jp->ps + 1; ps < psend; ps++)
     3800        printf(" | %s", ps->ps_cmd);
     3801    outcslow('\n', stdout);
    35423802    flush_stdout_stderr();
    35433803}
     
    35563816        goto out;
    35573817    jp->state = JOBRUNNING;
    3558     pgid = jp->ps->pid;
     3818    pgid = jp->ps[0].ps_pid;
    35593819    if (mode == FORK_FG)
    35603820        xtcsetpgrp(ttyfd, pgid);
     
    35633823    i = jp->nprocs;
    35643824    do {
    3565         if (WIFSTOPPED(ps->status)) {
    3566             ps->status = -1;
     3825        if (WIFSTOPPED(ps->ps_status)) {
     3826            ps->ps_status = -1;
    35673827        }
    35683828        ps++;
     
    35743834}
    35753835
    3576 static int
    3577 fg_bgcmd(int argc, char **argv)
     3836static int FAST_FUNC
     3837fg_bgcmd(int argc UNUSED_PARAM, char **argv)
    35783838{
    35793839    struct job *jp;
    3580     FILE *out;
    35813840    int mode;
    35823841    int retval;
     
    35853844    nextopt(nullstr);
    35863845    argv = argptr;
    3587     out = stdout;
    35883846    do {
    35893847        jp = getjob(*argv, 1);
    35903848        if (mode == FORK_BG) {
    35913849            set_curjob(jp, CUR_RUNNING);
    3592             fprintf(out, "[%d] ", jobno(jp));
    3593         }
    3594         outstr(jp->ps->cmd, out);
    3595         showpipe(jp, out);
     3850            printf("[%d] ", jobno(jp));
     3851        }
     3852        out1str(jp->ps[0].ps_cmd);
     3853        showpipe(jp /*, stdout*/);
    35963854        retval = restartjob(jp, mode);
    35973855    } while (*argv && *++argv);
     
    36383896}
    36393897
    3640 /*
    3641  * Do a wait system call.  If job control is compiled in, we accept
    3642  * stopped processes.  If block is zero, we return a value of zero
    3643  * rather than blocking.
    3644  *
    3645  * System V doesn't have a non-blocking wait system call.  It does
    3646  * have a SIGCLD signal that is sent to a process when one of it's
    3647  * children dies.  The obvious way to use SIGCLD would be to install
    3648  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
    3649  * was received, and have waitproc bump another counter when it got
    3650  * the status of a process.  Waitproc would then know that a wait
    3651  * system call would not block if the two counters were different.
    3652  * This approach doesn't work because if a process has children that
    3653  * have not been waited for, System V will send it a SIGCLD when it
    3654  * installs a signal handler for SIGCLD.  What this means is that when
    3655  * a child exits, the shell will be sent SIGCLD signals continuously
    3656  * until is runs out of stack space, unless it does a wait call before
    3657  * restoring the signal handler.  The code below takes advantage of
    3658  * this (mis)feature by installing a signal handler for SIGCLD and
    3659  * then checking to see whether it was called.  If there are any
    3660  * children to be waited for, it will be.
    3661  *
    3662  * If neither SYSV nor BSD is defined, we don't implement nonblocking
    3663  * waits at all.  In this case, the user will not be informed when
    3664  * a background process until the next time she runs a real program
    3665  * (as opposed to running a builtin command or just typing return),
    3666  * and the jobs command may give out of date information.
    3667  */
    36683898static int
    3669 waitproc(int block, int *status)
    3670 {
    3671     int flags = 0;
    3672 
    3673 #if JOBS
    3674     if (jobctl)
    3675         flags |= WUNTRACED;
    3676 #endif
    3677     if (block == 0)
    3678         flags |= WNOHANG;
    3679     return wait3(status, flags, (struct rusage *)NULL);
    3680 }
    3681 
    3682 /*
    3683  * Wait for a process to terminate.
    3684  */
    3685 static int
    3686 dowait(int block, struct job *job)
     3899dowait(int wait_flags, struct job *job)
    36873900{
    36883901    int pid;
     
    36923905    int state;
    36933906
    3694     TRACE(("dowait(%d) called\n", block));
    3695     pid = waitproc(block, &status);
    3696     TRACE(("wait returns pid %d, status=%d\n", pid, status));
     3907    TRACE(("dowait(0x%x) called\n", wait_flags));
     3908
     3909    /* Do a wait system call. If job control is compiled in, we accept
     3910     * stopped processes. wait_flags may have WNOHANG, preventing blocking.
     3911     * NB: _not_ safe_waitpid, we need to detect EINTR */
     3912    if (doing_jobctl)
     3913        wait_flags |= WUNTRACED;
     3914    pid = waitpid(-1, &status, wait_flags);
     3915    TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
     3916                pid, status, errno, strerror(errno)));
    36973917    if (pid <= 0)
    36983918        return pid;
     3919
    36993920    INT_OFF;
    37003921    thisjob = NULL;
    37013922    for (jp = curjob; jp; jp = jp->prev_job) {
    3702         struct procstat *sp;
    3703         struct procstat *spend;
     3923        struct procstat *ps;
     3924        struct procstat *psend;
    37043925        if (jp->state == JOBDONE)
    37053926            continue;
    37063927        state = JOBDONE;
    3707         spend = jp->ps + jp->nprocs;
    3708         sp = jp->ps;
     3928        ps = jp->ps;
     3929        psend = ps + jp->nprocs;
    37093930        do {
    3710             if (sp->pid == pid) {
     3931            if (ps->ps_pid == pid) {
    37113932                TRACE(("Job %d: changing status of proc %d "
    37123933                    "from 0x%x to 0x%x\n",
    3713                     jobno(jp), pid, sp->status, status));
    3714                 sp->status = status;
     3934                    jobno(jp), pid, ps->ps_status, status));
     3935                ps->ps_status = status;
    37153936                thisjob = jp;
    37163937            }
    3717             if (sp->status == -1)
     3938            if (ps->ps_status == -1)
    37183939                state = JOBRUNNING;
    37193940#if JOBS
    37203941            if (state == JOBRUNNING)
    37213942                continue;
    3722             if (WIFSTOPPED(sp->status)) {
    3723                 jp->stopstatus = sp->status;
     3943            if (WIFSTOPPED(ps->ps_status)) {
     3944                jp->stopstatus = ps->ps_status;
    37243945                state = JOBSTOPPED;
    37253946            }
    37263947#endif
    3727         } while (++sp < spend);
     3948        } while (++ps < psend);
    37283949        if (thisjob)
    37293950            goto gotjob;
     
    37323953    if (!WIFSTOPPED(status))
    37333954#endif
    3734 
    37353955        jobless--;
    37363956    goto out;
     
    37623982        if (len) {
    37633983            s[len] = '\n';
    3764             s[len + 1] = 0;
     3984            s[len + 1] = '\0';
    37653985            out2str(s);
    37663986        }
    37673987    }
     3988    return pid;
     3989}
     3990
     3991static int
     3992blocking_wait_with_raise_on_sig(void)
     3993{
     3994    pid_t pid = dowait(DOWAIT_BLOCK, NULL);
     3995    if (pid <= 0 && pending_sig)
     3996        raise_exception(EXSIG);
    37683997    return pid;
    37693998}
     
    37814010    ps = jp->ps;
    37824011
    3783     if (mode & SHOW_PGID) {
     4012    if (mode & SHOW_ONLY_PGID) { /* jobs -p */
    37844013        /* just output process (group) id of pipeline */
    3785         fprintf(out, "%d\n", ps->pid);
     4014        fprintf(out, "%d\n", ps->ps_pid);
    37864015        return;
    37874016    }
     
    37914020
    37924021    if (jp == curjob)
    3793         s[col - 2] = '+';
     4022        s[col - 3] = '+';
    37944023    else if (curjob && jp == curjob->prev_job)
    3795         s[col - 2] = '-';
    3796 
    3797     if (mode & SHOW_PID)
    3798         col += fmtstr(s + col, 16, "%d ", ps->pid);
     4024        s[col - 3] = '-';
     4025
     4026    if (mode & SHOW_PIDS)
     4027        col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
    37994028
    38004029    psend = ps + jp->nprocs;
     
    38044033        col += sizeof("Running") - 1;
    38054034    } else {
    3806         int status = psend[-1].status;
     4035        int status = psend[-1].ps_status;
    38074036        if (jp->state == JOBSTOPPED)
    38084037            status = jp->stopstatus;
    38094038        col += sprint_status(s + col, status, 0);
    38104039    }
    3811 
     4040    /* By now, "[JOBID]*  [maybe PID] STATUS" is printed */
     4041
     4042    /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
     4043     * or prints several "PID             | <cmdN>" lines,
     4044     * depending on SHOW_PIDS bit.
     4045     * We do not print status of individual processes
     4046     * between PID and <cmdN>. bash does it, but not very well:
     4047     * first line shows overall job status, not process status,
     4048     * making it impossible to know 1st process status.
     4049     */
    38124050    goto start;
    3813 
    38144051    do {
    38154052        /* for each process */
    3816         col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
     4053        s[0] = '\0';
     4054        col = 33;
     4055        if (mode & SHOW_PIDS)
     4056            col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
    38174057 start:
    3818         fprintf(out, "%s%*c%s",
    3819             s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
     4058        fprintf(out, "%s%*c%s%s",
     4059                s,
     4060                33 - col >= 0 ? 33 - col : 0, ' ',
     4061                ps == jp->ps ? "" : "| ",
     4062                ps->ps_cmd
    38204063        );
    3821         if (!(mode & SHOW_PID)) {
    3822             showpipe(jp, out);
    3823             break;
    3824         }
    3825         if (++ps == psend) {
    3826             outcslow('\n', out);
    3827             break;
    3828         }
    3829     } while (1);
     4064    } while (++ps != psend);
     4065    outcslow('\n', out);
    38304066
    38314067    jp->changed = 0;
     
    38464082    struct job *jp;
    38474083
    3848     TRACE(("showjobs(%x) called\n", mode));
    3849 
    3850     /* If not even one one job changed, there is nothing to do */
    3851     while (dowait(DOWAIT_NORMAL, NULL) > 0)
     4084    TRACE(("showjobs(0x%x) called\n", mode));
     4085
     4086    /* Handle all finished jobs */
     4087    while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
    38524088        continue;
    38534089
     
    38594095}
    38604096
    3861 static int
    3862 jobscmd(int argc, char **argv)
     4097static int FAST_FUNC
     4098jobscmd(int argc UNUSED_PARAM, char **argv)
    38634099{
    38644100    int mode, m;
    38654101
    38664102    mode = 0;
    3867     while ((m = nextopt("lp"))) {
     4103    while ((m = nextopt("lp")) != '\0') {
    38684104        if (m == 'l')
    3869             mode = SHOW_PID;
     4105            mode |= SHOW_PIDS;
    38704106        else
    3871             mode = SHOW_PGID;
     4107            mode |= SHOW_ONLY_PGID;
    38724108    }
    38734109
     
    38754111    if (*argv) {
    38764112        do
    3877             showjob(stdout, getjob(*argv,0), mode);
     4113            showjob(stdout, getjob(*argv, 0), mode);
    38784114        while (*++argv);
    3879     } else
     4115    } else {
    38804116        showjobs(stdout, mode);
     4117    }
    38814118
    38824119    return 0;
     
    38844121#endif /* JOBS */
    38854122
     4123/* Called only on finished or stopped jobs (no members are running) */
    38864124static int
    38874125getstatus(struct job *job)
     
    38894127    int status;
    38904128    int retval;
    3891 
    3892     status = job->ps[job->nprocs - 1].status;
     4129    struct procstat *ps;
     4130
     4131    /* Fetch last member's status */
     4132    ps = job->ps + job->nprocs - 1;
     4133    status = ps->ps_status;
     4134    if (pipefail) {
     4135        /* "set -o pipefail" mode: use last _nonzero_ status */
     4136        while (status == 0 && --ps >= job->ps)
     4137            status = ps->ps_status;
     4138    }
     4139
    38934140    retval = WEXITSTATUS(status);
    38944141    if (!WIFEXITED(status)) {
     
    39074154        retval += 128;
    39084155    }
    3909     TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
     4156    TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
    39104157        jobno(job), job->nprocs, status, retval));
    39114158    return retval;
    39124159}
    39134160
    3914 static int
    3915 waitcmd(int argc, char **argv)
     4161static int FAST_FUNC
     4162waitcmd(int argc UNUSED_PARAM, char **argv)
    39164163{
    39174164    struct job *job;
     
    39194166    struct job *jp;
    39204167
    3921     EXSIGON;
     4168    if (pending_sig)
     4169        raise_exception(EXSIG);
    39224170
    39234171    nextopt(nullstr);
     
    39304178            jp = curjob;
    39314179            while (1) {
    3932                 if (!jp) {
    3933                     /* no running procs */
    3934                     goto out;
    3935                 }
     4180                if (!jp) /* no running procs */
     4181                    goto ret;
    39364182                if (jp->state == JOBRUNNING)
    39374183                    break;
     
    39394185                jp = jp->prev_job;
    39404186            }
    3941             dowait(DOWAIT_BLOCK, 0);
     4187            blocking_wait_with_raise_on_sig();
     4188    /* man bash:
     4189     * "When bash is waiting for an asynchronous command via
     4190     * the wait builtin, the reception of a signal for which a trap
     4191     * has been set will cause the wait builtin to return immediately
     4192     * with an exit status greater than 128, immediately after which
     4193     * the trap is executed."
     4194     *
     4195     * blocking_wait_with_raise_on_sig raises signal handlers
     4196     * if it gets no pid (pid < 0). However,
     4197     * if child sends us a signal *and immediately exits*,
     4198     * blocking_wait_with_raise_on_sig gets pid > 0
     4199     * and does not handle pending_sig. Check this case: */
     4200            if (pending_sig)
     4201                raise_exception(EXSIG);
    39424202        }
    39434203    }
     
    39484208            pid_t pid = number(*argv);
    39494209            job = curjob;
    3950             goto start;
    3951             do {
    3952                 if (job->ps[job->nprocs - 1].pid == pid)
     4210            while (1) {
     4211                if (!job)
     4212                    goto repeat;
     4213                if (job->ps[job->nprocs - 1].ps_pid == pid)
    39534214                    break;
    39544215                job = job->prev_job;
    3955  start:
    3956                 if (!job)
    3957                     goto repeat;
    3958             } while (1);
     4216            }
    39594217        } else
    39604218            job = getjob(*argv, 0);
    39614219        /* loop until process terminated or stopped */
    39624220        while (job->state == JOBRUNNING)
    3963             dowait(DOWAIT_BLOCK, 0);
     4221            blocking_wait_with_raise_on_sig();
    39644222        job->waited = 1;
    39654223        retval = getstatus(job);
    3966  repeat:
    3967         ;
     4224 repeat: ;
    39684225    } while (*++argv);
    39694226
    3970  out:
     4227 ret:
    39714228    return retval;
    39724229}
     
    40204277 */
    40214278static struct job *
    4022 makejob(union node *node, int nprocs)
     4279makejob(/*union node *node,*/ int nprocs)
    40234280{
    40244281    int i;
     
    40354292            continue;
    40364293#if JOBS
    4037         if (jobctl)
     4294        if (doing_jobctl)
    40384295            continue;
    40394296#endif
     
    40454302    /* jp->jobctl is a bitfield.
    40464303     * "jp->jobctl |= jobctl" likely to give awful code */
    4047     if (jobctl)
     4304    if (doing_jobctl)
    40484305        jp->jobctl = 1;
    40494306#endif
     
    40554312        jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
    40564313    }
    4057     TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
     4314    TRACE(("makejob(%d) returns %%%d\n", nprocs,
    40584315                jobno(jp)));
    40594316    return jp;
     
    40704327cmdputs(const char *s)
    40714328{
    4072     const char *p, *str;
    4073     char c, cc[2] = " ";
    4074     char *nextc;
    4075     int subtype = 0;
    4076     int quoted = 0;
    4077     static const char vstype[VSTYPE + 1][4] = {
     4329    static const char vstype[VSTYPE + 1][3] = {
    40784330        "", "}", "-", "+", "?", "=",
    40794331        "%", "%%", "#", "##"
     4332        IF_ASH_BASH_COMPAT(, ":", "/", "//")
    40804333    };
    40814334
     4335    const char *p, *str;
     4336    char cc[2];
     4337    char *nextc;
     4338    unsigned char c;
     4339    unsigned char subtype = 0;
     4340    int quoted = 0;
     4341
     4342    cc[1] = '\0';
    40824343    nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
    40834344    p = s;
    4084     while ((c = *p++) != 0) {
    4085         str = 0;
     4345    while ((c = *p++) != '\0') {
     4346        str = NULL;
    40864347        switch (c) {
    40874348        case CTLESC:
     
    41104371            str = "\"$(...)\"";
    41114372            goto dostr;
    4112 #if ENABLE_ASH_MATH_SUPPORT
     4373#if ENABLE_SH_MATH_SUPPORT
    41134374        case CTLARI:
    41144375            str = "$((";
     
    41504411            continue;
    41514412 dostr:
    4152         while ((c = *str++)) {
     4413        while ((c = *str++) != '\0') {
    41534414            USTPUTC(c, nextc);
    41544415        }
    4155     }
     4416    } /* while *p++ not NUL */
     4417
    41564418    if (quoted & 1) {
    41574419        USTPUTC('"', nextc);
     
    41824444    struct nodelist *lp;
    41834445    const char *p;
    4184     char s[2];
    41854446
    41864447    if (!n)
     
    42284489        cmdtxt(n->nif.test);
    42294490        cmdputs("; then ");
    4230         n = n->nif.ifpart;
    42314491        if (n->nif.elsepart) {
    4232             cmdtxt(n);
     4492            cmdtxt(n->nif.ifpart);
    42334493            cmdputs("; else ");
    42344494            n = n->nif.elsepart;
     4495        } else {
     4496            n = n->nif.ifpart;
    42354497        }
    42364498        p = "; fi";
     
    43024564        p = ">>";
    43034565        goto redir;
     4566#if ENABLE_ASH_BASH_COMPAT
     4567    case NTO2:
     4568#endif
    43044569    case NTOFD:
    43054570        p = ">&";
     
    43144579        p = "<>";
    43154580 redir:
    4316         s[0] = n->nfile.fd + '0';
    4317         s[1] = '\0';
    4318         cmdputs(s);
     4581        cmdputs(utoa(n->nfile.fd));
    43194582        cmdputs(p);
    43204583        if (n->type == NTOFD || n->type == NFROMFD) {
    4321             s[0] = n->ndup.dupfd + '0';
    4322             p = s;
    4323             goto dotail2;
     4584            cmdputs(utoa(n->ndup.dupfd));
     4585            break;
    43244586        }
    43254587        n = n->nfile.fname;
     
    43674629
    43684630    for (tp = trap; tp < &trap[NSIG]; tp++) {
    4369         if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
     4631        if (*tp && **tp) {      /* trap not NULL or "" (SIG_IGN) */
    43704632            INT_OFF;
    4371             free(*tp);
     4633            if (trap_ptr == trap)
     4634                free(*tp);
     4635            /* else: it "belongs" to trap_ptr vector, don't free */
    43724636            *tp = NULL;
    4373             if (tp != &trap[0])
     4637            if ((tp - trap) != 0)
    43744638                setsignal(tp - trap);
    43754639            INT_ON;
    43764640        }
    43774641    }
     4642    may_have_traps = 0;
    43784643}
    43794644
     
    43824647
    43834648/* Called after fork(), in child */
    4384 static void
     4649static NOINLINE void
    43854650forkchild(struct job *jp, union node *n, int mode)
    43864651{
     
    43914656    shlvl++;
    43924657
     4658    /* man bash: "Non-builtin commands run by bash have signal handlers
     4659     * set to the values inherited by the shell from its parent".
     4660     * Do we do it correctly? */
     4661
    43934662    closescript();
     4663
     4664    if (mode == FORK_NOJOB          /* is it `xxx` ? */
     4665     && n && n->type == NCMD        /* is it single cmd? */
     4666    /* && n->ncmd.args->type == NARG - always true? */
     4667     && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
     4668     && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
     4669    /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
     4670    ) {
     4671        TRACE(("Trap hack\n"));
     4672        /* Awful hack for `trap` or $(trap).
     4673         *
     4674         * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
     4675         * contains an example where "trap" is executed in a subshell:
     4676         *
     4677         * save_traps=$(trap)
     4678         * ...
     4679         * eval "$save_traps"
     4680         *
     4681         * Standard does not say that "trap" in subshell shall print
     4682         * parent shell's traps. It only says that its output
     4683         * must have suitable form, but then, in the above example
     4684         * (which is not supposed to be normative), it implies that.
     4685         *
     4686         * bash (and probably other shell) does implement it
     4687         * (traps are reset to defaults, but "trap" still shows them),
     4688         * but as a result, "trap" logic is hopelessly messed up:
     4689         *
     4690         * # trap
     4691         * trap -- 'echo Ho' SIGWINCH  <--- we have a handler
     4692         * # (trap)        <--- trap is in subshell - no output (correct, traps are reset)
     4693         * # true | trap   <--- trap is in subshell - no output (ditto)
     4694         * # echo `true | trap`    <--- in subshell - output (but traps are reset!)
     4695         * trap -- 'echo Ho' SIGWINCH
     4696         * # echo `(trap)`         <--- in subshell in subshell - output
     4697         * trap -- 'echo Ho' SIGWINCH
     4698         * # echo `true | (trap)`  <--- in subshell in subshell in subshell - output!
     4699         * trap -- 'echo Ho' SIGWINCH
     4700         *
     4701         * The rules when to forget and when to not forget traps
     4702         * get really complex and nonsensical.
     4703         *
     4704         * Our solution: ONLY bare $(trap) or `trap` is special.
     4705         */
     4706        /* Save trap handler strings for trap builtin to print */
     4707        trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
     4708        /* Fall through into clearing traps */
     4709    }
    43944710    clear_traps();
    43954711#if JOBS
    43964712    /* do job control only in root shell */
    4397     jobctl = 0;
     4713    doing_jobctl = 0;
    43984714    if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
    43994715        pid_t pgrp;
     
    44024718            pgrp = getpid();
    44034719        else
    4404             pgrp = jp->ps[0].pid;
    4405         /* This can fail because we are doing it in the parent also */
    4406         (void)setpgid(0, pgrp);
     4720            pgrp = jp->ps[0].ps_pid;
     4721        /* this can fail because we are doing it in the parent also */
     4722        setpgid(0, pgrp);
    44074723        if (mode == FORK_FG)
    44084724            xtcsetpgrp(ttyfd, pgrp);
     
    44124728#endif
    44134729    if (mode == FORK_BG) {
     4730        /* man bash: "When job control is not in effect,
     4731         * asynchronous commands ignore SIGINT and SIGQUIT" */
    44144732        ignoresig(SIGINT);
    44154733        ignoresig(SIGQUIT);
     
    44174735            close(0);
    44184736            if (open(bb_dev_null, O_RDONLY) != 0)
    4419                 ash_msg_and_raise_error("can't open %s", bb_dev_null);
    4420         }
    4421     }
    4422     if (!oldlvl && iflag) {
    4423         setsignal(SIGINT);
     4737                ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
     4738        }
     4739    }
     4740    if (!oldlvl) {
     4741        if (iflag) { /* why if iflag only? */
     4742            setsignal(SIGINT);
     4743            setsignal(SIGTERM);
     4744        }
     4745        /* man bash:
     4746         * "In all cases, bash ignores SIGQUIT. Non-builtin
     4747         * commands run by bash have signal handlers
     4748         * set to the values inherited by the shell
     4749         * from its parent".
     4750         * Take care of the second rule: */
    44244751        setsignal(SIGQUIT);
    4425         setsignal(SIGTERM);
    4426     }
     4752    }
     4753#if JOBS
     4754    if (n && n->type == NCMD
     4755     && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
     4756    ) {
     4757        TRACE(("Job hack\n"));
     4758        /* "jobs": we do not want to clear job list for it,
     4759         * instead we remove only _its_ own_ job from job list.
     4760         * This makes "jobs .... | cat" more useful.
     4761         */
     4762        freejob(curjob);
     4763        return;
     4764    }
     4765#endif
    44274766    for (jp = curjob; jp; jp = jp->prev_job)
    44284767        freejob(jp);
     
    44314770
    44324771/* Called after fork(), in parent */
     4772#if !JOBS
     4773#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
     4774#endif
    44334775static void
    44344776forkparent(struct job *jp, union node *n, int mode, pid_t pid)
     
    44364778    TRACE(("In parent shell: child = %d\n", pid));
    44374779    if (!jp) {
    4438         while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
     4780        while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
     4781            continue;
    44394782        jobless++;
    44404783        return;
     
    44474790            pgrp = pid;
    44484791        else
    4449             pgrp = jp->ps[0].pid;
     4792            pgrp = jp->ps[0].ps_pid;
    44504793        /* This can fail because we are doing it in the child also */
    44514794        setpgid(pid, pgrp);
     
    44584801    if (jp) {
    44594802        struct procstat *ps = &jp->ps[jp->nprocs++];
    4460         ps->pid = pid;
    4461         ps->status = -1;
    4462         ps->cmd = nullstr;
     4803        ps->ps_pid = pid;
     4804        ps->ps_status = -1;
     4805        ps->ps_cmd = nullstr;
    44634806#if JOBS
    4464         if (jobctl && n)
    4465             ps->cmd = commandtext(n);
     4807        if (doing_jobctl && n)
     4808            ps->ps_cmd = commandtext(n);
    44664809#endif
    44674810    }
     
    44794822        if (jp)
    44804823            freejob(jp);
    4481         ash_msg_and_raise_error("cannot fork");
    4482     }
    4483     if (pid == 0)
     4824        ash_msg_and_raise_error("can't fork");
     4825    }
     4826    if (pid == 0) {
     4827        CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
    44844828        forkchild(jp, n, mode);
    4485     else
     4829    } else {
    44864830        forkparent(jp, n, mode, pid);
     4831    }
    44874832    return pid;
    44884833}
     
    44914836 * Wait for job to finish.
    44924837 *
    4493  * Under job control we have the problem that while a child process is
    4494  * running interrupts generated by the user are sent to the child but not
    4495  * to the shell.  This means that an infinite loop started by an inter-
    4496  * active user may be hard to kill.  With job control turned off, an
    4497  * interactive user may place an interactive program inside a loop.  If
    4498  * the interactive program catches interrupts, the user doesn't want
     4838 * Under job control we have the problem that while a child process
     4839 * is running interrupts generated by the user are sent to the child
     4840 * but not to the shell.  This means that an infinite loop started by
     4841 * an interactive user may be hard to kill.  With job control turned off,
     4842 * an interactive user may place an interactive program inside a loop.
     4843 * If the interactive program catches interrupts, the user doesn't want
    44994844 * these interrupts to also abort the loop.  The approach we take here
    45004845 * is to have the shell ignore interrupt signals while waiting for a
     
    45144859
    45154860    TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
     4861
     4862    INT_OFF;
    45164863    while (jp->state == JOBRUNNING) {
     4864        /* In non-interactive shells, we _can_ get
     4865         * a keyboard signal here and be EINTRed,
     4866         * but we just loop back, waiting for command to complete.
     4867         *
     4868         * man bash:
     4869         * "If bash is waiting for a command to complete and receives
     4870         * a signal for which a trap has been set, the trap
     4871         * will not be executed until the command completes."
     4872         *
     4873         * Reality is that even if trap is not set, bash
     4874         * will not act on the signal until command completes.
     4875         * Try this. sleep5intoff.c:
     4876         * #include <signal.h>
     4877         * #include <unistd.h>
     4878         * int main() {
     4879         *         sigset_t set;
     4880         *         sigemptyset(&set);
     4881         *         sigaddset(&set, SIGINT);
     4882         *         sigaddset(&set, SIGQUIT);
     4883         *         sigprocmask(SIG_BLOCK, &set, NULL);
     4884         *         sleep(5);
     4885         *         return 0;
     4886         * }
     4887         * $ bash -c './sleep5intoff; echo hi'
     4888         * ^C^C^C^C <--- pressing ^C once a second
     4889         * $ _
     4890         * $ bash -c './sleep5intoff; echo hi'
     4891         * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
     4892         * $ _
     4893         */
    45174894        dowait(DOWAIT_BLOCK, jp);
    45184895    }
     4896    INT_ON;
     4897
    45194898    st = getstatus(jp);
    45204899#if JOBS
     
    45294908         * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
    45304909         */
    4531         if (jp->sigint)
    4532             raise(SIGINT);
     4910        if (jp->sigint) /* TODO: do the same with all signals */
     4911            raise(SIGINT); /* ... by raise(jp->sig) instead? */
    45334912    }
    45344913    if (jp->state == JOBDONE)
     
    45674946
    45684947#define EMPTY -2                /* marks an unused slot in redirtab */
    4569 #ifndef PIPE_BUF
    4570 # define PIPESIZE 4096          /* amount of buffering in a pipe */
    4571 #else
    4572 # define PIPESIZE PIPE_BUF
    4573 #endif
     4948#define CLOSED -3               /* marks a slot of previously-closed fd */
    45744949
    45754950/*
     
    46214996     * replaced, return the file descriptor.
    46224997     */
    4623     if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
    4624      && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
     4998    if (fstat(fd, &finfo2) == 0
     4999     && !S_ISREG(finfo2.st_mode)
     5000     && finfo.st_dev == finfo2.st_dev
     5001     && finfo.st_ino == finfo2.st_ino
     5002    ) {
    46255003        return fd;
     5004    }
    46265005
    46275006    /* The file has been replaced.  badness. */
     
    46485027    if (redir->type == NHERE) {
    46495028        len = strlen(redir->nhere.doc->narg.text);
    4650         if (len <= PIPESIZE) {
     5029        if (len <= PIPE_BUF) {
    46515030            full_write(pip[1], redir->nhere.doc->narg.text, len);
    46525031            goto out;
     
    46545033    }
    46555034    if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
     5035        /* child */
    46565036        close(pip[0]);
    4657         signal(SIGINT, SIG_IGN);
    4658         signal(SIGQUIT, SIG_IGN);
    4659         signal(SIGHUP, SIG_IGN);
    4660 #ifdef SIGTSTP
    4661         signal(SIGTSTP, SIG_IGN);
    4662 #endif
     5037        ignoresig(SIGINT);  //signal(SIGINT, SIG_IGN);
     5038        ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
     5039        ignoresig(SIGHUP);  //signal(SIGHUP, SIG_IGN);
     5040        ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
    46635041        signal(SIGPIPE, SIG_DFL);
    46645042        if (redir->type == NHERE)
    46655043            full_write(pip[1], redir->nhere.doc->narg.text, len);
    4666         else
     5044        else /* NXHERE */
    46675045            expandhere(redir->nhere.doc, pip[1]);
    4668         _exit(0);
     5046        _exit(EXIT_SUCCESS);
    46695047    }
    46705048 out:
     
    46885066    case NFROMTO:
    46895067        fname = redir->nfile.expfname;
    4690         f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
     5068        f = open(fname, O_RDWR|O_CREAT, 0666);
    46915069        if (f < 0)
    46925070            goto ecreate;
    46935071        break;
    46945072    case NTO:
     5073#if ENABLE_ASH_BASH_COMPAT
     5074    case NTO2:
     5075#endif
    46955076        /* Take care of noclobber mode. */
    46965077        if (Cflag) {
     
    47195100#endif
    47205101        /* Fall through to eliminate warning. */
    4721     case NTOFD:
    4722     case NFROMFD:
    4723         f = -1;
    4724         break;
     5102/* Our single caller does this itself */
     5103//  case NTOFD:
     5104//  case NFROMFD:
     5105//      f = -1;
     5106//      break;
    47255107    case NHERE:
    47265108    case NXHERE:
     
    47315113    return f;
    47325114 ecreate:
    4733     ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
     5115    ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
    47345116 eopen:
    4735     ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
     5117    ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
    47365118}
    47375119
     
    47415123 * file descriptors left.
    47425124 */
     5125/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
     5126 * old code was doing close(to) prior to copyfd() to achieve the same */
     5127enum {
     5128    COPYFD_EXACT   = (int)~(INT_MAX),
     5129    COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
     5130};
    47435131static int
    47445132copyfd(int from, int to)
     
    47465134    int newfd;
    47475135
    4748     newfd = fcntl(from, F_DUPFD, to);
     5136    if (to & COPYFD_EXACT) {
     5137        to &= ~COPYFD_EXACT;
     5138        /*if (from != to)*/
     5139            newfd = dup2(from, to);
     5140    } else {
     5141        newfd = fcntl(from, F_DUPFD, to);
     5142    }
    47495143    if (newfd < 0) {
    47505144        if (errno == EMFILE)
    47515145            return EMPTY;
     5146        /* Happens when source fd is not open: try "echo >&99" */
    47525147        ash_msg_and_raise_error("%d: %m", from);
    47535148    }
     
    47555150}
    47565151
    4757 static void
    4758 dupredirect(union node *redir, int f)
    4759 {
    4760     int fd = redir->nfile.fd;
    4761 
    4762     if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
    4763         if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
    4764             copyfd(redir->ndup.dupfd, fd);
    4765         }
    4766         return;
    4767     }
    4768 
    4769     if (f != fd) {
    4770         copyfd(f, fd);
    4771         close(f);
    4772     }
     5152/* Struct def and variable are moved down to the first usage site */
     5153struct two_fd_t {
     5154    int orig, copy;
     5155};
     5156struct redirtab {
     5157    struct redirtab *next;
     5158    int nullredirs;
     5159    int pair_count;
     5160    struct two_fd_t two_fd[];
     5161};
     5162#define redirlist (G_var.redirlist)
     5163
     5164static int need_to_remember(struct redirtab *rp, int fd)
     5165{
     5166    int i;
     5167
     5168    if (!rp) /* remembering was not requested */
     5169        return 0;
     5170
     5171    for (i = 0; i < rp->pair_count; i++) {
     5172        if (rp->two_fd[i].orig == fd) {
     5173            /* already remembered */
     5174            return 0;
     5175        }
     5176    }
     5177    return 1;
     5178}
     5179
     5180/* "hidden" fd is a fd used to read scripts, or a copy of such */
     5181static int is_hidden_fd(struct redirtab *rp, int fd)
     5182{
     5183    int i;
     5184    struct parsefile *pf;
     5185
     5186    if (fd == -1)
     5187        return 0;
     5188    /* Check open scripts' fds */
     5189    pf = g_parsefile;
     5190    while (pf) {
     5191        /* We skip pf_fd == 0 case because of the following case:
     5192         * $ ash  # running ash interactively
     5193         * $ . ./script.sh
     5194         * and in script.sh: "exec 9>&0".
     5195         * Even though top-level pf_fd _is_ 0,
     5196         * it's still ok to use it: "read" builtin uses it,
     5197         * why should we cripple "exec" builtin?
     5198         */
     5199        if (pf->pf_fd > 0 && fd == pf->pf_fd) {
     5200            return 1;
     5201        }
     5202        pf = pf->prev;
     5203    }
     5204
     5205    if (!rp)
     5206        return 0;
     5207    /* Check saved fds of redirects */
     5208    fd |= COPYFD_RESTORE;
     5209    for (i = 0; i < rp->pair_count; i++) {
     5210        if (rp->two_fd[i].copy == fd) {
     5211            return 1;
     5212        }
     5213    }
     5214    return 0;
    47735215}
    47745216
     
    47765218 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
    47775219 * old file descriptors are stashed away so that the redirection can be
    4778  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
    4779  * standard output, and the standard error if it becomes a duplicate of
    4780  * stdout, is saved in memory.
     5220 * undone by calling popredir.
    47815221 */
    47825222/* flags passed to redirect */
     
    47865226redirect(union node *redir, int flags)
    47875227{
    4788     union node *n;
    47895228    struct redirtab *sv;
     5229    int sv_pos;
    47905230    int i;
    47915231    int fd;
    47925232    int newfd;
    4793     int *p;
    4794     nullredirs++;
     5233    int copied_fd2 = -1;
     5234
     5235    g_nullredirs++;
    47955236    if (!redir) {
    47965237        return;
    47975238    }
     5239
    47985240    sv = NULL;
     5241    sv_pos = 0;
    47995242    INT_OFF;
    48005243    if (flags & REDIR_PUSH) {
    4801         struct redirtab *q;
    4802         q = ckmalloc(sizeof(struct redirtab));
    4803         q->next = redirlist;
    4804         redirlist = q;
    4805         q->nullredirs = nullredirs - 1;
    4806         for (i = 0; i < 10; i++)
    4807             q->renamed[i] = EMPTY;
    4808         nullredirs = 0;
    4809         sv = q;
    4810     }
    4811     n = redir;
     5244        union node *tmp = redir;
     5245        do {
     5246            sv_pos++;
     5247#if ENABLE_ASH_BASH_COMPAT
     5248            if (tmp->nfile.type == NTO2)
     5249                sv_pos++;
     5250#endif
     5251            tmp = tmp->nfile.next;
     5252        } while (tmp);
     5253        sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
     5254        sv->next = redirlist;
     5255        sv->pair_count = sv_pos;
     5256        redirlist = sv;
     5257        sv->nullredirs = g_nullredirs - 1;
     5258        g_nullredirs = 0;
     5259        while (sv_pos > 0) {
     5260            sv_pos--;
     5261            sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
     5262        }
     5263    }
     5264
    48125265    do {
    4813         fd = n->nfile.fd;
    4814         if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
    4815          && n->ndup.dupfd == fd)
    4816             continue; /* redirect from/to same file descriptor */
    4817 
    4818         newfd = openredirect(n);
    4819         if (fd == newfd)
    4820             continue;
    4821         if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
    4822             i = fcntl(fd, F_DUPFD, 10);
    4823 
     5266        int right_fd = -1;
     5267        fd = redir->nfile.fd;
     5268        if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
     5269            right_fd = redir->ndup.dupfd;
     5270            //bb_error_msg("doing %d > %d", fd, right_fd);
     5271            /* redirect from/to same file descriptor? */
     5272            if (right_fd == fd)
     5273                continue;
     5274            /* "echo >&10" and 10 is a fd opened to a sh script? */
     5275            if (is_hidden_fd(sv, right_fd)) {
     5276                errno = EBADF; /* as if it is closed */
     5277                ash_msg_and_raise_error("%d: %m", right_fd);
     5278            }
     5279            newfd = -1;
     5280        } else {
     5281            newfd = openredirect(redir); /* always >= 0 */
     5282            if (fd == newfd) {
     5283                /* Descriptor wasn't open before redirect.
     5284                 * Mark it for close in the future */
     5285                if (need_to_remember(sv, fd)) {
     5286                    goto remember_to_close;
     5287                }
     5288                continue;
     5289            }
     5290        }
     5291#if ENABLE_ASH_BASH_COMPAT
     5292 redirect_more:
     5293#endif
     5294        if (need_to_remember(sv, fd)) {
     5295            /* Copy old descriptor */
     5296            /* Careful to not accidentally "save"
     5297             * to the same fd as right side fd in N>&M */
     5298            int minfd = right_fd < 10 ? 10 : right_fd + 1;
     5299            i = fcntl(fd, F_DUPFD, minfd);
     5300/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
     5301 * are closed in popredir() in the child, preventing them from leaking
     5302 * into child. (popredir() also cleans up the mess in case of failures)
     5303 */
    48245304            if (i == -1) {
    48255305                i = errno;
    48265306                if (i != EBADF) {
    4827                     close(newfd);
     5307                    /* Strange error (e.g. "too many files" EMFILE?) */
     5308                    if (newfd >= 0)
     5309                        close(newfd);
    48285310                    errno = i;
    48295311                    ash_msg_and_raise_error("%d: %m", fd);
    48305312                    /* NOTREACHED */
    48315313                }
     5314                /* EBADF: it is not open - good, remember to close it */
     5315 remember_to_close:
     5316                i = CLOSED;
     5317            } else { /* fd is open, save its copy */
     5318                /* "exec fd>&-" should not close fds
     5319                 * which point to script file(s).
     5320                 * Force them to be restored afterwards */
     5321                if (is_hidden_fd(sv, fd))
     5322                    i |= COPYFD_RESTORE;
     5323            }
     5324            if (fd == 2)
     5325                copied_fd2 = i;
     5326            sv->two_fd[sv_pos].orig = fd;
     5327            sv->two_fd[sv_pos].copy = i;
     5328            sv_pos++;
     5329        }
     5330        if (newfd < 0) {
     5331            /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
     5332            if (redir->ndup.dupfd < 0) { /* "fd>&-" */
     5333                /* Don't want to trigger debugging */
     5334                if (fd != -1)
     5335                    close(fd);
    48325336            } else {
    4833                 *p = i;
    4834                 close(fd);
     5337                copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
    48355338            }
    4836         } else {
    4837             close(fd);
    4838         }
    4839         dupredirect(n, newfd);
    4840     } while ((n = n->nfile.next));
     5339        } else if (fd != newfd) { /* move newfd to fd */
     5340            copyfd(newfd, fd | COPYFD_EXACT);
     5341#if ENABLE_ASH_BASH_COMPAT
     5342            if (!(redir->nfile.type == NTO2 && fd == 2))
     5343#endif
     5344                close(newfd);
     5345        }
     5346#if ENABLE_ASH_BASH_COMPAT
     5347        if (redir->nfile.type == NTO2 && fd == 1) {
     5348            /* We already redirected it to fd 1, now copy it to 2 */
     5349            newfd = 1;
     5350            fd = 2;
     5351            goto redirect_more;
     5352        }
     5353#endif
     5354    } while ((redir = redir->nfile.next) != NULL);
     5355
    48415356    INT_ON;
    4842     if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
    4843         preverrout_fd = sv->renamed[2];
     5357    if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
     5358        preverrout_fd = copied_fd2;
    48445359}
    48455360
     
    48485363 */
    48495364static void
    4850 popredir(int drop)
     5365popredir(int drop, int restore)
    48515366{
    48525367    struct redirtab *rp;
    48535368    int i;
    48545369
    4855     if (--nullredirs >= 0)
     5370    if (--g_nullredirs >= 0)
    48565371        return;
    48575372    INT_OFF;
    48585373    rp = redirlist;
    4859     for (i = 0; i < 10; i++) {
    4860         if (rp->renamed[i] != EMPTY) {
    4861             if (!drop) {
    4862                 close(i);
    4863                 copyfd(rp->renamed[i], i);
     5374    for (i = 0; i < rp->pair_count; i++) {
     5375        int fd = rp->two_fd[i].orig;
     5376        int copy = rp->two_fd[i].copy;
     5377        if (copy == CLOSED) {
     5378            if (!drop)
     5379                close(fd);
     5380            continue;
     5381        }
     5382        if (copy != EMPTY) {
     5383            if (!drop || (restore && (copy & COPYFD_RESTORE))) {
     5384                copy &= ~COPYFD_RESTORE;
     5385                /*close(fd);*/
     5386                copyfd(copy, fd | COPYFD_EXACT);
    48645387            }
    4865             close(rp->renamed[i]);
     5388            close(copy & ~COPYFD_RESTORE);
    48665389        }
    48675390    }
    48685391    redirlist = rp->next;
    4869     nullredirs = rp->nullredirs;
     5392    g_nullredirs = rp->nullredirs;
    48705393    free(rp);
    48715394    INT_ON;
     
    48835406{
    48845407    for (;;) {
    4885         nullredirs = 0;
     5408        g_nullredirs = 0;
    48865409        if (!redirlist)
    48875410            break;
    4888         popredir(drop);
     5411        popredir(drop, /*restore:*/ 0);
    48895412    }
    48905413}
     
    48995422
    49005423    SAVE_INT(saveint);
    4901     err = setjmp(jmploc.loc) * 2;
     5424    /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
     5425    err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
    49025426    if (!err) {
    49035427        exception_handler = &jmploc;
     
    49055429    }
    49065430    exception_handler = savehandler;
    4907     if (err && exception != EXERROR)
     5431    if (err && exception_type != EXERROR)
    49085432        longjmp(exception_handler->loc, 1);
    49095433    RESTORE_INT(saveint);
     
    49165440 * We have to deal with backquotes, shell variables, and file metacharacters.
    49175441 */
     5442
     5443#if ENABLE_SH_MATH_SUPPORT
     5444static arith_t
     5445ash_arith(const char *s)
     5446{
     5447    arith_state_t math_state;
     5448    arith_t result;
     5449
     5450    math_state.lookupvar = lookupvar;
     5451    math_state.setvar    = setvar2;
     5452    //math_state.endofname = endofname;
     5453
     5454    INT_OFF;
     5455    result = arith(&math_state, s);
     5456    if (math_state.errmsg)
     5457        ash_msg_and_raise_error(math_state.errmsg);
     5458    INT_ON;
     5459
     5460    return result;
     5461}
     5462#endif
    49185463
    49195464/*
     
    49305475#define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
    49315476/*
    4932  * _rmescape() flags
     5477 * rmescape() flags
    49335478 */
    49345479#define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
     
    49685513 * Our own itoa().
    49695514 */
     5515#if !ENABLE_SH_MATH_SUPPORT
     5516/* cvtnum() is used even if math support is off (to prepare $? values and such) */
     5517typedef long arith_t;
     5518# define ARITH_FMT "%ld"
     5519#endif
    49705520static int
    49715521cvtnum(arith_t num)
     
    49745524
    49755525    expdest = makestrspace(32, expdest);
    4976 #if ENABLE_ASH_MATH_SUPPORT_64
    4977     len = fmtstr(expdest, 32, "%lld", (long long) num);
    4978 #else
    4979     len = fmtstr(expdest, 32, "%ld", num);
    4980 #endif
     5526    len = fmtstr(expdest, 32, ARITH_FMT, num);
    49815527    STADJUST(len, expdest);
    49825528    return len;
     
    49885534    size_t esc = 0;
    49895535
    4990     while (p > start && *--p == CTLESC) {
     5536    while (p > start && (unsigned char)*--p == CTLESC) {
    49915537        esc++;
    49925538    }
     
    49985544 */
    49995545static char *
    5000 _rmescapes(char *str, int flag)
     5546rmescapes(char *str, int flag)
    50015547{
    50025548    static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
     
    50045550    char *p, *q, *r;
    50055551    unsigned inquotes;
    5006     int notescaped;
    5007     int globbing;
     5552    unsigned protect_against_glob;
     5553    unsigned globbing;
    50085554
    50095555    p = strpbrk(str, qchars);
    5010     if (!p) {
     5556    if (!p)
    50115557        return str;
    5012     }
     5558
    50135559    q = p;
    50145560    r = str;
     
    50185564
    50195565        if (flag & RMESCAPE_GROW) {
     5566            int strloc = str - (char *)stackblock();
    50205567            r = makestrspace(fulllen, expdest);
     5568            /* p and str may be invalidated by makestrspace */
     5569            str = (char *)stackblock() + strloc;
     5570            p = str + len;
    50215571        } else if (flag & RMESCAPE_HEAP) {
    50225572            r = ckmalloc(fulllen);
     
    50265576        q = r;
    50275577        if (len > 0) {
    5028             q = memcpy(q, str, len) + len;
    5029         }
    5030     }
     5578            q = (char *)memcpy(q, str, len) + len;
     5579        }
     5580    }
     5581
    50315582    inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
    50325583    globbing = flag & RMESCAPE_GLOB;
    5033     notescaped = globbing;
     5584    protect_against_glob = globbing;
    50345585    while (*p) {
    5035         if (*p == CTLQUOTEMARK) {
     5586        if ((unsigned char)*p == CTLQUOTEMARK) {
     5587// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
     5588// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
     5589// Note: both inquotes and protect_against_glob only affect whether
     5590// CTLESC,<ch> gets converted to <ch> or to \<ch>
    50365591            inquotes = ~inquotes;
    50375592            p++;
    5038             notescaped = globbing;
     5593            protect_against_glob = globbing;
    50395594            continue;
    50405595        }
    50415596        if (*p == '\\') {
    50425597            /* naked back slash */
    5043             notescaped = 0;
     5598            protect_against_glob = 0;
    50445599            goto copy;
    50455600        }
    5046         if (*p == CTLESC) {
     5601        if ((unsigned char)*p == CTLESC) {
    50475602            p++;
    5048             if (notescaped && inquotes && *p != '/') {
     5603            if (protect_against_glob && inquotes && *p != '/') {
    50495604                *q++ = '\\';
    50505605            }
    50515606        }
    5052         notescaped = globbing;
     5607        protect_against_glob = globbing;
    50535608 copy:
    50545609        *q++ = *p++;
     
    50615616    return r;
    50625617}
    5063 #define rmescapes(p) _rmescapes((p), 0)
    5064 
    50655618#define pmatch(a, b) !fnmatch((a), (b), 0)
    50665619
     
    50775630        flag |= RMESCAPE_QUOTED;
    50785631    }
    5079     return _rmescapes((char *)pattern, flag);
     5632    return rmescapes((char *)pattern, flag);
    50805633}
    50815634
     
    50885641    char *q = expdest;
    50895642
    5090     q = makestrspace(len * 2, q);
     5643    q = makestrspace(quotes ? len * 2 : len, q);
    50915644
    50925645    while (len--) {
    5093         int c = signed_char2int(*p++);
    5094         if (!c)
     5646        unsigned char c = *p++;
     5647        if (c == '\0')
    50955648            continue;
    5096         if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
    5097             USTPUTC(CTLESC, q);
     5649        if (quotes) {
     5650            int n = SIT(c, syntax);
     5651            if (n == CCTL || n == CBACK)
     5652                USTPUTC(CTLESC, q);
     5653        }
    50985654        USTPUTC(c, q);
    50995655    }
     
    51215677    } else {
    51225678        INT_OFF;
    5123         ifsp = ckmalloc(sizeof(*ifsp));
    5124         ifsp->next = NULL;
     5679        ifsp = ckzalloc(sizeof(*ifsp));
     5680        /*ifsp->next = NULL; - ckzalloc did it */
    51255681        ifslastp->next = ifsp;
    51265682        INT_ON;
     
    51395695
    51405696    if (ifsfirst.endoff > endoff) {
    5141         while (ifsfirst.next != NULL) {
     5697        while (ifsfirst.next) {
    51425698            struct ifsregion *ifsp;
    51435699            INT_OFF;
     
    51475703            INT_ON;
    51485704        }
    5149         if (ifsfirst.begoff > endoff)
     5705        if (ifsfirst.begoff > endoff) {
    51505706            ifslastp = NULL;
    5151         else {
     5707        } else {
    51525708            ifslastp = &ifsfirst;
    51535709            ifsfirst.endoff = endoff;
     
    51585714    ifslastp = &ifsfirst;
    51595715    while (ifslastp->next && ifslastp->next->begoff < endoff)
    5160         ifslastp=ifslastp->next;
    5161     while (ifslastp->next != NULL) {
     5716        ifslastp = ifslastp->next;
     5717    while (ifslastp->next) {
    51625718        struct ifsregion *ifsp;
    51635719        INT_OFF;
     
    51725728
    51735729static char *
    5174 exptilde(char *startp, char *p, int flag)
    5175 {
    5176     char c;
     5730exptilde(char *startp, char *p, int flags)
     5731{
     5732    unsigned char c;
    51775733    char *name;
    51785734    struct passwd *pw;
    51795735    const char *home;
    5180     int quotes = flag & (EXP_FULL | EXP_CASE);
     5736    int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
    51815737    int startloc;
    51825738
     
    51905746            return startp;
    51915747        case ':':
    5192             if (flag & EXP_VARTILDE)
     5748            if (flags & EXP_VARTILDE)
    51935749                goto done;
    51945750            break;
     
    52015757    *p = '\0';
    52025758    if (*name == '\0') {
    5203         home = lookupvar(homestr);
     5759        home = lookupvar("HOME");
    52045760    } else {
    52055761        pw = getpwnam(name);
     
    52285784struct backcmd {                /* result of evalbackcmd */
    52295785    int fd;                 /* file descriptor to read from */
     5786    int nleft;              /* number of chars in buffer */
    52305787    char *buf;              /* buffer */
    5231     int nleft;              /* number of chars in buffer */
    52325788    struct job *jp;         /* job structure for command */
    52335789};
    52345790
    52355791/* These forward decls are needed to use "eval" code for backticks handling: */
    5236 static int back_exitstatus; /* exit status of backquoted command */
     5792static uint8_t back_exitstatus; /* exit status of backquoted command */
    52375793#define EV_EXIT 01              /* exit after evaluating tree */
    52385794static void evaltree(union node *, int);
    52395795
    5240 static void
     5796static void FAST_FUNC
    52415797evalbackcmd(union node *n, struct backcmd *result)
    52425798{
     
    52475803    result->nleft = 0;
    52485804    result->jp = NULL;
    5249     if (n == NULL) {
     5805    if (n == NULL)
    52505806        goto out;
    5251     }
    52525807
    52535808    saveherefd = herefd;
     
    52605815        if (pipe(pip) < 0)
    52615816            ash_msg_and_raise_error("pipe call failed");
    5262         jp = makejob(n, 1);
     5817        jp = makejob(/*n,*/ 1);
    52635818        if (forkshell(jp, n, FORK_NOJOB) == 0) {
    52645819            FORCE_INT_ON;
    52655820            close(pip[0]);
    52665821            if (pip[1] != 1) {
    5267                 close(1);
    5268                 copyfd(pip[1], 1);
     5822                /*close(1);*/
     5823                copyfd(pip[1], 1 | COPYFD_EXACT);
    52695824                close(pip[1]);
    52705825            }
     
    52955850    char *dest;
    52965851    int startloc;
    5297     int syntax = quoted? DQSYNTAX : BASESYNTAX;
     5852    int syntax = quoted ? DQSYNTAX : BASESYNTAX;
    52985853    struct stackmark smark;
    52995854
     
    53155870        if (in.fd < 0)
    53165871            break;
    5317         i = safe_read(in.fd, buf, sizeof(buf));
     5872        i = nonblock_safe_read(in.fd, buf, sizeof(buf));
    53185873        TRACE(("expbackq: read returns %d\n", i));
    53195874        if (i <= 0)
     
    53225877    }
    53235878
    5324     if (in.buf)
    5325         free(in.buf);
     5879    free(in.buf);
    53265880    if (in.fd >= 0) {
    53275881        close(in.fd);
     
    53385892    if (quoted == 0)
    53395893        recordregion(startloc, dest - (char *)stackblock(), 0);
    5340     TRACE(("evalbackq: size=%d: \"%.*s\"\n",
    5341         (dest - (char *)stackblock()) - startloc,
    5342         (dest - (char *)stackblock()) - startloc,
     5894    TRACE(("evalbackq: size:%d:'%.*s'\n",
     5895        (int)((dest - (char *)stackblock()) - startloc),
     5896        (int)((dest - (char *)stackblock()) - startloc),
    53435897        stackblock() + startloc));
    53445898}
    53455899
    5346 #if ENABLE_ASH_MATH_SUPPORT
     5900#if ENABLE_SH_MATH_SUPPORT
    53475901/*
    53485902 * Expand arithmetic expression.  Backup to start of expression,
     
    53575911    int len;
    53585912
    5359     /*      ifsfree(); */
     5913    /* ifsfree(); */
    53605914
    53615915    /*
     
    53715925        int esc;
    53725926
    5373         while (*p != CTLARI) {
     5927        while ((unsigned char)*p != CTLARI) {
    53745928            p--;
    53755929#if DEBUG
     
    53975951
    53985952    if (quotes)
    5399         rmescapes(p + 2);
    5400 
    5401     len = cvtnum(dash_arith(p + 2));
     5953        rmescapes(p + 2, 0);
     5954
     5955    len = cvtnum(ash_arith(p + 2));
    54025956
    54035957    if (flag != '"')
     
    54075961
    54085962/* argstr needs it */
    5409 static char *evalvar(char *p, int flag);
     5963static char *evalvar(char *p, int flags, struct strlist *var_str_list);
    54105964
    54115965/*
     
    54135967 * characters to allow for further processing.  Otherwise treat
    54145968 * $@ like $* since no splitting will be performed.
     5969 *
     5970 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
     5971 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
     5972 * for correct expansion of "B=$A" word.
    54155973 */
    54165974static void
    5417 argstr(char *p, int flag)
     5975argstr(char *p, int flags, struct strlist *var_str_list)
    54185976{
    54195977    static const char spclchars[] ALIGN1 = {
     
    54265984        CTLBACKQ,
    54275985        CTLBACKQ | CTLQUOTE,
    5428 #if ENABLE_ASH_MATH_SUPPORT
     5986#if ENABLE_SH_MATH_SUPPORT
    54295987        CTLENDARI,
    54305988#endif
    5431         0
     5989        '\0'
    54325990    };
    54335991    const char *reject = spclchars;
    5434     int c;
    5435     int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
    5436     int breakall = flag & EXP_WORD;
     5992    int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
     5993    int breakall = flags & EXP_WORD;
    54375994    int inquotes;
    54385995    size_t length;
    54395996    int startloc;
    54405997
    5441     if (!(flag & EXP_VARTILDE)) {
     5998    if (!(flags & EXP_VARTILDE)) {
    54425999        reject += 2;
    5443     } else if (flag & EXP_VARTILDE2) {
     6000    } else if (flags & EXP_VARTILDE2) {
    54446001        reject++;
    54456002    }
    54466003    inquotes = 0;
    54476004    length = 0;
    5448     if (flag & EXP_TILDE) {
     6005    if (flags & EXP_TILDE) {
    54496006        char *q;
    54506007
    5451         flag &= ~EXP_TILDE;
     6008        flags &= ~EXP_TILDE;
    54526009 tilde:
    54536010        q = p;
    5454         if (*q == CTLESC && (flag & EXP_QWORD))
     6011        if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
    54556012            q++;
    54566013        if (*q == '~')
    5457             p = exptilde(p, q, flag);
     6014            p = exptilde(p, q, flags);
    54586015    }
    54596016 start:
    54606017    startloc = expdest - (char *)stackblock();
    54616018    for (;;) {
     6019        unsigned char c;
     6020
    54626021        length += strcspn(p + length, reject);
    54636022        c = p[length];
    5464         if (c && (!(c & 0x80)
    5465 #if ENABLE_ASH_MATH_SUPPORT
    5466                     || c == CTLENDARI
    5467 #endif
    5468            )) {
    5469             /* c == '=' || c == ':' || c == CTLENDARI */
    5470             length++;
     6023        if (c) {
     6024            if (!(c & 0x80)
     6025            IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
     6026            ) {
     6027                /* c == '=' || c == ':' || c == CTLENDARI */
     6028                length++;
     6029            }
    54716030        }
    54726031        if (length > 0) {
     
    54866045            goto breakloop;
    54876046        case '=':
    5488             if (flag & EXP_VARTILDE2) {
     6047            if (flags & EXP_VARTILDE2) {
    54896048                p--;
    54906049                continue;
    54916050            }
    5492             flag |= EXP_VARTILDE2;
     6051            flags |= EXP_VARTILDE2;
    54936052            reject++;
    54946053            /* fall through */
     
    55096068        case CTLQUOTEMARK:
    55106069            /* "$@" syntax adherence hack */
    5511             if (
    5512                 !inquotes &&
    5513                 !memcmp(p, dolatstr, 4) &&
    5514                 (p[4] == CTLQUOTEMARK || (
    5515                     p[4] == CTLENDVAR &&
    5516                     p[5] == CTLQUOTEMARK
    5517                 ))
     6070            if (!inquotes
     6071             && memcmp(p, dolatstr, 4) == 0
     6072             && (  p[4] == (char)CTLQUOTEMARK
     6073                || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
     6074                )
    55186075            ) {
    5519                 p = evalvar(p + 1, flag) + 1;
     6076                p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
    55206077                goto start;
    55216078            }
     
    55336090            goto addquote;
    55346091        case CTLVAR:
    5535             p = evalvar(p, flag);
     6092            p = evalvar(p, flags, var_str_list);
    55366093            goto start;
    55376094        case CTLBACKQ:
    5538             c = 0;
     6095            c = '\0';
    55396096        case CTLBACKQ|CTLQUOTE:
    55406097            expbackq(argbackq->n, c, quotes);
    55416098            argbackq = argbackq->next;
    55426099            goto start;
    5543 #if ENABLE_ASH_MATH_SUPPORT
     6100#if ENABLE_SH_MATH_SUPPORT
    55446101        case CTLENDARI:
    55456102            p--;
     
    55496106        }
    55506107    }
    5551  breakloop:
    5552     ;
     6108 breakloop: ;
    55536109}
    55546110
    55556111static char *
    5556 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
    5557     int zero)
    5558 {
    5559     char *loc;
    5560     char *loc2;
     6112scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
     6113        char *pattern, int quotes, int zero)
     6114{
     6115    char *loc, *loc2;
    55616116    char c;
    55626117
     
    55666121        int match;
    55676122        const char *s = loc2;
     6123
    55686124        c = *loc2;
    55696125        if (zero) {
     
    55716127            s = rmesc;
    55726128        }
    5573         match = pmatch(str, s);
     6129        match = pmatch(pattern, s);
     6130
    55746131        *loc2 = c;
    55756132        if (match)
    55766133            return loc;
    5577         if (quotes && *loc == CTLESC)
     6134        if (quotes && (unsigned char)*loc == CTLESC)
    55786135            loc++;
    55796136        loc++;
    55806137        loc2++;
    55816138    } while (c);
    5582     return 0;
     6139    return NULL;
    55836140}
    55846141
    55856142static char *
    5586 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
    5587     int zero)
    5588 {
     6143scanright(char *startp, char *rmesc, char *rmescend,
     6144        char *pattern, int quotes, int match_at_start)
     6145{
     6146#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
     6147    int try2optimize = match_at_start;
     6148#endif
    55896149    int esc = 0;
    55906150    char *loc;
    55916151    char *loc2;
    55926152
    5593     for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
     6153    /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
     6154     * startp="escaped_value_of_v" rmesc="raw_value_of_v"
     6155     * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
     6156     * Logic:
     6157     * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
     6158     * and on each iteration they go back two/one char until they reach the beginning.
     6159     * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
     6160     */
     6161    /* TODO: document in what other circumstances we are called. */
     6162
     6163    for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
    55946164        int match;
    55956165        char c = *loc2;
    55966166        const char *s = loc2;
    5597         if (zero) {
     6167        if (match_at_start) {
    55986168            *loc2 = '\0';
    55996169            s = rmesc;
    56006170        }
    5601         match = pmatch(str, s);
     6171        match = pmatch(pattern, s);
     6172        //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
    56026173        *loc2 = c;
    56036174        if (match)
    56046175            return loc;
     6176#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
     6177        if (try2optimize) {
     6178            /* Maybe we can optimize this:
     6179             * if pattern ends with unescaped *, we can avoid checking
     6180             * shorter strings: if "foo*" doesnt match "raw_value_of_v",
     6181             * it wont match truncated "raw_value_of_" strings too.
     6182             */
     6183            unsigned plen = strlen(pattern);
     6184            /* Does it end with "*"? */
     6185            if (plen != 0 && pattern[--plen] == '*') {
     6186                /* "xxxx*" is not escaped */
     6187                /* "xxx\*" is escaped */
     6188                /* "xx\\*" is not escaped */
     6189                /* "x\\\*" is escaped */
     6190                int slashes = 0;
     6191                while (plen != 0 && pattern[--plen] == '\\')
     6192                    slashes++;
     6193                if (!(slashes & 1))
     6194                    break; /* ends with unescaped "*" */
     6195            }
     6196            try2optimize = 0;
     6197        }
     6198#endif
    56056199        loc--;
    56066200        if (quotes) {
     
    56146208        }
    56156209    }
    5616     return 0;
    5617 }
    5618 
    5619 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
     6210    return NULL;
     6211}
     6212
     6213static void varunset(const char *, const char *, const char *, int) NORETURN;
    56206214static void
    56216215varunset(const char *end, const char *var, const char *umsg, int varflags)
     
    56276221    msg = "parameter not set";
    56286222    if (umsg) {
    5629         if (*end == CTLENDVAR) {
     6223        if ((unsigned char)*end == CTLENDVAR) {
    56306224            if (varflags & VSNUL)
    56316225                tail = " or null";
    5632         } else
     6226        } else {
    56336227            msg = umsg;
    5634     }
    5635     ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
    5636 }
     6228        }
     6229    }
     6230    ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
     6231}
     6232
     6233#if ENABLE_ASH_BASH_COMPAT
     6234static char *
     6235parse_sub_pattern(char *arg, int varflags)
     6236{
     6237    char *idx, *repl = NULL;
     6238    unsigned char c;
     6239
     6240    //char *org_arg = arg;
     6241    //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
     6242    idx = arg;
     6243    while (1) {
     6244        c = *arg;
     6245        if (!c)
     6246            break;
     6247        if (c == '/') {
     6248            /* Only the first '/' seen is our separator */
     6249            if (!repl) {
     6250                repl = idx + 1;
     6251                c = '\0';
     6252            }
     6253        }
     6254        *idx++ = c;
     6255        arg++;
     6256        /*
     6257         * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
     6258         * The result is a_\_z_c (not a\_\_z_c)!
     6259         *
     6260         * Enable debug prints in this function and you'll see:
     6261         * ash: arg:'\\b/_\\_z_' varflags:d
     6262         * ash: pattern:'\\b' repl:'_\_z_'
     6263         * That is, \\b is interpreted as \\b, but \\_ as \_!
     6264         * IOW: search pattern and replace string treat backslashes
     6265         * differently! That is the reason why we check repl below:
     6266         */
     6267        if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
     6268            arg++; /* skip both '\', not just first one */
     6269    }
     6270    *idx = c; /* NUL */
     6271    //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
     6272
     6273    return repl;
     6274}
     6275#endif /* ENABLE_ASH_BASH_COMPAT */
    56376276
    56386277static const char *
    5639 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
    5640 {
     6278subevalvar(char *p, char *varname, int strloc, int subtype,
     6279        int startloc, int varflags, int quotes, struct strlist *var_str_list)
     6280{
     6281    struct nodelist *saveargbackq = argbackq;
    56416282    char *startp;
    56426283    char *loc;
     6284    char *rmesc, *rmescend;
     6285    char *str;
     6286    IF_ASH_BASH_COMPAT(const char *repl = NULL;)
     6287    IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
    56436288    int saveherefd = herefd;
    5644     struct nodelist *saveargbackq = argbackq;
    5645     int amount;
    5646     char *rmesc, *rmescend;
     6289    int amount, workloc, resetloc;
    56476290    int zero;
    5648     char *(*scan)(char *, char *, char *, char *, int , int);
     6291    char *(*scan)(char*, char*, char*, char*, int, int);
     6292
     6293    //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
     6294    //      p, varname, strloc, subtype, startloc, varflags, quotes);
    56496295
    56506296    herefd = -1;
    5651     argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
     6297    argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
     6298            var_str_list);
    56526299    STPUTC('\0', expdest);
    56536300    herefd = saveherefd;
    56546301    argbackq = saveargbackq;
    5655     startp = stackblock() + startloc;
     6302    startp = (char *)stackblock() + startloc;
    56566303
    56576304    switch (subtype) {
    56586305    case VSASSIGN:
    5659         setvar(str, startp, 0);
     6306        setvar(varname, startp, 0);
    56606307        amount = startp - expdest;
    56616308        STADJUST(amount, expdest);
     
    56636310
    56646311    case VSQUESTION:
    5665         varunset(p, str, startp, varflags);
     6312        varunset(p, varname, startp, varflags);
    56666313        /* NOTREACHED */
    5667     }
     6314
     6315#if ENABLE_ASH_BASH_COMPAT
     6316    case VSSUBSTR:
     6317        loc = str = stackblock() + strloc;
     6318        /* Read POS in ${var:POS:LEN} */
     6319        pos = atoi(loc); /* number(loc) errors out on "1:4" */
     6320        len = str - startp - 1;
     6321
     6322        /* *loc != '\0', guaranteed by parser */
     6323        if (quotes) {
     6324            char *ptr;
     6325
     6326            /* Adjust the length by the number of escapes */
     6327            for (ptr = startp; ptr < (str - 1); ptr++) {
     6328                if ((unsigned char)*ptr == CTLESC) {
     6329                    len--;
     6330                    ptr++;
     6331                }
     6332            }
     6333        }
     6334        orig_len = len;
     6335
     6336        if (*loc++ == ':') {
     6337            /* ${var::LEN} */
     6338            len = number(loc);
     6339        } else {
     6340            /* Skip POS in ${var:POS:LEN} */
     6341            len = orig_len;
     6342            while (*loc && *loc != ':') {
     6343                /* TODO?
     6344                 * bash complains on: var=qwe; echo ${var:1a:123}
     6345                if (!isdigit(*loc))
     6346                    ash_msg_and_raise_error(msg_illnum, str);
     6347                 */
     6348                loc++;
     6349            }
     6350            if (*loc++ == ':') {
     6351                len = number(loc);
     6352            }
     6353        }
     6354        if (pos >= orig_len) {
     6355            pos = 0;
     6356            len = 0;
     6357        }
     6358        if (len > (orig_len - pos))
     6359            len = orig_len - pos;
     6360
     6361        for (str = startp; pos; str++, pos--) {
     6362            if (quotes && (unsigned char)*str == CTLESC)
     6363                str++;
     6364        }
     6365        for (loc = startp; len; len--) {
     6366            if (quotes && (unsigned char)*str == CTLESC)
     6367                *loc++ = *str++;
     6368            *loc++ = *str++;
     6369        }
     6370        *loc = '\0';
     6371        amount = loc - expdest;
     6372        STADJUST(amount, expdest);
     6373        return loc;
     6374#endif
     6375    }
     6376
     6377    resetloc = expdest - (char *)stackblock();
     6378
     6379    /* We'll comeback here if we grow the stack while handling
     6380     * a VSREPLACE or VSREPLACEALL, since our pointers into the
     6381     * stack will need rebasing, and we'll need to remove our work
     6382     * areas each time
     6383     */
     6384 IF_ASH_BASH_COMPAT(restart:)
     6385
     6386    amount = expdest - ((char *)stackblock() + resetloc);
     6387    STADJUST(-amount, expdest);
     6388    startp = (char *)stackblock() + startloc;
     6389
     6390    rmesc = startp;
     6391    rmescend = (char *)stackblock() + strloc;
     6392    if (quotes) {
     6393        rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
     6394        if (rmesc != startp) {
     6395            rmescend = expdest;
     6396            startp = (char *)stackblock() + startloc;
     6397        }
     6398    }
     6399    rmescend--;
     6400    str = (char *)stackblock() + strloc;
     6401    preglob(str, varflags & VSQUOTE, 0);
     6402    workloc = expdest - (char *)stackblock();
     6403
     6404#if ENABLE_ASH_BASH_COMPAT
     6405    if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
     6406        char *idx, *end;
     6407
     6408        if (!repl) {
     6409            repl = parse_sub_pattern(str, varflags);
     6410            //bb_error_msg("repl:'%s'", repl);
     6411            if (!repl)
     6412                repl = nullstr;
     6413        }
     6414
     6415        /* If there's no pattern to match, return the expansion unmolested */
     6416        if (str[0] == '\0')
     6417            return NULL;
     6418
     6419        len = 0;
     6420        idx = startp;
     6421        end = str - 1;
     6422        while (idx < end) {
     6423 try_to_match:
     6424            loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
     6425            //bb_error_msg("scanright('%s'):'%s'", str, loc);
     6426            if (!loc) {
     6427                /* No match, advance */
     6428                char *restart_detect = stackblock();
     6429 skip_matching:
     6430                STPUTC(*idx, expdest);
     6431                if (quotes && (unsigned char)*idx == CTLESC) {
     6432                    idx++;
     6433                    len++;
     6434                    STPUTC(*idx, expdest);
     6435                }
     6436                if (stackblock() != restart_detect)
     6437                    goto restart;
     6438                idx++;
     6439                len++;
     6440                rmesc++;
     6441                /* continue; - prone to quadratic behavior, smarter code: */
     6442                if (idx >= end)
     6443                    break;
     6444                if (str[0] == '*') {
     6445                    /* Pattern is "*foo". If "*foo" does not match "long_string",
     6446                     * it would never match "ong_string" etc, no point in trying.
     6447                     */
     6448                    goto skip_matching;
     6449                }
     6450                goto try_to_match;
     6451            }
     6452
     6453            if (subtype == VSREPLACEALL) {
     6454                while (idx < loc) {
     6455                    if (quotes && (unsigned char)*idx == CTLESC)
     6456                        idx++;
     6457                    idx++;
     6458                    rmesc++;
     6459                }
     6460            } else {
     6461                idx = loc;
     6462            }
     6463
     6464            //bb_error_msg("repl:'%s'", repl);
     6465            for (loc = (char*)repl; *loc; loc++) {
     6466                char *restart_detect = stackblock();
     6467                if (quotes && *loc == '\\') {
     6468                    STPUTC(CTLESC, expdest);
     6469                    len++;
     6470                }
     6471                STPUTC(*loc, expdest);
     6472                if (stackblock() != restart_detect)
     6473                    goto restart;
     6474                len++;
     6475            }
     6476
     6477            if (subtype == VSREPLACE) {
     6478                //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
     6479                while (*idx) {
     6480                    char *restart_detect = stackblock();
     6481                    STPUTC(*idx, expdest);
     6482                    if (stackblock() != restart_detect)
     6483                        goto restart;
     6484                    len++;
     6485                    idx++;
     6486                }
     6487                break;
     6488            }
     6489        }
     6490
     6491        /* We've put the replaced text into a buffer at workloc, now
     6492         * move it to the right place and adjust the stack.
     6493         */
     6494        STPUTC('\0', expdest);
     6495        startp = (char *)stackblock() + startloc;
     6496        memmove(startp, (char *)stackblock() + workloc, len + 1);
     6497        //bb_error_msg("startp:'%s'", startp);
     6498        amount = expdest - (startp + len);
     6499        STADJUST(-amount, expdest);
     6500        return startp;
     6501    }
     6502#endif /* ENABLE_ASH_BASH_COMPAT */
    56686503
    56696504    subtype -= VSTRIMRIGHT;
    56706505#if DEBUG
    5671     if (subtype < 0 || subtype > 3)
     6506    if (subtype < 0 || subtype > 7)
    56726507        abort();
    56736508#endif
    5674 
    5675     rmesc = startp;
    5676     rmescend = stackblock() + strloc;
    5677     if (quotes) {
    5678         rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
    5679         if (rmesc != startp) {
    5680             rmescend = expdest;
    5681             startp = stackblock() + startloc;
    5682         }
    5683     }
    5684     rmescend--;
    5685     str = stackblock() + strloc;
    5686     preglob(str, varflags & VSQUOTE, 0);
    5687 
    5688     /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
     6509    /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
    56896510    zero = subtype >> 1;
    56906511    /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
     
    57066527/*
    57076528 * Add the value of a specialized variable to the stack string.
    5708  */
    5709 static ssize_t
    5710 varvalue(char *name, int varflags, int flags)
    5711 {
     6529 * name parameter (examples):
     6530 * ash -c 'echo $1'      name:'1='
     6531 * ash -c 'echo $qwe'    name:'qwe='
     6532 * ash -c 'echo $$'      name:'$='
     6533 * ash -c 'echo ${$}'    name:'$='
     6534 * ash -c 'echo ${$##q}' name:'$=q'
     6535 * ash -c 'echo ${#$}'   name:'$='
     6536 * note: examples with bad shell syntax:
     6537 * ash -c 'echo ${#$1}'  name:'$=1'
     6538 * ash -c 'echo ${#1#}'  name:'1=#'
     6539 */
     6540static NOINLINE ssize_t
     6541varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
     6542{
     6543    const char *p;
    57126544    int num;
    5713     char *p;
    57146545    int i;
    5715     int sep = 0;
    57166546    int sepq = 0;
    57176547    ssize_t len = 0;
    5718     char **ap;
    5719     int syntax;
     6548    int subtype = varflags & VSTYPE;
     6549    int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
    57206550    int quoted = varflags & VSQUOTE;
    5721     int subtype = varflags & VSTYPE;
    5722     int quotes = flags & (EXP_FULL | EXP_CASE);
    5723 
    5724     if (quoted && (flags & EXP_FULL))
    5725         sep = 1 << CHAR_BIT;
    5726 
    5727     syntax = quoted ? DQSYNTAX : BASESYNTAX;
     6551    int syntax = quoted ? DQSYNTAX : BASESYNTAX;
     6552
    57286553    switch (*name) {
    57296554    case '$':
     
    57426567 numvar:
    57436568        len = cvtnum(num);
    5744         break;
     6569        goto check_1char_name;
    57456570    case '-':
    5746         p = makestrspace(NOPTS, expdest);
     6571        expdest = makestrspace(NOPTS, expdest);
    57476572        for (i = NOPTS - 1; i >= 0; i--) {
    57486573            if (optlist[i]) {
    5749                 USTPUTC(optletters(i), p);
     6574                USTPUTC(optletters(i), expdest);
    57506575                len++;
    57516576            }
    57526577        }
    5753         expdest = p;
     6578 check_1char_name:
     6579#if 0
     6580        /* handles cases similar to ${#$1} */
     6581        if (name[2] != '\0')
     6582            raise_error_syntax("bad substitution");
     6583#endif
    57546584        break;
    5755     case '@':
    5756         if (sep)
     6585    case '@': {
     6586        char **ap;
     6587        int sep;
     6588
     6589        if (quoted && (flags & EXP_FULL)) {
     6590            /* note: this is not meant as PEOF value */
     6591            sep = 1 << CHAR_BIT;
    57576592            goto param;
     6593        }
    57586594        /* fall through */
    57596595    case '*':
    5760         sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
    5761         if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
     6596        sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
     6597        i = SIT(sep, syntax);
     6598        if (quotes && (i == CCTL || i == CBACK))
    57626599            sepq = 1;
    57636600 param:
     
    57656602        if (!ap)
    57666603            return -1;
    5767         while ((p = *ap++)) {
     6604        while ((p = *ap++) != NULL) {
    57686605            size_t partlen;
    57696606
     
    57846621                if (sepq)
    57856622                    STPUTC(CTLESC, q);
     6623                /* note: may put NUL despite sep != 0
     6624                 * (see sep = 1 << CHAR_BIT above) */
    57866625                STPUTC(sep, q);
    57876626                expdest = q;
     
    57896628        }
    57906629        return len;
     6630    } /* case '@' and '*' */
    57916631    case '0':
    57926632    case '1':
     
    57996639    case '8':
    58006640    case '9':
    5801         num = atoi(name);
     6641        num = atoi(name); /* number(name) fails on ${N#str} etc */
    58026642        if (num < 0 || num > shellparam.nparam)
    58036643            return -1;
     
    58056645        goto value;
    58066646    default:
     6647        /* NB: name has form "VAR=..." */
     6648
     6649        /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
     6650         * which should be considered before we check variables. */
     6651        if (var_str_list) {
     6652            unsigned name_len = (strchrnul(name, '=') - name) + 1;
     6653            p = NULL;
     6654            do {
     6655                char *str, *eq;
     6656                str = var_str_list->text;
     6657                eq = strchr(str, '=');
     6658                if (!eq) /* stop at first non-assignment */
     6659                    break;
     6660                eq++;
     6661                if (name_len == (unsigned)(eq - str)
     6662                 && strncmp(str, name, name_len) == 0
     6663                ) {
     6664                    p = eq;
     6665                    /* goto value; - WRONG! */
     6666                    /* think "A=1 A=2 B=$A" */
     6667                }
     6668                var_str_list = var_str_list->next;
     6669            } while (var_str_list);
     6670            if (p)
     6671                goto value;
     6672        }
    58076673        p = lookupvar(name);
    58086674 value:
     
    58266692 */
    58276693static char *
    5828 evalvar(char *p, int flag)
    5829 {
    5830     int subtype;
    5831     int varflags;
     6694evalvar(char *p, int flags, struct strlist *var_str_list)
     6695{
     6696    char varflags;
     6697    char subtype;
     6698    char quoted;
     6699    char easy;
    58326700    char *var;
    58336701    int patloc;
    5834     int c;
    58356702    int startloc;
    58366703    ssize_t varlen;
    5837     int easy;
    5838     int quotes;
    5839     int quoted;
    5840 
    5841     quotes = flag & (EXP_FULL | EXP_CASE);
    5842     varflags = *p++;
     6704
     6705    varflags = (unsigned char) *p++;
    58436706    subtype = varflags & VSTYPE;
    58446707    quoted = varflags & VSQUOTE;
     
    58466709    easy = (!quoted || (*var == '@' && shellparam.nparam));
    58476710    startloc = expdest - (char *)stackblock();
    5848     p = strchr(p, '=') + 1;
     6711    p = strchr(p, '=') + 1; //TODO: use var_end(p)?
    58496712
    58506713 again:
    5851     varlen = varvalue(var, varflags, flag);
     6714    varlen = varvalue(var, varflags, flags, var_str_list);
    58526715    if (varflags & VSNUL)
    58536716        varlen--;
     
    58626725        if (varlen < 0) {
    58636726            argstr(
    5864                 p, flag | EXP_TILDE |
    5865                     (quoted ?  EXP_QWORD : EXP_WORD)
     6727                p,
     6728                flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
     6729                var_str_list
    58666730            );
    58676731            goto end;
     
    58746738    if (subtype == VSASSIGN || subtype == VSQUESTION) {
    58756739        if (varlen < 0) {
    5876             if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) {
     6740            if (subevalvar(p, var, /* strloc: */ 0,
     6741                    subtype, startloc, varflags,
     6742                    /* quotes: */ 0,
     6743                    var_str_list)
     6744            ) {
    58776745                varflags &= ~VSNUL;
    58786746                /*
     
    58996767
    59006768    if (subtype == VSNORMAL) {
    5901         if (!easy)
    5902             goto end;
    5903  record:
    5904         recordregion(startloc, expdest - (char *)stackblock(), quoted);
     6769        if (easy)
     6770            goto record;
    59056771        goto end;
    59066772    }
     
    59126778    case VSTRIMRIGHT:
    59136779    case VSTRIMRIGHTMAX:
     6780#if ENABLE_ASH_BASH_COMPAT
     6781    case VSSUBSTR:
     6782    case VSREPLACE:
     6783    case VSREPLACEALL:
     6784#endif
    59146785        break;
    59156786    default:
     
    59256796        STPUTC('\0', expdest);
    59266797        patloc = expdest - (char *)stackblock();
    5927         if (subevalvar(p, NULL, patloc, subtype,
    5928                 startloc, varflags, quotes) == 0) {
     6798        if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
     6799                startloc, varflags,
     6800//TODO: | EXP_REDIR too? All other such places do it too
     6801                /* quotes: */ flags & (EXP_FULL | EXP_CASE),
     6802                var_str_list)
     6803        ) {
    59296804            int amount = expdest - (
    59306805                (char *)stackblock() + patloc - 1
     
    59346809        /* Remove any recorded regions beyond start of variable */
    59356810        removerecordregions(startloc);
    5936         goto record;
     6811 record:
     6812        recordregion(startloc, expdest - (char *)stackblock(), quoted);
    59376813    }
    59386814
     
    59416817        int nesting = 1;
    59426818        for (;;) {
    5943             c = *p++;
     6819            unsigned char c = *p++;
    59446820            if (c == CTLESC)
    59456821                p++;
     
    59896865            while (p < string + ifsp->endoff) {
    59906866                q = p;
    5991                 if (*p == CTLESC)
     6867                if ((unsigned char)*p == CTLESC)
    59926868                    p++;
    59936869                if (!strchr(ifs, *p)) {
     
    60046880                }
    60056881                *q = '\0';
    6006                 sp = stalloc(sizeof(*sp));
     6882                sp = stzalloc(sizeof(*sp));
    60076883                sp->text = start;
    60086884                *arglist->lastp = sp;
     
    60156891                        }
    60166892                        q = p;
    6017                         if (*p == CTLESC)
     6893                        if ((unsigned char)*p == CTLESC)
    60186894                            p++;
    6019                         if (strchr(ifs, *p) == NULL ) {
     6895                        if (strchr(ifs, *p) == NULL) {
    60206896                            p = q;
    60216897                            break;
    6022                         } else if (strchr(defifs, *p) == NULL) {
     6898                        }
     6899                        if (strchr(defifs, *p) == NULL) {
    60236900                            if (ifsspc) {
    60246901                                p++;
     
    60446921
    60456922 add:
    6046     sp = stalloc(sizeof(*sp));
     6923    sp = stzalloc(sizeof(*sp));
    60476924    sp->text = start;
    60486925    *arglist->lastp = sp;
     
    60766953    struct strlist *sp;
    60776954
    6078     sp = stalloc(sizeof(*sp));
     6955    sp = stzalloc(sizeof(*sp));
    60796956    sp->text = ststrdup(name);
    60806957    *exparg.lastp = sp;
     
    60826959}
    60836960
    6084 static char *expdir;
    6085 
    60866961/*
    60876962 * Do metacharacter (i.e. *, ?, [...]) expansion.
    60886963 */
    60896964static void
    6090 expmeta(char *enddir, char *name)
     6965expmeta(char *expdir, char *enddir, char *name)
    60916966{
    60926967    char *p;
     
    61767051    if (*p == '.')
    61777052        matchdot++;
    6178     while (! intpending && (dp = readdir(dirp)) != NULL) {
    6179         if (dp->d_name[0] == '.' && ! matchdot)
     7053    while (!pending_int && (dp = readdir(dirp)) != NULL) {
     7054        if (dp->d_name[0] == '.' && !matchdot)
    61807055            continue;
    61817056        if (pmatch(start, dp->d_name)) {
     
    61877062                    continue;
    61887063                p[-1] = '/';
    6189                 expmeta(p, endname);
     7064                expmeta(expdir, p, endname);
    61907065            }
    61917066        }
    61927067    }
    61937068    closedir(dirp);
    6194     if (! atend)
     7069    if (!atend)
    61957070        endname[-1] = '/';
    61967071}
     
    62087083    half = len >> 1;
    62097084    p = list;
    6210     for (n = half; --n >= 0; ) {
     7085    for (n = half; --n >= 0;) {
    62117086        q = p;
    62127087        p = p->next;
     
    62617136
    62627137static void
    6263 expandmeta(struct strlist *str, int flag)
     7138expandmeta(struct strlist *str /*, int flag*/)
    62647139{
    62657140    static const char metachars[] ALIGN1 = {
     
    62697144
    62707145    while (str) {
     7146        char *expdir;
    62717147        struct strlist **savelastp;
    62727148        struct strlist *sp;
     
    62857161            expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
    62867162        }
    6287 
    6288         expmeta(expdir, p);
     7163        expmeta(expdir, expdir, p);
    62897164        free(expdir);
    62907165        if (p != str->text)
     
    62977172 nometa:
    62987173            *exparg.lastp = str;
    6299             rmescapes(str->text);
     7174            rmescapes(str->text, 0);
    63007175            exparg.lastp = &str->next;
    63017176        } else {
     
    63267201    ifsfirst.next = NULL;
    63277202    ifslastp = NULL;
    6328     argstr(arg->narg.text, flag);
     7203    argstr(arg->narg.text, flag,
     7204            /* var_str_list: */ arglist ? arglist->list : NULL);
    63297205    p = _STPUTC('\0', expdest);
    63307206    expdest = p - 1;
     
    63417217        *exparg.lastp = NULL;
    63427218        exparg.lastp = &exparg.list;
    6343         expandmeta(exparg.list, flag);
     7219        expandmeta(exparg.list /*, flag*/);
    63447220    } else {
    63457221        if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
    6346             rmescapes(p);
    6347         sp = stalloc(sizeof(*sp));
     7222            rmescapes(p, 0);
     7223        sp = stzalloc(sizeof(*sp));
    63487224        sp->text = p;
    63497225        *exparg.lastp = sp;
     
    63927268    STARTSTACKSTR(expdest);
    63937269    ifslastp = NULL;
    6394     argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
     7270    argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
     7271            /* var_str_list: */ NULL);
    63957272    STACKSTRNUL(expdest);
    63967273    result = patmatch(stackblock(), val);
     
    64047281struct builtincmd {
    64057282    const char *name;
    6406     int (*builtin)(int, char **);
     7283    int (*builtin)(int, char **) FAST_FUNC;
    64077284    /* unsigned flags; */
    64087285};
    64097286#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
     7287/* "regular" builtins always take precedence over commands,
     7288 * regardless of PATH=....%builtin... position */
    64107289#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
    6411 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
     7290#define IS_BUILTIN_ASSIGN(b)  ((b)->name[0] & 4)
    64127291
    64137292struct cmdentry {
    6414     int cmdtype;
     7293    smallint cmdtype;       /* CMDxxx */
    64157294    union param {
    64167295        int index;
     7296        /* index >= 0 for commands without path (slashes) */
     7297        /* (TODO: what exactly does the value mean? PATH position?) */
     7298        /* index == -1 for commands with slashes */
     7299        /* index == (-2 - applet_no) for NOFORK applets */
    64177300        const struct builtincmd *cmd;
    64187301        struct funcnode *func;
     
    64467329 */
    64477330
    6448 #define CMDTABLESIZE 31         /* should be prime */
    6449 #define ARB 1                   /* actual size determined at run time */
    6450 
    64517331struct tblentry {
    64527332    struct tblentry *next;  /* next entry in hash chain */
    64537333    union param param;      /* definition of builtin function */
    6454     short cmdtype;          /* index identifying command */
     7334    smallint cmdtype;       /* CMDxxx */
    64557335    char rehash;            /* if set, cd done since entry created */
    6456     char cmdname[ARB];      /* name of command */
     7336    char cmdname[1];        /* name of command */
    64577337};
    64587338
    6459 static struct tblentry *cmdtable[CMDTABLESIZE];
    6460 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
     7339static struct tblentry **cmdtable;
     7340#define INIT_G_cmdtable() do { \
     7341    cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
     7342} while (0)
     7343
     7344static int builtinloc = -1;     /* index in path of %builtin, or -1 */
     7345
    64617346
    64627347static void
    6463 tryexec(char *cmd, char **argv, char **envp)
     7348tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
    64647349{
    64657350    int repeated = 0;
    64667351
    64677352#if ENABLE_FEATURE_SH_STANDALONE
    6468     if (strchr(cmd, '/') == NULL) {
    6469         const struct bb_applet *a;
    6470 
    6471         a = find_applet_by_name(cmd);
    6472         if (a) {
    6473             if (a->noexec) {
    6474                 current_applet = a;
    6475                 run_current_applet_and_exit(argv);
    6476             }
    6477             /* re-exec ourselves with the new arguments */
    6478             execve(bb_busybox_exec_path, argv, envp);
    6479             /* If they called chroot or otherwise made the binary no longer
    6480              * executable, fall through */
    6481         }
     7353    if (applet_no >= 0) {
     7354        if (APPLET_IS_NOEXEC(applet_no)) {
     7355            clearenv();
     7356            while (*envp)
     7357                putenv(*envp++);
     7358            run_applet_no_and_exit(applet_no, argv);
     7359        }
     7360        /* re-exec ourselves with the new arguments */
     7361        execve(bb_busybox_exec_path, argv, envp);
     7362        /* If they called chroot or otherwise made the binary no longer
     7363         * executable, fall through */
    64827364    }
    64837365#endif
     
    64917373    execve(cmd, argv, envp);
    64927374#endif
    6493     if (repeated++) {
     7375    if (repeated) {
    64947376        free(argv);
    6495     } else if (errno == ENOEXEC) {
     7377        return;
     7378    }
     7379    if (errno == ENOEXEC) {
    64967380        char **ap;
    64977381        char **new;
    64987382
    64997383        for (ap = argv; *ap; ap++)
    6500             ;
    6501         ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
     7384            continue;
     7385        ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
    65027386        ap[1] = cmd;
    65037387        ap[0] = cmd = (char *)DEFAULT_SHELL;
    65047388        ap += 2;
    65057389        argv++;
    6506         while ((*ap++ = *argv++))
    6507             ;
     7390        while ((*ap++ = *argv++) != NULL)
     7391            continue;
    65087392        argv = new;
     7393        repeated++;
    65097394        goto repeat;
    65107395    }
     
    65157400 * have to change the find_command routine as well.
    65167401 */
    6517 #define environment() listvars(VEXPORT, VUNSET, 0)
    6518 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
     7402static void shellexec(char **, const char *, int) NORETURN;
    65197403static void
    65207404shellexec(char **argv, const char *path, int idx)
     
    65247408    char **envp;
    65257409    int exerrno;
    6526 
    6527     clearredir(1);
    6528     envp = environment();
    6529     if (strchr(argv[0], '/')
    65307410#if ENABLE_FEATURE_SH_STANDALONE
    6531      || find_applet_by_name(argv[0])
     7411    int applet_no = -1;
     7412#endif
     7413
     7414    clearredir(/*drop:*/ 1);
     7415    envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
     7416    if (strchr(argv[0], '/') != NULL
     7417#if ENABLE_FEATURE_SH_STANDALONE
     7418     || (applet_no = find_applet_by_name(argv[0])) >= 0
    65327419#endif
    65337420    ) {
    6534         tryexec(argv[0], argv, envp);
     7421        tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
    65357422        e = errno;
    65367423    } else {
    65377424        e = ENOENT;
    6538         while ((cmdname = padvance(&path, argv[0])) != NULL) {
     7425        while ((cmdname = path_advance(&path, argv[0])) != NULL) {
    65397426            if (--idx < 0 && pathopt == NULL) {
    6540                 tryexec(cmdname, argv, envp);
     7427                tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
    65417428                if (errno != ENOENT && errno != ENOTDIR)
    65427429                    e = errno;
     
    65597446    }
    65607447    exitstatus = exerrno;
    6561     TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
    6562         argv[0], e, suppressint ));
     7448    TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
     7449        argv[0], e, suppress_int));
    65637450    ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
    65647451    /* NOTREACHED */
     
    65757462    path = pathval();
    65767463    do {
    6577         name = padvance(&path, cmdp->cmdname);
     7464        name = path_advance(&path, cmdp->cmdname);
    65787465        stunalloc(name);
    65797466    } while (--idx >= 0);
     
    66427529    }
    66437530    if (add && cmdp == NULL) {
    6644         cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
    6645                     + strlen(name) + 1);
    6646         cmdp->next = NULL;
     7531        cmdp = *pp = ckzalloc(sizeof(struct tblentry)
     7532                + strlen(name)
     7533                /* + 1 - already done because
     7534                 * tblentry::cmdname is char[1] */);
     7535        /*cmdp->next = NULL; - ckzalloc did it */
    66477536        cmdp->cmdtype = CMDUNKNOWN;
    66487537        strcpy(cmdp->cmdname, name);
     
    66877576}
    66887577
    6689 static int
    6690 hashcmd(int argc, char **argv)
     7578static int FAST_FUNC
     7579hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    66917580{
    66927581    struct tblentry **pp;
     
    66967585    char *name;
    66977586
    6698     while ((c = nextopt("r")) != '\0') {
     7587    if (nextopt("r") != '\0') {
    66997588        clearcmdentry(0);
    67007589        return 0;
    67017590    }
     7591
    67027592    if (*argptr == NULL) {
    67037593        for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
     
    67097599        return 0;
    67107600    }
     7601
    67117602    c = 0;
    67127603    while ((name = *argptr) != NULL) {
     
    67147605        if (cmdp != NULL
    67157606         && (cmdp->cmdtype == CMDNORMAL
    6716              || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
     7607             || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
     7608        ) {
    67177609            delete_cmd_entry();
     7610        }
    67187611        find_command(name, &entry, DO_ERR, pathval());
    67197612        if (entry.cmdtype == CMDUNKNOWN)
     
    67367629    for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
    67377630        for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
    6738             if (cmdp->cmdtype == CMDNORMAL || (
    6739                 cmdp->cmdtype == CMDBUILTIN &&
    6740                 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
    6741                 builtinloc > 0
    6742             ))
     7631            if (cmdp->cmdtype == CMDNORMAL
     7632             || (cmdp->cmdtype == CMDBUILTIN
     7633                 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
     7634                 && builtinloc > 0)
     7635            ) {
    67437636                cmdp->rehash = 1;
     7637            }
    67447638        }
    67457639    }
     
    67527646 * Called with interrupts off.
    67537647 */
    6754 static void
    6755 changepath(const char *newval)
    6756 {
    6757     const char *old, *new;
     7648static void FAST_FUNC
     7649changepath(const char *new)
     7650{
     7651    const char *old;
     7652    int firstchange;
    67587653    int idx;
    6759     int firstchange;
    67607654    int idx_bltin;
    67617655
    67627656    old = pathval();
    6763     new = newval;
    67647657    firstchange = 9999;     /* assume no change */
    67657658    idx = 0;
     
    67697662            firstchange = idx;
    67707663            if ((*old == '\0' && *new == ':')
    6771              || (*old == ':' && *new == '\0'))
     7664             || (*old == ':' && *new == '\0')
     7665            ) {
    67727666                firstchange++;
     7667            }
    67737668            old = new;      /* ignore subsequent differences */
    67747669        }
     
    67777672        if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
    67787673            idx_bltin = idx;
    6779         if (*new == ':') {
     7674        if (*new == ':')
    67807675            idx++;
    6781         }
    6782         new++, old++;
     7676        new++;
     7677        old++;
    67837678    }
    67847679    if (builtinloc < 0 && idx_bltin >= 0)
     
    68197714#define TBEGIN 27
    68207715#define TEND 28
     7716typedef smallint token_id_t;
    68217717
    68227718/* first char is indicating which tokens mark the end of a list */
     
    68557751};
    68567752
    6857 static const char *
    6858 tokname(int tok)
    6859 {
    6860     static char buf[16];
    6861 
    6862 //try this:
    6863 //if (tok < TSEMI) return tokname_array[tok] + 1;
    6864 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
    6865 //return buf;
    6866 
    6867     if (tok >= TSEMI)
    6868         buf[0] = '"';
    6869     sprintf(buf + (tok >= TSEMI), "%s%c",
    6870             tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
    6871     return buf;
    6872 }
    6873 
    68747753/* Wrapper around strcmp for qsort/bsearch/... */
    68757754static int
     
    69377816        int j = entry.u.index;
    69387817        char *p;
    6939         if (j == -1) {
     7818        if (j < 0) {
    69407819            p = command;
    69417820        } else {
    69427821            do {
    6943                 p = padvance(&path, command);
     7822                p = path_advance(&path, command);
    69447823                stunalloc(p);
    69457824            } while (--j >= 0);
     
    69817860    }
    69827861 out:
    6983     outstr("\n", stdout);
     7862    out1str("\n");
    69847863    return 0;
    69857864}
    69867865
    6987 static int
    6988 typecmd(int argc, char **argv)
     7866static int FAST_FUNC
     7867typecmd(int argc UNUSED_PARAM, char **argv)
    69897868{
    69907869    int i = 1;
     
    69977876        verbose = 0;
    69987877    }
    6999     while (i < argc) {
     7878    while (argv[i]) {
    70007879        err |= describe_command(argv[i++], verbose);
    70017880    }
     
    70047883
    70057884#if ENABLE_ASH_CMDCMD
    7006 static int
    7007 commandcmd(int argc, char **argv)
     7885static int FAST_FUNC
     7886commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    70087887{
    70097888    int c;
     
    70227901            abort();
    70237902#endif
    7024     if (verify)
     7903    /* Mimic bash: just "command -v" doesn't complain, it's a nop */
     7904    if (verify && (*argptr != NULL)) {
    70257905        return describe_command(*argptr, verify - VERIFY_BRIEF);
     7906    }
    70267907
    70277908    return 0;
     
    70327913/* ============ eval.c */
    70337914
    7034 static int funcblocksize;          /* size of structures in function */
    7035 static int funcstringsize;         /* size of strings in node */
    7036 static void *funcblock;            /* block to allocate function from */
    7037 static char *funcstring;           /* block to allocate strings from */
     7915static int funcblocksize;       /* size of structures in function */
     7916static int funcstringsize;      /* size of strings in node */
     7917static void *funcblock;         /* block to allocate function from */
     7918static char *funcstring;        /* block to allocate strings from */
    70387919
    70397920/* flags in argument to evaltree */
    7040 #define EV_EXIT 01              /* exit after evaluating tree */
    7041 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
     7921#define EV_EXIT    01           /* exit after evaluating tree */
     7922#define EV_TESTED  02           /* exit status is checked; ignore -e flag */
    70427923#define EV_BACKCMD 04           /* command executing within back quotes */
    70437924
    7044 static const short nodesize[26] = {
    7045     SHELL_ALIGN(sizeof(struct ncmd)),
    7046     SHELL_ALIGN(sizeof(struct npipe)),
    7047     SHELL_ALIGN(sizeof(struct nredir)),
    7048     SHELL_ALIGN(sizeof(struct nredir)),
    7049     SHELL_ALIGN(sizeof(struct nredir)),
    7050     SHELL_ALIGN(sizeof(struct nbinary)),
    7051     SHELL_ALIGN(sizeof(struct nbinary)),
    7052     SHELL_ALIGN(sizeof(struct nbinary)),
    7053     SHELL_ALIGN(sizeof(struct nif)),
    7054     SHELL_ALIGN(sizeof(struct nbinary)),
    7055     SHELL_ALIGN(sizeof(struct nbinary)),
    7056     SHELL_ALIGN(sizeof(struct nfor)),
    7057     SHELL_ALIGN(sizeof(struct ncase)),
    7058     SHELL_ALIGN(sizeof(struct nclist)),
    7059     SHELL_ALIGN(sizeof(struct narg)),
    7060     SHELL_ALIGN(sizeof(struct narg)),
    7061     SHELL_ALIGN(sizeof(struct nfile)),
    7062     SHELL_ALIGN(sizeof(struct nfile)),
    7063     SHELL_ALIGN(sizeof(struct nfile)),
    7064     SHELL_ALIGN(sizeof(struct nfile)),
    7065     SHELL_ALIGN(sizeof(struct nfile)),
    7066     SHELL_ALIGN(sizeof(struct ndup)),
    7067     SHELL_ALIGN(sizeof(struct ndup)),
    7068     SHELL_ALIGN(sizeof(struct nhere)),
    7069     SHELL_ALIGN(sizeof(struct nhere)),
    7070     SHELL_ALIGN(sizeof(struct nnot)),
     7925static const uint8_t nodesize[N_NUMBER] = {
     7926    [NCMD     ] = SHELL_ALIGN(sizeof(struct ncmd)),
     7927    [NPIPE    ] = SHELL_ALIGN(sizeof(struct npipe)),
     7928    [NREDIR   ] = SHELL_ALIGN(sizeof(struct nredir)),
     7929    [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
     7930    [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
     7931    [NAND     ] = SHELL_ALIGN(sizeof(struct nbinary)),
     7932    [NOR      ] = SHELL_ALIGN(sizeof(struct nbinary)),
     7933    [NSEMI    ] = SHELL_ALIGN(sizeof(struct nbinary)),
     7934    [NIF      ] = SHELL_ALIGN(sizeof(struct nif)),
     7935    [NWHILE   ] = SHELL_ALIGN(sizeof(struct nbinary)),
     7936    [NUNTIL   ] = SHELL_ALIGN(sizeof(struct nbinary)),
     7937    [NFOR     ] = SHELL_ALIGN(sizeof(struct nfor)),
     7938    [NCASE    ] = SHELL_ALIGN(sizeof(struct ncase)),
     7939    [NCLIST   ] = SHELL_ALIGN(sizeof(struct nclist)),
     7940    [NDEFUN   ] = SHELL_ALIGN(sizeof(struct narg)),
     7941    [NARG     ] = SHELL_ALIGN(sizeof(struct narg)),
     7942    [NTO      ] = SHELL_ALIGN(sizeof(struct nfile)),
     7943#if ENABLE_ASH_BASH_COMPAT
     7944    [NTO2     ] = SHELL_ALIGN(sizeof(struct nfile)),
     7945#endif
     7946    [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
     7947    [NFROM    ] = SHELL_ALIGN(sizeof(struct nfile)),
     7948    [NFROMTO  ] = SHELL_ALIGN(sizeof(struct nfile)),
     7949    [NAPPEND  ] = SHELL_ALIGN(sizeof(struct nfile)),
     7950    [NTOFD    ] = SHELL_ALIGN(sizeof(struct ndup)),
     7951    [NFROMFD  ] = SHELL_ALIGN(sizeof(struct ndup)),
     7952    [NHERE    ] = SHELL_ALIGN(sizeof(struct nhere)),
     7953    [NXHERE   ] = SHELL_ALIGN(sizeof(struct nhere)),
     7954    [NNOT     ] = SHELL_ALIGN(sizeof(struct nnot)),
    70717955};
    70727956
     
    71388022        break;
    71398023    case NTO:
     8024#if ENABLE_ASH_BASH_COMPAT
     8025    case NTO2:
     8026#endif
    71408027    case NCLOBBER:
    71418028    case NFROM:
     
    72098096    case NPIPE:
    72108097        new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
    7211         new->npipe.backgnd = n->npipe.backgnd;
     8098        new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
    72128099        break;
    72138100    case NREDIR:
     
    72518138        break;
    72528139    case NTO:
     8140#if ENABLE_ASH_BASH_COMPAT
     8141    case NTO2:
     8142#endif
    72538143    case NCLOBBER:
    72548144    case NFROM:
     
    73168206}
    73178207
    7318 static int evalskip;            /* set if we are skipping commands */
    7319 /* reasons for skipping commands (see comment on breakcmd routine) */
     8208/* Reasons for skipping commands (see comment on breakcmd routine) */
    73208209#define SKIPBREAK      (1 << 0)
    73218210#define SKIPCONT       (1 << 1)
     
    73238212#define SKIPFILE       (1 << 3)
    73248213#define SKIPEVAL       (1 << 4)
     8214static smallint evalskip;       /* set to SKIPxxx if we are skipping commands */
    73258215static int skipcount;           /* number of levels to skip */
    73268216static int funcnest;            /* depth of function calls */
    7327 
    7328 /* forward decl way out to parsing code - dotrap needs it */
     8217static int loopnest;            /* current loop nesting level */
     8218
     8219/* Forward decl way out to parsing code - dotrap needs it */
    73298220static int evalstring(char *s, int mask);
    73308221
    7331 /*
    7332  * Called to execute a trap.  Perhaps we should avoid entering new trap
    7333  * handlers while we are executing a trap handler.
     8222/* Called to execute a trap.
     8223 * Single callsite - at the end of evaltree().
     8224 * If we return non-zero, evaltree raises EXEXIT exception.
     8225 *
     8226 * Perhaps we should avoid entering new trap handlers
     8227 * while we are executing a trap handler. [is it a TODO?]
    73348228 */
    73358229static int
    73368230dotrap(void)
    73378231{
    7338     char *p;
    7339     char *q;
    7340     int i;
    7341     int savestatus;
    7342     int skip = 0;
     8232    uint8_t *g;
     8233    int sig;
     8234    uint8_t savestatus;
    73438235
    73448236    savestatus = exitstatus;
    7345     pendingsig = 0;
     8237    pending_sig = 0;
    73468238    xbarrier();
    73478239
    7348     for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
    7349         if (!*q)
     8240    TRACE(("dotrap entered\n"));
     8241    for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
     8242        int want_exexit;
     8243        char *t;
     8244
     8245        if (*g == 0)
    73508246            continue;
    7351         *q = '\0';
    7352 
    7353         p = trap[i + 1];
    7354         if (!p)
     8247        t = trap[sig];
     8248        /* non-trapped SIGINT is handled separately by raise_interrupt,
     8249         * don't upset it by resetting gotsig[SIGINT-1] */
     8250        if (sig == SIGINT && !t)
    73558251            continue;
    7356         skip = evalstring(p, SKIPEVAL);
     8252
     8253        TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
     8254        *g = 0;
     8255        if (!t)
     8256            continue;
     8257        want_exexit = evalstring(t, SKIPEVAL);
    73578258        exitstatus = savestatus;
    7358         if (skip)
    7359             break;
    7360     }
    7361 
    7362     return skip;
     8259        if (want_exexit) {
     8260            TRACE(("dotrap returns %d\n", want_exexit));
     8261            return want_exexit;
     8262        }
     8263    }
     8264
     8265    TRACE(("dotrap returns 0\n"));
     8266    return 0;
    73638267}
    73648268
     
    73818285evaltree(union node *n, int flags)
    73828286{
     8287    struct jmploc *volatile savehandler = exception_handler;
     8288    struct jmploc jmploc;
    73838289    int checkexit = 0;
    73848290    void (*evalfn)(union node *, int);
    7385     unsigned isor;
    73868291    int status;
     8292    int int_level;
     8293
     8294    SAVE_INT(int_level);
     8295
    73878296    if (n == NULL) {
    73888297        TRACE(("evaltree(NULL) called\n"));
    7389         goto out;
    7390     }
    7391     TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
    7392             getpid(), n, n->type, flags));
     8298        goto out1;
     8299    }
     8300    TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
     8301
     8302    exception_handler = &jmploc;
     8303    {
     8304        int err = setjmp(jmploc.loc);
     8305        if (err) {
     8306            /* if it was a signal, check for trap handlers */
     8307            if (exception_type == EXSIG) {
     8308                TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
     8309                        exception_type, err));
     8310                goto out;
     8311            }
     8312            /* continue on the way out */
     8313            TRACE(("exception %d in evaltree, propagating err=%d\n",
     8314                    exception_type, err));
     8315            exception_handler = savehandler;
     8316            longjmp(exception_handler->loc, err);
     8317        }
     8318    }
     8319
    73938320    switch (n->type) {
    73948321    default:
    73958322#if DEBUG
    73968323        out1fmt("Node type = %d\n", n->type);
    7397         fflush(stdout);
     8324        fflush_all();
    73988325        break;
    73998326#endif
     
    74098336            status = exitstatus;
    74108337        }
    7411         popredir(0);
     8338        popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
    74128339        goto setstatus;
    74138340    case NCMD:
     
    74368363    case NAND:
    74378364    case NOR:
    7438     case NSEMI:
     8365    case NSEMI: {
     8366
    74398367#if NAND + 1 != NOR
    74408368#error NAND + 1 != NOR
     
    74438371#error NOR + 1 != NSEMI
    74448372#endif
    7445         isor = n->type - NAND;
     8373        unsigned is_or = n->type - NAND;
    74468374        evaltree(
    74478375            n->nbinary.ch1,
    7448             (flags | ((isor >> 1) - 1)) & EV_TESTED
     8376            (flags | ((is_or >> 1) - 1)) & EV_TESTED
    74498377        );
    7450         if (!exitstatus == isor)
     8378        if (!exitstatus == is_or)
    74518379            break;
    74528380        if (!evalskip) {
     
    74598387        }
    74608388        break;
     8389    }
    74618390    case NIF:
    74628391        evaltree(n->nif.test, EV_TESTED);
     
    74668395            n = n->nif.ifpart;
    74678396            goto evaln;
    7468         } else if (n->nif.elsepart) {
     8397        }
     8398        if (n->nif.elsepart) {
    74698399            n = n->nif.elsepart;
    74708400            goto evaln;
     
    74798409        break;
    74808410    }
     8411
    74818412 out:
    7482     if ((checkexit & exitstatus))
     8413    exception_handler = savehandler;
     8414
     8415 out1:
     8416    /* Order of checks below is important:
     8417     * signal handlers trigger before exit caused by "set -e".
     8418     */
     8419    if (pending_sig && dotrap())
     8420        goto exexit;
     8421    if (checkexit & exitstatus)
    74838422        evalskip |= SKIPEVAL;
    7484     else if (pendingsig && dotrap())
    7485         goto exexit;
    74868423
    74878424    if (flags & EV_EXIT) {
     
    74898426        raise_exception(EXEXIT);
    74908427    }
     8428
     8429    RESTORE_INT(int_level);
     8430    TRACE(("leaving evaltree (no interrupts)\n"));
    74918431}
    74928432
     
    74958435#endif
    74968436void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
    7497 
    7498 static int loopnest;            /* current loop nesting level */
    74998437
    75008438static void
     
    75438481
    75448482    setstackmark(&smark);
     8483    arglist.list = NULL;
    75458484    arglist.lastp = &arglist.list;
    75468485    for (argp = n->nfor.args; argp; argp = argp->narg.next) {
     
    75828521
    75838522    setstackmark(&smark);
     8523    arglist.list = NULL;
    75848524    arglist.lastp = &arglist.list;
    75858525    expandarg(n->ncase.expr, &arglist, EXP_TILDE);
     
    76108550
    76118551    expredir(n->nredir.redirect);
    7612     if (!backgnd && flags & EV_EXIT && !trap[0])
     8552    if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
    76138553        goto nofork;
    76148554    INT_OFF;
    7615     jp = makejob(n, 1);
     8555    jp = makejob(/*n,*/ 1);
    76168556    if (forkshell(jp, n, backgnd) == 0) {
     8557        /* child */
    76178558        INT_ON;
    76188559        flags |= EV_EXIT;
    76198560        if (backgnd)
    7620             flags &=~ EV_TESTED;
     8561            flags &= ~EV_TESTED;
    76218562 nofork:
    76228563        redirect(n->nredir.redirect, 0);
     
    76258566    }
    76268567    status = 0;
    7627     if (! backgnd)
     8568    if (!backgnd)
    76288569        status = waitforjob(jp);
    76298570    exitstatus = status;
     
    76438584        struct arglist fn;
    76448585
    7645         memset(&fn, 0, sizeof(fn));
     8586        fn.list = NULL;
    76468587        fn.lastp = &fn.list;
    76478588        switch (redir->type) {
     
    76498590        case NFROM:
    76508591        case NTO:
     8592#if ENABLE_ASH_BASH_COMPAT
     8593        case NTO2:
     8594#endif
    76518595        case NCLOBBER:
    76528596        case NAPPEND:
    76538597            expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
     8598#if ENABLE_ASH_BASH_COMPAT
     8599 store_expfname:
     8600#endif
    76548601            redir->nfile.expfname = fn.list->text;
    76558602            break;
    76568603        case NFROMFD:
    7657         case NTOFD:
     8604        case NTOFD: /* >& */
    76588605            if (redir->ndup.vname) {
    76598606                expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
    76608607                if (fn.list == NULL)
    76618608                    ash_msg_and_raise_error("redir error");
     8609#if ENABLE_ASH_BASH_COMPAT
     8610//FIXME: we used expandarg with different args!
     8611                if (!isdigit_str9(fn.list->text)) {
     8612                    /* >&file, not >&fd */
     8613                    if (redir->nfile.fd != 1) /* 123>&file - BAD */
     8614                        ash_msg_and_raise_error("redir error");
     8615                    redir->type = NTO2;
     8616                    goto store_expfname;
     8617                }
     8618#endif
    76628619                fixredir(redir, fn.list->text, 1);
    76638620            }
     
    76888645    flags |= EV_EXIT;
    76898646    INT_OFF;
    7690     jp = makejob(n, pipelen);
     8647    jp = makejob(/*n,*/ pipelen);
    76918648    prevfd = -1;
    76928649    for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
     
    76998656            }
    77008657        }
    7701         if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
     8658        if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
    77028659            INT_ON;
    77038660            if (pip[1] >= 0) {
     
    77188675            close(prevfd);
    77198676        prevfd = pip[0];
    7720         close(pip[1]);
    7721     }
    7722     if (n->npipe.backgnd == 0) {
     8677        /* Don't want to trigger debugging */
     8678        if (pip[1] != -1)
     8679            close(pip[1]);
     8680    }
     8681    if (n->npipe.pipe_backgnd == 0) {
    77238682        exitstatus = waitforjob(jp);
    77248683        TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
     
    77338692setinteractive(int on)
    77348693{
    7735     static int is_interactive;
     8694    static smallint is_interactive;
    77368695
    77378696    if (++on == is_interactive)
     
    77478706
    77488707        if (!did_banner) {
    7749             out1fmt(
    7750                 "\n\n"
    7751                 "%s built-in shell (ash)\n"
     8708            /* note: ash and hush share this string */
     8709            out1fmt("\n\n%s %s\n"
    77528710                "Enter 'help' for a list of built-in commands."
    77538711                "\n\n",
    7754                 bb_banner);
     8712                bb_banner,
     8713                "built-in shell (ash)"
     8714            );
    77558715            did_banner = 1;
    77568716        }
     
    77588718#endif
    77598719}
    7760 
    7761 #if ENABLE_FEATURE_EDITING_VI
    7762 #define setvimode(on) do { \
    7763     if (on) line_input_state->flags |= VI_MODE; \
    7764     else line_input_state->flags &= ~VI_MODE; \
    7765 } while (0)
    7766 #else
    7767 #define setvimode(on) viflag = 0   /* forcibly keep the option off */
    7768 #endif
    77698720
    77708721static void
     
    77768727    setinteractive(iflag);
    77778728    setjobctl(mflag);
    7778     setvimode(viflag);
     8729#if ENABLE_FEATURE_EDITING_VI
     8730    if (viflag)
     8731        line_input_state->flags |= VI_MODE;
     8732    else
     8733        line_input_state->flags &= ~VI_MODE;
     8734#else
     8735    viflag = 0; /* forcibly keep the option off */
     8736#endif
    77798737}
    77808738
     
    77948752        localvars = lvp->next;
    77958753        vp = lvp->vp;
    7796         TRACE(("poplocalvar %s", vp ? vp->text : "-"));
     8754        TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
    77978755        if (vp == NULL) {       /* $- saved */
    77988756            memcpy(optlist, lvp->text, sizeof(optlist));
     
    78008758            optschanged();
    78018759        } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
    7802             unsetvar(vp->text);
     8760            unsetvar(vp->var_text);
    78038761        } else {
    7804             if (vp->func)
    7805                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
     8762            if (vp->var_func)
     8763                vp->var_func(var_end(lvp->text));
    78068764            if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
    7807                 free((char*)vp->text);
     8765                free((char*)vp->var_text);
    78088766            vp->flags = lvp->flags;
    7809             vp->text = lvp->text;
     8767            vp->var_text = lvp->text;
    78108768        }
    78118769        free(lvp);
     
    78328790    exception_handler = &jmploc;
    78338791    localvars = NULL;
    7834     shellparam.malloc = 0;
     8792    shellparam.malloced = 0;
    78358793    func->count++;
    78368794    funcnest++;
     
    78438801#endif
    78448802    evaltree(&func->n, flags & EV_TESTED);
    7845 funcdone:
     8803 funcdone:
    78468804    INT_OFF;
    78478805    funcnest--;
     
    79068864
    79078865    INT_OFF;
    7908     lvp = ckmalloc(sizeof(struct localvar));
     8866    lvp = ckzalloc(sizeof(struct localvar));
    79098867    if (LONE_DASH(name)) {
    79108868        char *p;
     
    79268884            lvp->flags = VUNSET;
    79278885        } else {
    7928             lvp->text = vp->text;
     8886            lvp->text = vp->var_text;
    79298887            lvp->flags = vp->flags;
    79308888            vp->flags |= VSTRFIXED|VTEXTFIXED;
     
    79428900 * The "local" command.
    79438901 */
    7944 static int
    7945 localcmd(int argc, char **argv)
     8902static int FAST_FUNC
     8903localcmd(int argc UNUSED_PARAM, char **argv)
    79468904{
    79478905    char *name;
     
    79548912}
    79558913
    7956 static int
    7957 falsecmd(int argc, char **argv)
     8914static int FAST_FUNC
     8915falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    79588916{
    79598917    return 1;
    79608918}
    79618919
    7962 static int
    7963 truecmd(int argc, char **argv)
     8920static int FAST_FUNC
     8921truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    79648922{
    79658923    return 0;
    79668924}
    79678925
    7968 static int
    7969 execcmd(int argc, char **argv)
    7970 {
    7971     if (argc > 1) {
     8926static int FAST_FUNC
     8927execcmd(int argc UNUSED_PARAM, char **argv)
     8928{
     8929    if (argv[1]) {
    79728930        iflag = 0;              /* exit on error */
    79738931        mflag = 0;
     
    79818939 * The return command.
    79828940 */
    7983 static int
    7984 returncmd(int argc, char **argv)
     8941static int FAST_FUNC
     8942returncmd(int argc UNUSED_PARAM, char **argv)
    79858943{
    79868944    /*
     
    79938951
    79948952/* Forward declarations for builtintab[] */
    7995 static int breakcmd(int, char **);
    7996 static int dotcmd(int, char **);
    7997 static int evalcmd(int, char **);
    7998 #if ENABLE_ASH_BUILTIN_ECHO
    7999 static int echocmd(int, char **);
    8000 #endif
    8001 #if ENABLE_ASH_BUILTIN_TEST
    8002 static int testcmd(int, char **);
    8003 #endif
    8004 static int exitcmd(int, char **);
    8005 static int exportcmd(int, char **);
     8953static int breakcmd(int, char **) FAST_FUNC;
     8954static int dotcmd(int, char **) FAST_FUNC;
     8955static int evalcmd(int, char **) FAST_FUNC;
     8956static int exitcmd(int, char **) FAST_FUNC;
     8957static int exportcmd(int, char **) FAST_FUNC;
    80068958#if ENABLE_ASH_GETOPTS
    8007 static int getoptscmd(int, char **);
     8959static int getoptscmd(int, char **) FAST_FUNC;
    80088960#endif
    80098961#if !ENABLE_FEATURE_SH_EXTRA_QUIET
    8010 static int helpcmd(int argc, char **argv);
    8011 #endif
    8012 #if ENABLE_ASH_MATH_SUPPORT
    8013 static int letcmd(int, char **);
    8014 #endif
    8015 static int readcmd(int, char **);
    8016 static int setcmd(int, char **);
    8017 static int shiftcmd(int, char **);
    8018 static int timescmd(int, char **);
    8019 static int trapcmd(int, char **);
    8020 static int umaskcmd(int, char **);
    8021 static int unsetcmd(int, char **);
    8022 static int ulimitcmd(int, char **);
     8962static int helpcmd(int, char **) FAST_FUNC;
     8963#endif
     8964#if ENABLE_SH_MATH_SUPPORT
     8965static int letcmd(int, char **) FAST_FUNC;
     8966#endif
     8967static int readcmd(int, char **) FAST_FUNC;
     8968static int setcmd(int, char **) FAST_FUNC;
     8969static int shiftcmd(int, char **) FAST_FUNC;
     8970static int timescmd(int, char **) FAST_FUNC;
     8971static int trapcmd(int, char **) FAST_FUNC;
     8972static int umaskcmd(int, char **) FAST_FUNC;
     8973static int unsetcmd(int, char **) FAST_FUNC;
     8974static int ulimitcmd(int, char **) FAST_FUNC;
    80238975
    80248976#define BUILTIN_NOSPEC          "0"
     
    80318983#define BUILTIN_SPEC_REG_ASSG   "7"
    80328984
    8033 /* make sure to keep these in proper order since it is searched via bsearch() */
     8985/* Stubs for calling non-FAST_FUNC's */
     8986#if ENABLE_ASH_BUILTIN_ECHO
     8987static int FAST_FUNC echocmd(int argc, char **argv)   { return echo_main(argc, argv); }
     8988#endif
     8989#if ENABLE_ASH_BUILTIN_PRINTF
     8990static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
     8991#endif
     8992#if ENABLE_ASH_BUILTIN_TEST
     8993static int FAST_FUNC testcmd(int argc, char **argv)   { return test_main(argc, argv); }
     8994#endif
     8995
     8996/* Keep these in proper order since it is searched via bsearch() */
    80348997static const struct builtincmd builtintab[] = {
    8035     { BUILTIN_SPEC_REG      ".", dotcmd },
    8036     { BUILTIN_SPEC_REG      ":", truecmd },
     8998    { BUILTIN_SPEC_REG      "."       , dotcmd    },
     8999    { BUILTIN_SPEC_REG      ":"       , truecmd    },
    80379000#if ENABLE_ASH_BUILTIN_TEST
    8038     { BUILTIN_REGULAR   "[", testcmd },
    8039     { BUILTIN_REGULAR   "[[", testcmd },
     9001    { BUILTIN_REGULAR       "["       , testcmd    },
     9002#if ENABLE_ASH_BASH_COMPAT
     9003    { BUILTIN_REGULAR       "[["      , testcmd    },
     9004#endif
    80409005#endif
    80419006#if ENABLE_ASH_ALIAS
    8042     { BUILTIN_REG_ASSG      "alias", aliascmd },
     9007    { BUILTIN_REG_ASSG      "alias"   , aliascmd  },
    80439008#endif
    80449009#if JOBS
    8045     { BUILTIN_REGULAR       "bg", fg_bgcmd },
    8046 #endif
    8047     { BUILTIN_SPEC_REG      "break", breakcmd },
    8048     { BUILTIN_REGULAR       "cd", cdcmd },
    8049     { BUILTIN_NOSPEC        "chdir", cdcmd },
     9010    { BUILTIN_REGULAR       "bg"      , fg_bgcmd  },
     9011#endif
     9012    { BUILTIN_SPEC_REG      "break"   , breakcmd  },
     9013    { BUILTIN_REGULAR       "cd"      , cdcmd      },
     9014    { BUILTIN_NOSPEC        "chdir"   , cdcmd      },
    80509015#if ENABLE_ASH_CMDCMD
    8051     { BUILTIN_REGULAR       "command", commandcmd },
    8052 #endif
    8053     { BUILTIN_SPEC_REG      "continue", breakcmd },
     9016    { BUILTIN_REGULAR       "command" , commandcmd },
     9017#endif
     9018    { BUILTIN_SPEC_REG      "continue", breakcmd   },
    80549019#if ENABLE_ASH_BUILTIN_ECHO
    8055     { BUILTIN_REGULAR       "echo", echocmd },
    8056 #endif
    8057     { BUILTIN_SPEC_REG      "eval", evalcmd },
    8058     { BUILTIN_SPEC_REG      "exec", execcmd },
    8059     { BUILTIN_SPEC_REG      "exit", exitcmd },
    8060     { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
    8061     { BUILTIN_REGULAR       "false", falsecmd },
     9020    { BUILTIN_REGULAR       "echo"    , echocmd    },
     9021#endif
     9022    { BUILTIN_SPEC_REG      "eval"    , evalcmd    },
     9023    { BUILTIN_SPEC_REG      "exec"    , execcmd    },
     9024    { BUILTIN_SPEC_REG      "exit"    , exitcmd    },
     9025    { BUILTIN_SPEC_REG_ASSG "export"  , exportcmd },
     9026    { BUILTIN_REGULAR       "false"   , falsecmd  },
    80629027#if JOBS
    8063     { BUILTIN_REGULAR       "fg", fg_bgcmd },
     9028    { BUILTIN_REGULAR       "fg"      , fg_bgcmd  },
    80649029#endif
    80659030#if ENABLE_ASH_GETOPTS
    8066     { BUILTIN_REGULAR       "getopts", getoptscmd },
    8067 #endif
    8068     { BUILTIN_NOSPEC        "hash", hashcmd },
     9031    { BUILTIN_REGULAR       "getopts" , getoptscmd },
     9032#endif
     9033    { BUILTIN_NOSPEC        "hash"    , hashcmd    },
    80699034#if !ENABLE_FEATURE_SH_EXTRA_QUIET
    8070     { BUILTIN_NOSPEC        "help", helpcmd },
     9035    { BUILTIN_NOSPEC        "help"    , helpcmd    },
    80719036#endif
    80729037#if JOBS
    8073     { BUILTIN_REGULAR       "jobs", jobscmd },
    8074     { BUILTIN_REGULAR       "kill", killcmd },
    8075 #endif
    8076 #if ENABLE_ASH_MATH_SUPPORT
    8077     { BUILTIN_NOSPEC        "let", letcmd },
    8078 #endif
    8079     { BUILTIN_ASSIGN        "local", localcmd },
    8080     { BUILTIN_NOSPEC        "pwd", pwdcmd },
    8081     { BUILTIN_REGULAR       "read", readcmd },
    8082     { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
    8083     { BUILTIN_SPEC_REG      "return", returncmd },
    8084     { BUILTIN_SPEC_REG      "set", setcmd },
    8085     { BUILTIN_SPEC_REG      "shift", shiftcmd },
    8086     { BUILTIN_SPEC_REG      "source", dotcmd },
     9038    { BUILTIN_REGULAR       "jobs"    , jobscmd    },
     9039    { BUILTIN_REGULAR       "kill"    , killcmd    },
     9040#endif
     9041#if ENABLE_SH_MATH_SUPPORT
     9042    { BUILTIN_NOSPEC        "let"     , letcmd     },
     9043#endif
     9044    { BUILTIN_ASSIGN        "local"   , localcmd   },
     9045#if ENABLE_ASH_BUILTIN_PRINTF
     9046    { BUILTIN_REGULAR       "printf"  , printfcmd  },
     9047#endif
     9048    { BUILTIN_NOSPEC        "pwd"     , pwdcmd     },
     9049    { BUILTIN_REGULAR       "read"    , readcmd    },
     9050    { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd  },
     9051    { BUILTIN_SPEC_REG      "return"  , returncmd  },
     9052    { BUILTIN_SPEC_REG      "set"     , setcmd     },
     9053    { BUILTIN_SPEC_REG      "shift"   , shiftcmd   },
     9054#if ENABLE_ASH_BASH_COMPAT
     9055    { BUILTIN_SPEC_REG      "source"  , dotcmd     },
     9056#endif
    80879057#if ENABLE_ASH_BUILTIN_TEST
    8088     { BUILTIN_REGULAR   "test", testcmd },
    8089 #endif
    8090     { BUILTIN_SPEC_REG      "times", timescmd },
    8091     { BUILTIN_SPEC_REG      "trap", trapcmd },
    8092     { BUILTIN_REGULAR       "true", truecmd },
    8093     { BUILTIN_NOSPEC        "type", typecmd },
    8094     { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
    8095     { BUILTIN_REGULAR       "umask", umaskcmd },
     9058    { BUILTIN_REGULAR       "test"    , testcmd    },
     9059#endif
     9060    { BUILTIN_SPEC_REG      "times"   , timescmd  },
     9061    { BUILTIN_SPEC_REG      "trap"    , trapcmd    },
     9062    { BUILTIN_REGULAR       "true"    , truecmd    },
     9063    { BUILTIN_NOSPEC        "type"    , typecmd    },
     9064    { BUILTIN_NOSPEC        "ulimit"  , ulimitcmd },
     9065    { BUILTIN_REGULAR       "umask"   , umaskcmd  },
    80969066#if ENABLE_ASH_ALIAS
    8097     { BUILTIN_REGULAR       "unalias", unaliascmd },
    8098 #endif
    8099     { BUILTIN_SPEC_REG      "unset", unsetcmd },
    8100     { BUILTIN_REGULAR       "wait", waitcmd },
     9067    { BUILTIN_REGULAR       "unalias" , unaliascmd },
     9068#endif
     9069    { BUILTIN_SPEC_REG      "unset"   , unsetcmd  },
     9070    { BUILTIN_REGULAR       "wait"    , waitcmd    },
    81019071};
    81029072
    8103 
    8104 #define COMMANDCMD (builtintab + 5 + \
    8105     2 * ENABLE_ASH_BUILTIN_TEST + \
    8106     ENABLE_ASH_ALIAS + \
    8107     ENABLE_ASH_JOB_CONTROL)
    8108 #define EXECCMD (builtintab + 7 + \
    8109     2 * ENABLE_ASH_BUILTIN_TEST + \
    8110     ENABLE_ASH_ALIAS + \
    8111     ENABLE_ASH_JOB_CONTROL + \
    8112     ENABLE_ASH_CMDCMD + \
    8113     ENABLE_ASH_BUILTIN_ECHO)
     9073/* Should match the above table! */
     9074#define COMMANDCMD (builtintab + \
     9075    2 + \
     9076    1 * ENABLE_ASH_BUILTIN_TEST + \
     9077    1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
     9078    1 * ENABLE_ASH_ALIAS + \
     9079    1 * ENABLE_ASH_JOB_CONTROL + \
     9080    3)
     9081#define EXECCMD (builtintab + \
     9082    2 + \
     9083    1 * ENABLE_ASH_BUILTIN_TEST + \
     9084    1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
     9085    1 * ENABLE_ASH_ALIAS + \
     9086    1 * ENABLE_ASH_JOB_CONTROL + \
     9087    3 + \
     9088    1 * ENABLE_ASH_CMDCMD + \
     9089    1 + \
     9090    ENABLE_ASH_BUILTIN_ECHO + \
     9091    1)
    81149092
    81159093/*
     
    81319109 * Execute a simple command.
    81329110 */
    8133 static int back_exitstatus; /* exit status of backquoted command */
    81349111static int
    81359112isassignment(const char *p)
     
    81409117    return *q == '=';
    81419118}
    8142 static int
    8143 bltincmd(int argc, char **argv)
     9119static int FAST_FUNC
     9120bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    81449121{
    81459122    /* Preserve exitstatus of a previous possible redirection
     
    81509127evalcommand(union node *cmd, int flags)
    81519128{
    8152     static const struct builtincmd bltin = {
    8153         "\0\0", bltincmd
     9129    static const struct builtincmd null_bltin = {
     9130        "\0\0", bltincmd /* why three NULs? */
    81549131    };
    81559132    struct stackmark smark;
     
    81659142    const char *path;
    81669143    int spclbltin;
    8167     int cmd_is_exec;
    81689144    int status;
    81699145    char **nargv;
    81709146    struct builtincmd *bcmd;
    8171     int pseudovarflag = 0;
     9147    smallint cmd_is_exec;
     9148    smallint pseudovarflag = 0;
    81729149
    81739150    /* First expand the arguments. */
     
    81779154
    81789155    cmdentry.cmdtype = CMDBUILTIN;
    8179     cmdentry.u.cmd = &bltin;
     9156    cmdentry.u.cmd = &null_bltin;
    81809157    varlist.lastp = &varlist.list;
    81819158    *varlist.lastp = NULL;
     
    82179194    status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
    82189195
    8219     path = vpath.text;
     9196    path = vpath.var_text;
    82209197    for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
    82219198        struct strlist **spp;
     
    82309207         */
    82319208        p = (*spp)->text;
    8232         if (varequal(p, path))
     9209        if (varcmp(p, path) == 0)
    82339210            path = p;
    82349211    }
     
    82379214    if (xflag) {
    82389215        int n;
    8239         const char *p = " %s";
    8240 
    8241         p++;
    8242         dprintf(preverrout_fd, p, expandstr(ps4val()));
    8243 
     9216        const char *p = " %s" + 1;
     9217
     9218        fdprintf(preverrout_fd, p, expandstr(ps4val()));
    82449219        sp = varlist.list;
    82459220        for (n = 0; n < 2; n++) {
    82469221            while (sp) {
    8247                 dprintf(preverrout_fd, p, sp->text);
     9222                fdprintf(preverrout_fd, p, sp->text);
    82489223                sp = sp->next;
    8249                 if (*p == '%') {
    8250                     p--;
    8251                 }
     9224                p = " %s";
    82529225            }
    82539226            sp = arglist.list;
    82549227        }
    8255         full_write(preverrout_fd, "\n", 1);
     9228        safe_write(preverrout_fd, "\n", 1);
    82569229    }
    82579230
     
    82699242            find_command(argv[0], &cmdentry, cmd_flag, path);
    82709243            if (cmdentry.cmdtype == CMDUNKNOWN) {
     9244                flush_stdout_stderr();
    82719245                status = 127;
    8272                 flush_stderr();
    82739246                goto bail;
    82749247            }
     
    82809253                spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
    82819254            if (cmdentry.u.cmd == EXECCMD)
    8282                 cmd_is_exec++;
     9255                cmd_is_exec = 1;
    82839256#if ENABLE_ASH_CMDCMD
    82849257            if (cmdentry.u.cmd == COMMANDCMD) {
     
    83079280    /* Execute the command. */
    83089281    switch (cmdentry.cmdtype) {
    8309     default:
    8310         /* Fork off a child process if necessary. */
    8311         if (!(flags & EV_EXIT) || trap[0]) {
     9282    default: {
     9283
     9284#if ENABLE_FEATURE_SH_NOFORK
     9285/* (1) BUG: if variables are set, we need to fork, or save/restore them
     9286 *     around run_nofork_applet() call.
     9287 * (2) Should this check also be done in forkshell()?
     9288 *     (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
     9289 */
     9290        /* find_command() encodes applet_no as (-2 - applet_no) */
     9291        int applet_no = (- cmdentry.u.index - 2);
     9292        if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
     9293            listsetvar(varlist.list, VEXPORT|VSTACK);
     9294            /* run <applet>_main() */
     9295            exitstatus = run_nofork_applet(applet_no, argv);
     9296            break;
     9297        }
     9298#endif
     9299        /* Can we avoid forking off? For example, very last command
     9300         * in a script or a subshell does not need forking,
     9301         * we can just exec it.
     9302         */
     9303        if (!(flags & EV_EXIT) || may_have_traps) {
     9304            /* No, forking off a child is necessary */
    83129305            INT_OFF;
    8313             jp = makejob(cmd, 1);
     9306            jp = makejob(/*cmd,*/ 1);
    83149307            if (forkshell(jp, cmd, FORK_FG) != 0) {
     9308                /* parent */
    83159309                exitstatus = waitforjob(jp);
    83169310                INT_ON;
     9311                TRACE(("forked child exited with %d\n", exitstatus));
    83179312                break;
    83189313            }
     9314            /* child */
    83199315            FORCE_INT_ON;
     9316            /* fall through to exec'ing external program */
    83209317        }
    83219318        listsetvar(varlist.list, VEXPORT|VSTACK);
    83229319        shellexec(argv, path, cmdentry.u.index);
    83239320        /* NOTREACHED */
    8324 
     9321    } /* default */
    83259322    case CMDBUILTIN:
    83269323        cmdenviron = varlist.list;
     
    83359332            listsetvar(list, i);
    83369333        }
     9334        /* Tight loop with builtins only:
     9335         * "while kill -0 $child; do true; done"
     9336         * will never exit even if $child died, unless we do this
     9337         * to reap the zombie and make kill detect that it's gone: */
     9338        dowait(DOWAIT_NONBLOCK, NULL);
     9339
    83379340        if (evalbltin(cmdentry.u.cmd, argc, argv)) {
    83389341            int exit_status;
    8339             int i, j;
    8340 
    8341             i = exception;
     9342            int i = exception_type;
    83429343            if (i == EXEXIT)
    83439344                goto raise;
    8344 
    83459345            exit_status = 2;
    8346             j = 0;
    83479346            if (i == EXINT)
    8348                 j = SIGINT;
     9347                exit_status = 128 + SIGINT;
    83499348            if (i == EXSIG)
    8350                 j = pendingsig;
    8351             if (j)
    8352                 exit_status = j + 128;
     9349                exit_status = 128 + pending_sig;
    83539350            exitstatus = exit_status;
    8354 
    83559351            if (i == EXINT || spclbltin > 0) {
    83569352 raise:
     
    83639359    case CMDFUNCTION:
    83649360        listsetvar(varlist.list, 0);
     9361        /* See above for the rationale */
     9362        dowait(DOWAIT_NONBLOCK, NULL);
    83659363        if (evalfun(cmdentry.u.func, argc, argv, flags))
    83669364            goto raise;
    83679365        break;
    8368     }
     9366
     9367    } /* switch */
    83699368
    83709369 out:
    8371     popredir(cmd_is_exec);
    8372     if (lastarg)
     9370    popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
     9371    if (lastarg) {
    83739372        /* dsl: I think this is intended to be used to support
    83749373         * '_' in 'vi' command mode during line editing...
     
    83769375         */
    83779376        setvar("_", lastarg, 0);
     9377    }
    83789378    popstackmark(&smark);
    83799379}
     
    84029402    clearerr(stdout);
    84039403    commandname = savecmdname;
    8404     exsig = 0;
    84059404    exception_handler = savehandler;
    84069405
     
    84119410goodname(const char *p)
    84129411{
    8413     return !*endofname(p);
     9412    return endofname(p)[0] == '\0';
    84149413}
    84159414
     
    84479446 * in the standard shell so we don't make it one here.
    84489447 */
    8449 static int
    8450 breakcmd(int argc, char **argv)
    8451 {
    8452     int n = argc > 1 ? number(argv[1]) : 1;
     9448static int FAST_FUNC
     9449breakcmd(int argc UNUSED_PARAM, char **argv)
     9450{
     9451    int n = argv[1] ? number(argv[1]) : 1;
    84539452
    84549453    if (n <= 0)
    8455         ash_msg_and_raise_error(illnum, argv[1]);
     9454        ash_msg_and_raise_error(msg_illnum, argv[1]);
    84569455    if (n > loopnest)
    84579456        n = loopnest;
     
    84699468 */
    84709469
    8471 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
    8472 
    84739470enum {
    84749471    INPUT_PUSH_FILE = 1,
     
    84769473};
    84779474
    8478 /*
    8479  * NEOF is returned by parsecmd when it encounters an end of file.  It
    8480  * must be distinct from NULL, so we use the address of a variable that
    8481  * happens to be handy.
    8482  */
    8483 static int plinno = 1;                  /* input line number */
    8484 /* number of characters left in input buffer */
    8485 static int parsenleft;                  /* copy of parsefile->nleft */
    8486 static int parselleft;                  /* copy of parsefile->lleft */
    8487 /* next character in input buffer */
    8488 static char *parsenextc;                /* copy of parsefile->nextc */
    8489 
    8490 static int checkkwd;
     9475static smallint checkkwd;
    84919476/* values of checkkwd variable */
    84929477#define CHKALIAS        0x1
     
    84949479#define CHKNL           0x4
    84959480
     9481/*
     9482 * Push a string back onto the input at this current parsefile level.
     9483 * We handle aliases this way.
     9484 */
     9485#if !ENABLE_ASH_ALIAS
     9486#define pushstring(s, ap) pushstring(s)
     9487#endif
     9488static void
     9489pushstring(char *s, struct alias *ap)
     9490{
     9491    struct strpush *sp;
     9492    int len;
     9493
     9494    len = strlen(s);
     9495    INT_OFF;
     9496    if (g_parsefile->strpush) {
     9497        sp = ckzalloc(sizeof(*sp));
     9498        sp->prev = g_parsefile->strpush;
     9499    } else {
     9500        sp = &(g_parsefile->basestrpush);
     9501    }
     9502    g_parsefile->strpush = sp;
     9503    sp->prev_string = g_parsefile->next_to_pgetc;
     9504    sp->prev_left_in_line = g_parsefile->left_in_line;
     9505#if ENABLE_ASH_ALIAS
     9506    sp->ap = ap;
     9507    if (ap) {
     9508        ap->flag |= ALIASINUSE;
     9509        sp->string = s;
     9510    }
     9511#endif
     9512    g_parsefile->next_to_pgetc = s;
     9513    g_parsefile->left_in_line = len;
     9514    INT_ON;
     9515}
     9516
    84969517static void
    84979518popstring(void)
    84989519{
    8499     struct strpush *sp = parsefile->strpush;
     9520    struct strpush *sp = g_parsefile->strpush;
    85009521
    85019522    INT_OFF;
    85029523#if ENABLE_ASH_ALIAS
    85039524    if (sp->ap) {
    8504         if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
     9525        if (g_parsefile->next_to_pgetc[-1] == ' '
     9526         || g_parsefile->next_to_pgetc[-1] == '\t'
     9527        ) {
    85059528            checkkwd |= CHKALIAS;
    85069529        }
     
    85149537    }
    85159538#endif
    8516     parsenextc = sp->prevstring;
    8517     parsenleft = sp->prevnleft;
    8518 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
    8519     parsefile->strpush = sp->prev;
    8520     if (sp != &(parsefile->basestrpush))
     9539    g_parsefile->next_to_pgetc = sp->prev_string;
     9540    g_parsefile->left_in_line = sp->prev_left_in_line;
     9541    g_parsefile->strpush = sp->prev;
     9542    if (sp != &(g_parsefile->basestrpush))
    85219543        free(sp);
    85229544    INT_ON;
    85239545}
    85249546
     9547//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
     9548//it peeks whether it is &>, and then pushes back both chars.
     9549//This function needs to save last *next_to_pgetc to buf[0]
     9550//to make two pungetc() reliable. Currently,
     9551// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
    85259552static int
    85269553preadfd(void)
    85279554{
    85289555    int nr;
    8529     char *buf =  parsefile->buf;
    8530     parsenextc = buf;
    8531 
     9556    char *buf = g_parsefile->buf;
     9557
     9558    g_parsefile->next_to_pgetc = buf;
     9559#if ENABLE_FEATURE_EDITING
    85329560 retry:
    8533 #if ENABLE_FEATURE_EDITING
    8534     if (!iflag || parsefile->fd)
    8535         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
     9561    if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
     9562        nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
    85369563    else {
    85379564#if ENABLE_FEATURE_TAB_COMPLETION
    85389565        line_input_state->path_lookup = pathval();
    85399566#endif
    8540         nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
     9567        nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
    85419568        if (nr == 0) {
    85429569            /* Ctrl+C pressed */
     
    85509577        }
    85519578        if (nr < 0 && errno == 0) {
    8552             /* Ctrl+D presend */
     9579            /* Ctrl+D pressed */
    85539580            nr = 0;
    85549581        }
    85559582    }
    85569583#else
    8557     nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
    8558 #endif
    8559 
     9584    nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
     9585#endif
     9586
     9587#if 0
     9588/* nonblock_safe_read() handles this problem */
    85609589    if (nr < 0) {
    85619590        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
    85629591            int flags = fcntl(0, F_GETFL);
    8563             if (flags >= 0 && flags & O_NONBLOCK) {
    8564                 flags &=~ O_NONBLOCK;
     9592            if (flags >= 0 && (flags & O_NONBLOCK)) {
     9593                flags &= ~O_NONBLOCK;
    85659594                if (fcntl(0, F_SETFL, flags) >= 0) {
    85669595                    out2str("sh: turning off NDELAY mode\n");
     
    85709599        }
    85719600    }
     9601#endif
    85729602    return nr;
    85739603}
     
    85779607 *
    85789608 * 1) If a string was pushed back on the input, pop it;
    8579  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
    8580  *    from a string so we can't refill the buffer, return EOF.
    8581  * 3) If the is more stuff in this buffer, use it else call read to fill it.
     9609 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
     9610 *    or we are reading from a string so we can't refill the buffer,
     9611 *    return EOF.
     9612 * 3) If there is more stuff in this buffer, use it else call read to fill it.
    85829613 * 4) Process input up to the next newline, deleting nul characters.
    85839614 */
     9615//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
     9616#define pgetc_debug(...) ((void)0)
    85849617static int
    85859618preadbuffer(void)
     
    85879620    char *q;
    85889621    int more;
    8589     char savec;
    8590 
    8591     while (parsefile->strpush) {
     9622
     9623    while (g_parsefile->strpush) {
    85929624#if ENABLE_ASH_ALIAS
    8593         if (parsenleft == -1 && parsefile->strpush->ap &&
    8594             parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
     9625        if (g_parsefile->left_in_line == -1
     9626         && g_parsefile->strpush->ap
     9627         && g_parsefile->next_to_pgetc[-1] != ' '
     9628         && g_parsefile->next_to_pgetc[-1] != '\t'
     9629        ) {
     9630            pgetc_debug("preadbuffer PEOA");
    85959631            return PEOA;
    85969632        }
    85979633#endif
    85989634        popstring();
    8599         if (--parsenleft >= 0)
    8600             return signed_char2int(*parsenextc++);
    8601     }
    8602     if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
     9635        /* try "pgetc" now: */
     9636        pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
     9637                g_parsefile->left_in_line,
     9638                g_parsefile->next_to_pgetc,
     9639                g_parsefile->next_to_pgetc);
     9640        if (--g_parsefile->left_in_line >= 0)
     9641            return (unsigned char)(*g_parsefile->next_to_pgetc++);
     9642    }
     9643    /* on both branches above g_parsefile->left_in_line < 0.
     9644     * "pgetc" needs refilling.
     9645     */
     9646
     9647    /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
     9648     * pungetc() may increment it a few times.
     9649     * Assuming it won't increment it to less than -90.
     9650     */
     9651    if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
     9652        pgetc_debug("preadbuffer PEOF1");
     9653        /* even in failure keep left_in_line and next_to_pgetc
     9654         * in lock step, for correct multi-layer pungetc.
     9655         * left_in_line was decremented before preadbuffer(),
     9656         * must inc next_to_pgetc: */
     9657        g_parsefile->next_to_pgetc++;
    86039658        return PEOF;
    8604     flush_stdout_stderr();
    8605 
    8606     more = parselleft;
     9659    }
     9660
     9661    more = g_parsefile->left_in_buffer;
    86079662    if (more <= 0) {
     9663        flush_stdout_stderr();
    86089664 again:
    86099665        more = preadfd();
    86109666        if (more <= 0) {
    8611             parselleft = parsenleft = EOF_NLEFT;
     9667            /* don't try reading again */
     9668            g_parsefile->left_in_line = -99;
     9669            pgetc_debug("preadbuffer PEOF2");
     9670            g_parsefile->next_to_pgetc++;
    86129671            return PEOF;
    86139672        }
    86149673    }
    86159674
    8616     q = parsenextc;
    8617 
    8618     /* delete nul characters */
     9675    /* Find out where's the end of line.
     9676     * Set g_parsefile->left_in_line
     9677     * and g_parsefile->left_in_buffer acordingly.
     9678     * NUL chars are deleted.
     9679     */
     9680    q = g_parsefile->next_to_pgetc;
    86199681    for (;;) {
    8620         int c;
     9682        char c;
    86219683
    86229684        more--;
     9685
    86239686        c = *q;
    8624 
    8625         if (!c)
     9687        if (c == '\0') {
    86269688            memmove(q, q + 1, more);
    8627         else {
     9689        } else {
    86289690            q++;
    86299691            if (c == '\n') {
    8630                 parsenleft = q - parsenextc - 1;
     9692                g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
    86319693                break;
    86329694            }
     
    86349696
    86359697        if (more <= 0) {
    8636             parsenleft = q - parsenextc - 1;
    8637             if (parsenleft < 0)
     9698            g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
     9699            if (g_parsefile->left_in_line < 0)
    86389700                goto again;
    86399701            break;
    86409702        }
    86419703    }
    8642     parselleft = more;
    8643 
    8644     savec = *q;
    8645     *q = '\0';
     9704    g_parsefile->left_in_buffer = more;
    86469705
    86479706    if (vflag) {
    8648         out2str(parsenextc);
    8649     }
    8650 
    8651     *q = savec;
    8652 
    8653     return signed_char2int(*parsenextc++);
    8654 }
    8655 
    8656 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
     9707        char save = *q;
     9708        *q = '\0';
     9709        out2str(g_parsefile->next_to_pgetc);
     9710        *q = save;
     9711    }
     9712
     9713    pgetc_debug("preadbuffer at %d:%p'%s'",
     9714            g_parsefile->left_in_line,
     9715            g_parsefile->next_to_pgetc,
     9716            g_parsefile->next_to_pgetc);
     9717    return (unsigned char)*g_parsefile->next_to_pgetc++;
     9718}
     9719
     9720#define pgetc_as_macro() \
     9721    (--g_parsefile->left_in_line >= 0 \
     9722    ? (unsigned char)*g_parsefile->next_to_pgetc++ \
     9723    : preadbuffer() \
     9724    )
     9725
    86579726static int
    86589727pgetc(void)
    86599728{
     9729    pgetc_debug("pgetc_fast at %d:%p'%s'",
     9730            g_parsefile->left_in_line,
     9731            g_parsefile->next_to_pgetc,
     9732            g_parsefile->next_to_pgetc);
    86609733    return pgetc_as_macro();
    86619734}
    86629735
    86639736#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
    8664 #define pgetc_macro() pgetc()
     9737# define pgetc_fast() pgetc()
    86659738#else
    8666 #define pgetc_macro() pgetc_as_macro()
    8667 #endif
    8668 
    8669 /*
    8670  * Same as pgetc(), but ignores PEOA.
    8671  */
     9739# define pgetc_fast() pgetc_as_macro()
     9740#endif
     9741
    86729742#if ENABLE_ASH_ALIAS
    86739743static int
    8674 pgetc2(void)
     9744pgetc_without_PEOA(void)
    86759745{
    86769746    int c;
    8677 
    86789747    do {
    8679         c = pgetc_macro();
     9748        pgetc_debug("pgetc_fast at %d:%p'%s'",
     9749                g_parsefile->left_in_line,
     9750                g_parsefile->next_to_pgetc,
     9751                g_parsefile->next_to_pgetc);
     9752        c = pgetc_fast();
    86809753    } while (c == PEOA);
    86819754    return c;
    86829755}
    86839756#else
    8684 static int
    8685 pgetc2(void)
    8686 {
    8687     return pgetc_macro();
    8688 }
     9757# define pgetc_without_PEOA() pgetc()
    86899758#endif
    86909759
     
    87009769
    87019770    while (--nleft > 0) {
    8702         c = pgetc2();
     9771        c = pgetc_without_PEOA();
    87039772        if (c == PEOF) {
    87049773            if (p == line)
     
    87219790pungetc(void)
    87229791{
    8723     parsenleft++;
    8724     parsenextc--;
    8725 }
    8726 
    8727 /*
    8728  * Push a string back onto the input at this current parsefile level.
    8729  * We handle aliases this way.
    8730  */
    8731 static void
    8732 pushstring(char *s, void *ap)
    8733 {
    8734     struct strpush *sp;
    8735     size_t len;
    8736 
    8737     len = strlen(s);
    8738     INT_OFF;
    8739 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
    8740     if (parsefile->strpush) {
    8741         sp = ckmalloc(sizeof(struct strpush));
    8742         sp->prev = parsefile->strpush;
    8743         parsefile->strpush = sp;
    8744     } else
    8745         sp = parsefile->strpush = &(parsefile->basestrpush);
    8746     sp->prevstring = parsenextc;
    8747     sp->prevnleft = parsenleft;
    8748 #if ENABLE_ASH_ALIAS
    8749     sp->ap = (struct alias *)ap;
    8750     if (ap) {
    8751         ((struct alias *)ap)->flag |= ALIASINUSE;
    8752         sp->string = s;
    8753     }
    8754 #endif
    8755     parsenextc = s;
    8756     parsenleft = len;
    8757     INT_ON;
     9792    g_parsefile->left_in_line++;
     9793    g_parsefile->next_to_pgetc--;
     9794    pgetc_debug("pushed back to %d:%p'%s'",
     9795            g_parsefile->left_in_line,
     9796            g_parsefile->next_to_pgetc,
     9797            g_parsefile->next_to_pgetc);
    87589798}
    87599799
     
    87679807    struct parsefile *pf;
    87689808
    8769     parsefile->nleft = parsenleft;
    8770     parsefile->lleft = parselleft;
    8771     parsefile->nextc = parsenextc;
    8772     parsefile->linno = plinno;
    8773     pf = ckmalloc(sizeof(*pf));
    8774     pf->prev = parsefile;
    8775     pf->fd = -1;
    8776     pf->strpush = NULL;
    8777     pf->basestrpush.prev = NULL;
    8778     parsefile = pf;
     9809    pf = ckzalloc(sizeof(*pf));
     9810    pf->prev = g_parsefile;
     9811    pf->pf_fd = -1;
     9812    /*pf->strpush = NULL; - ckzalloc did it */
     9813    /*pf->basestrpush.prev = NULL;*/
     9814    g_parsefile = pf;
    87799815}
    87809816
     
    87829818popfile(void)
    87839819{
    8784     struct parsefile *pf = parsefile;
     9820    struct parsefile *pf = g_parsefile;
    87859821
    87869822    INT_OFF;
    8787     if (pf->fd >= 0)
    8788         close(pf->fd);
    8789     if (pf->buf)
    8790         free(pf->buf);
     9823    if (pf->pf_fd >= 0)
     9824        close(pf->pf_fd);
     9825    free(pf->buf);
    87919826    while (pf->strpush)
    87929827        popstring();
    8793     parsefile = pf->prev;
     9828    g_parsefile = pf->prev;
    87949829    free(pf);
    8795     parsenleft = parsefile->nleft;
    8796     parselleft = parsefile->lleft;
    8797     parsenextc = parsefile->nextc;
    8798     plinno = parsefile->linno;
    87999830    INT_ON;
    88009831}
     
    88069837popallfiles(void)
    88079838{
    8808     while (parsefile != &basepf)
     9839    while (g_parsefile != &basepf)
    88099840        popfile();
    88109841}
     
    88189849{
    88199850    popallfiles();
    8820     if (parsefile->fd > 0) {
    8821         close(parsefile->fd);
    8822         parsefile->fd = 0;
     9851    if (g_parsefile->pf_fd > 0) {
     9852        close(g_parsefile->pf_fd);
     9853        g_parsefile->pf_fd = 0;
    88239854    }
    88249855}
     
    88319862setinputfd(int fd, int push)
    88329863{
    8833     fcntl(fd, F_SETFD, FD_CLOEXEC);
     9864    close_on_exec_on(fd);
    88349865    if (push) {
    88359866        pushfile();
    8836         parsefile->buf = 0;
    8837     }
    8838     parsefile->fd = fd;
    8839     if (parsefile->buf == NULL)
    8840         parsefile->buf = ckmalloc(IBUFSIZ);
    8841     parselleft = parsenleft = 0;
    8842     plinno = 1;
     9867        g_parsefile->buf = NULL;
     9868    }
     9869    g_parsefile->pf_fd = fd;
     9870    if (g_parsefile->buf == NULL)
     9871        g_parsefile->buf = ckmalloc(IBUFSIZ);
     9872    g_parsefile->left_in_buffer = 0;
     9873    g_parsefile->left_in_line = 0;
     9874    g_parsefile->linno = 1;
    88439875}
    88449876
     
    88589890        if (flags & INPUT_NOFILE_OK)
    88599891            goto out;
    8860         ash_msg_and_raise_error("can't open %s", fname);
     9892        ash_msg_and_raise_error("can't open '%s'", fname);
    88619893    }
    88629894    if (fd < 10) {
     
    88819913    INT_OFF;
    88829914    pushfile();
    8883     parsenextc = string;
    8884     parsenleft = strlen(string);
    8885     parsefile->buf = NULL;
    8886     plinno = 1;
     9915    g_parsefile->next_to_pgetc = string;
     9916    g_parsefile->left_in_line = strlen(string);
     9917    g_parsefile->buf = NULL;
     9918    g_parsefile->linno = 1;
    88879919    INT_ON;
    88889920}
     
    89019933static time_t mailtime[MAXMBOXES];
    89029934/* Set if MAIL or MAILPATH is changed. */
    8903 static int mail_var_path_changed;
     9935static smallint mail_var_path_changed;
    89049936
    89059937/*
     
    89229954    mpath = mpathset() ? mpathval() : mailval();
    89239955    for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
    8924         p = padvance(&mpath, nullstr);
     9956        p = path_advance(&mpath, nullstr);
    89259957        if (p == NULL)
    89269958            break;
    89279959        if (*p == '\0')
    89289960            continue;
    8929         for (q = p; *q; q++);
     9961        for (q = p; *q; q++)
     9962            continue;
    89309963#if DEBUG
    89319964        if (q[-1] != '/')
     
    89399972        if (!mail_var_path_changed && statb.st_mtime != *mtp) {
    89409973            fprintf(
    8941                 stderr, snlfmt,
     9974                stderr, "%s\n",
    89429975                pathopt ? pathopt : "you have mail"
    89439976            );
     
    89499982}
    89509983
    8951 static void
    8952 changemail(const char *val)
    8953 {
    8954     mail_var_path_changed++;
     9984static void FAST_FUNC
     9985changemail(const char *val UNUSED_PARAM)
     9986{
     9987    mail_var_path_changed = 1;
    89559988}
    89569989
     
    897010003    int nparam;
    897110004
    8972     for (nparam = 0; argv[nparam]; nparam++);
     10005    for (nparam = 0; argv[nparam]; nparam++)
     10006        continue;
    897310007    ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
    897410008    while (*argv) {
     
    897710011    *ap = NULL;
    897810012    freeparam(&shellparam);
    8979     shellparam.malloc = 1;
     10013    shellparam.malloced = 1;
    898010014    shellparam.nparam = nparam;
    898110015    shellparam.p = newparam;
     
    898910023 * Process shell options.  The global variable argptr contains a pointer
    899010024 * to the argument list; we advance it past the options.
    8991  */
    8992 static void
    8993 minus_o(char *name, int val)
     10025 *
     10026 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
     10027 * For a non-interactive shell, an error condition encountered
     10028 * by a special built-in ... shall cause the shell to write a diagnostic message
     10029 * to standard error and exit as shown in the following table:
     10030 * Error                                           Special Built-In
     10031 * ...
     10032 * Utility syntax error (option or operand error)  Shall exit
     10033 * ...
     10034 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
     10035 * we see that bash does not do that (set "finishes" with error code 1 instead,
     10036 * and shell continues), and people rely on this behavior!
     10037 * Testcase:
     10038 * set -o barfoo 2>/dev/null
     10039 * echo $?
     10040 *
     10041 * Oh well. Let's mimic that.
     10042 */
     10043static int
     10044plus_minus_o(char *name, int val)
    899410045{
    899510046    int i;
     
    899910050            if (strcmp(name, optnames(i)) == 0) {
    900010051                optlist[i] = val;
    9001                 return;
     10052                return 0;
    900210053            }
    900310054        }
    9004         ash_msg_and_raise_error("illegal option -o %s", name);
    9005     }
    9006     out1str("Current option settings\n");
    9007     for (i = 0; i < NOPTS; i++)
    9008         out1fmt("%-16s%s\n", optnames(i),
    9009                 optlist[i] ? "on" : "off");
     10055        ash_msg("illegal option %co %s", val ? '-' : '+', name);
     10056        return 1;
     10057    }
     10058    for (i = 0; i < NOPTS; i++) {
     10059        if (val) {
     10060            out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
     10061        } else {
     10062            out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
     10063        }
     10064    }
     10065    return 0;
    901010066}
    901110067static void
     
    902010076        }
    902110077    }
    9022     ash_msg_and_raise_error("illegal option -%c", flag);
     10078    ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
    902310079    /* NOTREACHED */
    902410080}
    9025 static void
     10081static int
    902610082options(int cmdline)
    902710083{
     
    905810114                minusc = p;     /* command is after shell args */
    905910115            } else if (c == 'o') {
    9060                 minus_o(*argptr, val);
     10116                if (plus_minus_o(*argptr, val)) {
     10117                    /* it already printed err message */
     10118                    return 1; /* error */
     10119                }
    906110120                if (*argptr)
    906210121                    argptr++;
     
    907310132        }
    907410133    }
     10134    return 0;
    907510135}
    907610136
     
    907810138 * The shift builtin command.
    907910139 */
    9080 static int
    9081 shiftcmd(int argc, char **argv)
     10140static int FAST_FUNC
     10141shiftcmd(int argc UNUSED_PARAM, char **argv)
    908210142{
    908310143    int n;
     
    908510145
    908610146    n = 1;
    9087     if (argc > 1)
     10147    if (argv[1])
    908810148        n = number(argv[1]);
    908910149    if (n > shellparam.nparam)
    9090         ash_msg_and_raise_error("can't shift that many");
     10150        n = 0; /* bash compat, was = shellparam.nparam; */
    909110151    INT_OFF;
    909210152    shellparam.nparam -= n;
    909310153    for (ap1 = shellparam.p; --n >= 0; ap1++) {
    9094         if (shellparam.malloc)
     10154        if (shellparam.malloced)
    909510155            free(*ap1);
    909610156    }
    909710157    ap2 = shellparam.p;
    9098     while ((*ap2++ = *ap1++) != NULL);
     10158    while ((*ap2++ = *ap1++) != NULL)
     10159        continue;
    909910160#if ENABLE_ASH_GETOPTS
    910010161    shellparam.optind = 1;
     
    913910200 * The set command builtin.
    914010201 */
    9141 static int
    9142 setcmd(int argc, char **argv)
    9143 {
    9144     if (argc == 1)
     10202static int FAST_FUNC
     10203setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
     10204{
     10205    int retval;
     10206
     10207    if (!argv[1])
    914510208        return showvars(nullstr, 0, VUNSET);
    914610209    INT_OFF;
    9147     options(0);
    9148     optschanged();
    9149     if (*argptr != NULL) {
    9150         setparam(argptr);
     10210    retval = 1;
     10211    if (!options(0)) { /* if no parse error... */
     10212        retval = 0;
     10213        optschanged();
     10214        if (*argptr != NULL) {
     10215            setparam(argptr);
     10216        }
    915110217    }
    915210218    INT_ON;
    9153     return 0;
     10219    return retval;
    915410220}
    915510221
    915610222#if ENABLE_ASH_RANDOM_SUPPORT
    9157 /* Roughly copied from bash.. */
    9158 static void
     10223static void FAST_FUNC
    915910224change_random(const char *value)
    916010225{
     10226    uint32_t t;
     10227
    916110228    if (value == NULL) {
    916210229        /* "get", generate */
    9163         char buf[16];
    9164 
    9165         rseed = rseed * 1103515245 + 12345;
    9166         sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
     10230        t = next_random(&random_gen);
    916710231        /* set without recursion */
    9168         setvar(vrandom.text, buf, VNOFUNC);
     10232        setvar(vrandom.var_text, utoa(t), VNOFUNC);
    916910233        vrandom.flags &= ~VNOFUNC;
    917010234    } else {
    917110235        /* set/reset */
    9172         rseed = strtoul(value, (char **)NULL, 10);
     10236        t = strtoul(value, NULL, 10);
     10237        INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
    917310238    }
    917410239}
     
    919010255    optnext = optfirst + *param_optind - 1;
    919110256
    9192     if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
     10257    if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
    919310258        p = NULL;
    919410259    else
     
    920910274
    921010275    c = *p++;
    9211     for (q = optstr; *q != c; ) {
     10276    for (q = optstr; *q != c;) {
    921210277        if (*q == '\0') {
    921310278            if (optstr[0] == ':') {
     
    927010335 * then it's the first time getopts has been called.
    927110336 */
    9272 static int
     10337static int FAST_FUNC
    927310338getoptscmd(int argc, char **argv)
    927410339{
     
    929910364/* ============ Shell parser */
    930010365
    9301 static int tokpushback;                /* last token pushed back */
    9302 #define NEOF ((union node *)&tokpushback)
    9303 static int parsebackquote;             /* nonzero if we are inside backquotes */
    9304 static int lasttoken;                  /* last token read */
     10366struct heredoc {
     10367    struct heredoc *next;   /* next here document in list */
     10368    union node *here;       /* redirection node */
     10369    char *eofmark;          /* string indicating end of input */
     10370    smallint striptabs;     /* if set, strip leading tabs */
     10371};
     10372
     10373static smallint tokpushback;           /* last token pushed back */
     10374static smallint parsebackquote;        /* nonzero if we are inside backquotes */
     10375static smallint quoteflag;             /* set if (part of) last token was quoted */
     10376static token_id_t lasttoken;           /* last token read (integer id Txxx) */
     10377static struct heredoc *heredoclist;    /* list of here documents to read */
    930510378static char *wordtext;                 /* text of last word returned by readtoken */
    930610379static struct nodelist *backquotelist;
    930710380static union node *redirnode;
    930810381static struct heredoc *heredoc;
    9309 static int quoteflag;                  /* set if (part of) last token was quoted */
    9310 
    9311 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
    9312 static void
    9313 raise_error_syntax(const char *msg)
    9314 {
    9315     ash_msg_and_raise_error("syntax error: %s", msg);
    9316     /* NOTREACHED */
    9317 }
    9318 
    9319 /*
     10382
     10383static const char *
     10384tokname(char *buf, int tok)
     10385{
     10386    if (tok < TSEMI)
     10387        return tokname_array[tok] + 1;
     10388    sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
     10389    return buf;
     10390}
     10391
     10392/* raise_error_unexpected_syntax:
    932010393 * Called when an unexpected token is read during the parse.  The argument
    932110394 * is the token that is expected, or -1 if more than one type of token can
    932210395 * occur at this point.
    932310396 */
    9324 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
     10397static void raise_error_unexpected_syntax(int) NORETURN;
    932510398static void
    932610399raise_error_unexpected_syntax(int token)
    932710400{
    932810401    char msg[64];
     10402    char buf[16];
    932910403    int l;
    933010404
    9331     l = sprintf(msg, "%s unexpected", tokname(lasttoken));
     10405    l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
    933210406    if (token >= 0)
    9333         sprintf(msg + l, " (expecting %s)", tokname(token));
     10407        sprintf(msg + l, " (expecting %s)", tokname(buf, token));
    933410408    raise_error_syntax(msg);
    933510409    /* NOTREACHED */
     
    933710411
    933810412#define EOFMARKLEN 79
    9339 
    9340 struct heredoc {
    9341     struct heredoc *next;   /* next here document in list */
    9342     union node *here;               /* redirection node */
    9343     char *eofmark;          /* string indicating end of input */
    9344     int striptabs;          /* if set, strip leading tabs */
    9345 };
    9346 
    9347 static struct heredoc *heredoclist;    /* list of here documents to read */
    934810413
    934910414/* parsing is heavily cross-recursive, need these forward decls */
     
    937010435        if (tok == TBACKGND) {
    937110436            if (n2->type == NPIPE) {
    9372                 n2->npipe.backgnd = 1;
     10437                n2->npipe.pipe_backgnd = 1;
    937310438            } else {
    937410439                if (n2->type != NREDIR) {
    9375                     n3 = stalloc(sizeof(struct nredir));
     10440                    n3 = stzalloc(sizeof(struct nredir));
    937610441                    n3->nredir.n = n2;
    9377                     n3->nredir.redirect = NULL;
     10442                    /*n3->nredir.redirect = NULL; - stzalloc did it */
    937810443                    n2 = n3;
    937910444                }
     
    938410449            n1 = n2;
    938510450        } else {
    9386             n3 = stalloc(sizeof(struct nbinary));
     10451            n3 = stzalloc(sizeof(struct nbinary));
    938710452            n3->type = NSEMI;
    938810453            n3->nbinary.ch1 = n1;
     
    940110466                    return n1;
    940210467            } else {
    9403                 tokpushback++;
     10468                tokpushback = 1;
    940410469            }
    940510470            checkkwd = CHKNL | CHKKWD | CHKALIAS;
     
    941610481            if (nlflag == 1)
    941710482                raise_error_unexpected_syntax(-1);
    9418             tokpushback++;
     10483            tokpushback = 1;
    941910484            return n1;
    942010485        }
     
    943610501            t = NOR;
    943710502        } else {
    9438             tokpushback++;
     10503            tokpushback = 1;
    943910504            return n1;
    944010505        }
    944110506        checkkwd = CHKNL | CHKKWD | CHKALIAS;
    944210507        n2 = pipeline();
    9443         n3 = stalloc(sizeof(struct nbinary));
     10508        n3 = stzalloc(sizeof(struct nbinary));
    944410509        n3->type = t;
    944510510        n3->nbinary.ch1 = n1;
     
    946210527        checkkwd = CHKKWD | CHKALIAS;
    946310528    } else
    9464         tokpushback++;
     10529        tokpushback = 1;
    946510530    n1 = parse_command();
    946610531    if (readtoken() == TPIPE) {
    9467         pipenode = stalloc(sizeof(struct npipe));
     10532        pipenode = stzalloc(sizeof(struct npipe));
    946810533        pipenode->type = NPIPE;
    9469         pipenode->npipe.backgnd = 0;
    9470         lp = stalloc(sizeof(struct nodelist));
     10534        /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
     10535        lp = stzalloc(sizeof(struct nodelist));
    947110536        pipenode->npipe.cmdlist = lp;
    947210537        lp->n = n1;
    947310538        do {
    947410539            prev = lp;
    9475             lp = stalloc(sizeof(struct nodelist));
     10540            lp = stzalloc(sizeof(struct nodelist));
    947610541            checkkwd = CHKNL | CHKKWD | CHKALIAS;
    947710542            lp->n = parse_command();
     
    948110546        n1 = pipenode;
    948210547    }
    9483     tokpushback++;
     10548    tokpushback = 1;
    948410549    if (negate) {
    9485         n2 = stalloc(sizeof(struct nnot));
     10550        n2 = stzalloc(sizeof(struct nnot));
    948610551        n2->type = NNOT;
    948710552        n2->nnot.com = n1;
     
    949610561    union node *n;
    949710562
    9498     n = stalloc(sizeof(struct narg));
     10563    n = stzalloc(sizeof(struct narg));
    949910564    n->type = NARG;
    9500     n->narg.next = NULL;
     10565    /*n->narg.next = NULL; - stzalloc did it */
    950110566    n->narg.text = wordtext;
    950210567    n->narg.backquote = backquotelist;
     
    950710572fixredir(union node *n, const char *text, int err)
    950810573{
     10574    int fd;
     10575
    950910576    TRACE(("Fix redir %s %d\n", text, err));
    951010577    if (!err)
    951110578        n->ndup.vname = NULL;
    951210579
    9513     if (isdigit(text[0]) && text[1] == '\0')
    9514         n->ndup.dupfd = text[0] - '0';
     10580    fd = bb_strtou(text, NULL, 10);
     10581    if (!errno && fd >= 0)
     10582        n->ndup.dupfd = fd;
    951510583    else if (LONE_DASH(text))
    951610584        n->ndup.dupfd = -1;
    951710585    else {
    951810586        if (err)
    9519             raise_error_syntax("Bad fd number");
     10587            raise_error_syntax("bad fd number");
    952010588        n->ndup.vname = makename();
    952110589    }
     
    952710595 */
    952810596static int
    9529 noexpand(char *text)
    9530 {
    9531     char *p;
    9532     char c;
    9533 
    9534     p = text;
    9535     while ((c = *p++) != '\0') {
     10597noexpand(const char *text)
     10598{
     10599    unsigned char c;
     10600
     10601    while ((c = *text++) != '\0') {
    953610602        if (c == CTLQUOTEMARK)
    953710603            continue;
    953810604        if (c == CTLESC)
    9539             p++;
     10605            text++;
    954010606        else if (SIT(c, BASESYNTAX) == CCTL)
    954110607            return 0;
     
    956010626        TRACE(("Here document %d\n", n->type));
    956110627        if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
    9562             raise_error_syntax("Illegal eof marker for << redirection");
    9563         rmescapes(wordtext);
     10628            raise_error_syntax("illegal eof marker for << redirection");
     10629        rmescapes(wordtext, 0);
    956410630        here->eofmark = wordtext;
    956510631        here->next = NULL;
     
    956710633            heredoclist = here;
    956810634        else {
    9569             for (p = heredoclist; p->next; p = p->next);
     10635            for (p = heredoclist; p->next; p = p->next)
     10636                continue;
    957010637            p->next = here;
    957110638        }
     
    958510652    union node **rpp, *redir;
    958610653    int savecheckkwd;
     10654#if ENABLE_ASH_BASH_COMPAT
     10655    smallint double_brackets_flag = 0;
     10656#endif
    958710657
    958810658    args = NULL;
     
    959510665    savecheckkwd = CHKALIAS;
    959610666    for (;;) {
     10667        int t;
    959710668        checkkwd = savecheckkwd;
    9598         switch (readtoken()) {
     10669        t = readtoken();
     10670        switch (t) {
     10671#if ENABLE_ASH_BASH_COMPAT
     10672        case TAND: /* "&&" */
     10673        case TOR: /* "||" */
     10674            if (!double_brackets_flag) {
     10675                tokpushback = 1;
     10676                goto out;
     10677            }
     10678            wordtext = (char *) (t == TAND ? "-a" : "-o");
     10679#endif
    959910680        case TWORD:
    9600             n = stalloc(sizeof(struct narg));
     10681            n = stzalloc(sizeof(struct narg));
    960110682            n->type = NARG;
     10683            /*n->narg.next = NULL; - stzalloc did it */
    960210684            n->narg.text = wordtext;
     10685#if ENABLE_ASH_BASH_COMPAT
     10686            if (strcmp("[[", wordtext) == 0)
     10687                double_brackets_flag = 1;
     10688            else if (strcmp("]]", wordtext) == 0)
     10689                double_brackets_flag = 0;
     10690#endif
    960310691            n->narg.backquote = backquotelist;
    960410692            if (savecheckkwd && isassignment(wordtext)) {
     
    963010718                 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
    963110719                ) {
    9632                     raise_error_syntax("Bad function name");
     10720                    raise_error_syntax("bad function name");
    963310721                }
    963410722                n->type = NDEFUN;
     
    963910727            /* fall through */
    964010728        default:
    9641             tokpushback++;
     10729            tokpushback = 1;
    964210730            goto out;
    964310731        }
     
    964710735    *vpp = NULL;
    964810736    *rpp = NULL;
    9649     n = stalloc(sizeof(struct ncmd));
     10737    n = stzalloc(sizeof(struct ncmd));
    965010738    n->type = NCMD;
    965110739    n->ncmd.args = args;
     
    967310761        /* NOTREACHED */
    967410762    case TIF:
    9675         n1 = stalloc(sizeof(struct nif));
     10763        n1 = stzalloc(sizeof(struct nif));
    967610764        n1->type = NIF;
    967710765        n1->nif.test = list(0);
     
    968110769        n2 = n1;
    968210770        while (readtoken() == TELIF) {
    9683             n2->nif.elsepart = stalloc(sizeof(struct nif));
     10771            n2->nif.elsepart = stzalloc(sizeof(struct nif));
    968410772            n2 = n2->nif.elsepart;
    968510773            n2->type = NIF;
     
    969310781        else {
    969410782            n2->nif.elsepart = NULL;
    9695             tokpushback++;
     10783            tokpushback = 1;
    969610784        }
    969710785        t = TFI;
     
    970010788    case TUNTIL: {
    970110789        int got;
    9702         n1 = stalloc(sizeof(struct nbinary));
     10790        n1 = stzalloc(sizeof(struct nbinary));
    970310791        n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
    970410792        n1->nbinary.ch1 = list(0);
    970510793        got = readtoken();
    970610794        if (got != TDO) {
    9707             TRACE(("expecting DO got %s %s\n", tokname(got),
     10795            TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
    970810796                    got == TWORD ? wordtext : ""));
    970910797            raise_error_unexpected_syntax(TDO);
     
    971410802    }
    971510803    case TFOR:
    9716         if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
    9717             raise_error_syntax("Bad for loop variable");
    9718         n1 = stalloc(sizeof(struct nfor));
     10804        if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
     10805            raise_error_syntax("bad for loop variable");
     10806        n1 = stzalloc(sizeof(struct nfor));
    971910807        n1->type = NFOR;
    972010808        n1->nfor.var = wordtext;
     
    972310811            app = &ap;
    972410812            while (readtoken() == TWORD) {
    9725                 n2 = stalloc(sizeof(struct narg));
     10813                n2 = stzalloc(sizeof(struct narg));
    972610814                n2->type = NARG;
     10815                /*n2->narg.next = NULL; - stzalloc did it */
    972710816                n2->narg.text = wordtext;
    972810817                n2->narg.backquote = backquotelist;
     
    973510824                raise_error_unexpected_syntax(-1);
    973610825        } else {
    9737             n2 = stalloc(sizeof(struct narg));
     10826            n2 = stzalloc(sizeof(struct narg));
    973810827            n2->type = NARG;
     10828            /*n2->narg.next = NULL; - stzalloc did it */
    973910829            n2->narg.text = (char *)dolatstr;
    9740             n2->narg.backquote = NULL;
    9741             n2->narg.next = NULL;
     10830            /*n2->narg.backquote = NULL;*/
    974210831            n1->nfor.args = n2;
    974310832            /*
     
    974610835             */
    974710836            if (lasttoken != TNL && lasttoken != TSEMI)
    9748                 tokpushback++;
     10837                tokpushback = 1;
    974910838        }
    975010839        checkkwd = CHKNL | CHKKWD | CHKALIAS;
     
    975510844        break;
    975610845    case TCASE:
    9757         n1 = stalloc(sizeof(struct ncase));
     10846        n1 = stzalloc(sizeof(struct ncase));
    975810847        n1->type = NCASE;
    975910848        if (readtoken() != TWORD)
    976010849            raise_error_unexpected_syntax(TWORD);
    9761         n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
     10850        n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
    976210851        n2->type = NARG;
     10852        /*n2->narg.next = NULL; - stzalloc did it */
    976310853        n2->narg.text = wordtext;
    976410854        n2->narg.backquote = backquotelist;
    9765         n2->narg.next = NULL;
    976610855        do {
    976710856            checkkwd = CHKKWD | CHKALIAS;
     
    977610865            if (lasttoken == TLP)
    977710866                readtoken();
    9778             *cpp = cp = stalloc(sizeof(struct nclist));
     10867            *cpp = cp = stzalloc(sizeof(struct nclist));
    977910868            cp->type = NCLIST;
    978010869            app = &cp->nclist.pattern;
    978110870            for (;;) {
    9782                 *app = ap = stalloc(sizeof(struct narg));
     10871                *app = ap = stzalloc(sizeof(struct narg));
    978310872                ap->type = NARG;
     10873                /*ap->narg.next = NULL; - stzalloc did it */
    978410874                ap->narg.text = wordtext;
    978510875                ap->narg.backquote = backquotelist;
     
    978910879                readtoken();
    979010880            }
    9791             ap->narg.next = NULL;
     10881            //ap->narg.next = NULL;
    979210882            if (lasttoken != TRP)
    979310883                raise_error_unexpected_syntax(TRP);
     
    980710897        goto redir;
    980810898    case TLP:
    9809         n1 = stalloc(sizeof(struct nredir));
     10899        n1 = stzalloc(sizeof(struct nredir));
    981010900        n1->type = NSUBSHELL;
    981110901        n1->nredir.n = list(0);
    9812         n1->nredir.redirect = NULL;
     10902        /*n1->nredir.redirect = NULL; - stzalloc did it */
    981310903        t = TRP;
    981410904        break;
     
    981910909    case TWORD:
    982010910    case TREDIR:
    9821         tokpushback++;
     10911        tokpushback = 1;
    982210912        return simplecmd();
    982310913    }
     
    983510925        parsefname();
    983610926    }
    9837     tokpushback++;
     10927    tokpushback = 1;
    983810928    *rpp = NULL;
    983910929    if (redir) {
    984010930        if (n1->type != NSUBSHELL) {
    9841             n2 = stalloc(sizeof(struct nredir));
     10931            n2 = stzalloc(sizeof(struct nredir));
    984210932            n2->type = NREDIR;
    984310933            n2->nredir.n = n1;
     
    984910939}
    985010940
     10941#if ENABLE_ASH_BASH_COMPAT
     10942static int decode_dollar_squote(void)
     10943{
     10944    static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
     10945    int c, cnt;
     10946    char *p;
     10947    char buf[4];
     10948
     10949    c = pgetc();
     10950    p = strchr(C_escapes, c);
     10951    if (p) {
     10952        buf[0] = c;
     10953        p = buf;
     10954        cnt = 3;
     10955        if ((unsigned char)(c - '0') <= 7) { /* \ooo */
     10956            do {
     10957                c = pgetc();
     10958                *++p = c;
     10959            } while ((unsigned char)(c - '0') <= 7 && --cnt);
     10960            pungetc();
     10961        } else if (c == 'x') { /* \xHH */
     10962            do {
     10963                c = pgetc();
     10964                *++p = c;
     10965            } while (isxdigit(c) && --cnt);
     10966            pungetc();
     10967            if (cnt == 3) { /* \x but next char is "bad" */
     10968                c = 'x';
     10969                goto unrecognized;
     10970            }
     10971        } else { /* simple seq like \\ or \t */
     10972            p++;
     10973        }
     10974        *p = '\0';
     10975        p = buf;
     10976        c = bb_process_escape_sequence((void*)&p);
     10977    } else { /* unrecognized "\z": print both chars unless ' or " */
     10978        if (c != '\'' && c != '"') {
     10979 unrecognized:
     10980            c |= 0x100; /* "please encode \, then me" */
     10981        }
     10982    }
     10983    return c;
     10984}
     10985#endif
     10986
    985110987/*
    985210988 * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
    985310989 * is not NULL, read a here document.  In the latter case, eofmark is the
    985410990 * word which marks the end of the document and striptabs is true if
    9855  * leading tabs should be stripped from the document.  The argument firstc
     10991 * leading tabs should be stripped from the document.  The argument c
    985610992 * is the first character of the input token or document.
    985710993 *
     
    986010996 * will run code that appears at the end of readtoken1.
    986110997 */
    9862 
    9863 static int parsebackquote;             /* nonzero if we are inside backquotes */
    9864 
    986510998#define CHECKEND()      {goto checkend; checkend_return:;}
    986610999#define PARSEREDIR()    {goto parseredir; parseredir_return:;}
     
    986911002#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
    987011003#define PARSEARITH()    {goto parsearith; parsearith_return:;}
    9871 
    987211004static int
    9873 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
    9874 {
    9875     int c = firstc;
     11005readtoken1(int c, int syntax, char *eofmark, int striptabs)
     11006{
     11007    /* NB: syntax parameter fits into smallint */
     11008    /* c parameter is an unsigned char or PEOF or PEOA */
    987611009    char *out;
    987711010    int len;
    987811011    char line[EOFMARKLEN + 1];
    9879     struct nodelist *bqlist = 0;
    9880     int quotef = 0;
    9881     int dblquote = 0;
    9882     int varnest = 0;    /* levels of variables expansion */
    9883     int arinest = 0;    /* levels of arithmetic expansion */
    9884     int parenlevel = 0; /* levels of parens in arithmetic */
    9885     int dqvarnest = 0;  /* levels of variables expansion within double quotes */
    9886     int oldstyle = 0;
    9887     int prevsyntax = 0; /* syntax before arithmetic */
     11012    struct nodelist *bqlist;
     11013    smallint quotef;
     11014    smallint dblquote;
     11015    smallint oldstyle;
     11016    smallint prevsyntax; /* syntax before arithmetic */
     11017#if ENABLE_ASH_EXPAND_PRMT
     11018    smallint pssyntax;   /* we are expanding a prompt string */
     11019#endif
     11020    int varnest;         /* levels of variables expansion */
     11021    int arinest;         /* levels of arithmetic expansion */
     11022    int parenlevel;      /* levels of parens in arithmetic */
     11023    int dqvarnest;       /* levels of variables expansion within double quotes */
     11024
     11025    IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
     11026
    988811027#if __GNUC__
    988911028    /* Avoid longjmp clobbering */
     
    989911038    (void) &syntax;
    990011039#endif
    9901 
    9902     startlinno = plinno;
    9903     dblquote = 0;
    9904     if (syntax == DQSYNTAX)
    9905         dblquote = 1;
     11040    startlinno = g_parsefile->linno;
     11041    bqlist = NULL;
    990611042    quotef = 0;
    9907     bqlist = NULL;
     11043    prevsyntax = 0;
     11044#if ENABLE_ASH_EXPAND_PRMT
     11045    pssyntax = (syntax == PSSYNTAX);
     11046    if (pssyntax)
     11047        syntax = DQSYNTAX;
     11048#endif
     11049    dblquote = (syntax == DQSYNTAX);
    990811050    varnest = 0;
    990911051    arinest = 0;
     
    991211054
    991311055    STARTSTACKSTR(out);
    9914     loop: { /* for each line, until end of word */
    9915         CHECKEND();     /* set c to PEOF if at end of here document */
    9916         for (;;) {      /* until end of line or end of word */
    9917             CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
    9918             switch (SIT(c, syntax)) {
    9919             case CNL:       /* '\n' */
    9920                 if (syntax == BASESYNTAX)
    9921                     goto endword;   /* exit outer loop */
    9922                 USTPUTC(c, out);
    9923                 plinno++;
    9924                 if (doprompt)
    9925                     setprompt(2);
    9926                 c = pgetc();
    9927                 goto loop;              /* continue outer loop */
    9928             case CWORD:
    9929                 USTPUTC(c, out);
    9930                 break;
    9931             case CCTL:
    9932                 if (eofmark == NULL || dblquote)
     11056 loop:
     11057    /* For each line, until end of word */
     11058    CHECKEND();     /* set c to PEOF if at end of here document */
     11059    for (;;) {      /* until end of line or end of word */
     11060        CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
     11061        switch (SIT(c, syntax)) {
     11062        case CNL:       /* '\n' */
     11063            if (syntax == BASESYNTAX)
     11064                goto endword;   /* exit outer loop */
     11065            USTPUTC(c, out);
     11066            g_parsefile->linno++;
     11067            setprompt_if(doprompt, 2);
     11068            c = pgetc();
     11069            goto loop;              /* continue outer loop */
     11070        case CWORD:
     11071            USTPUTC(c, out);
     11072            break;
     11073        case CCTL:
     11074            if (eofmark == NULL || dblquote)
     11075                USTPUTC(CTLESC, out);
     11076#if ENABLE_ASH_BASH_COMPAT
     11077            if (c == '\\' && bash_dollar_squote) {
     11078                c = decode_dollar_squote();
     11079                if (c & 0x100) {
     11080                    USTPUTC('\\', out);
     11081                    c = (unsigned char)c;
     11082                }
     11083            }
     11084#endif
     11085            USTPUTC(c, out);
     11086            break;
     11087        case CBACK:     /* backslash */
     11088            c = pgetc_without_PEOA();
     11089            if (c == PEOF) {
     11090                USTPUTC(CTLESC, out);
     11091                USTPUTC('\\', out);
     11092                pungetc();
     11093            } else if (c == '\n') {
     11094                setprompt_if(doprompt, 2);
     11095            } else {
     11096#if ENABLE_ASH_EXPAND_PRMT
     11097                if (c == '$' && pssyntax) {
     11098                    USTPUTC(CTLESC, out);
     11099                    USTPUTC('\\', out);
     11100                }
     11101#endif
     11102                /* Backslash is retained if we are in "str" and next char isn't special */
     11103                if (dblquote
     11104                 && c != '\\'
     11105                 && c != '`'
     11106                 && c != '$'
     11107                 && (c != '"' || eofmark != NULL)
     11108                ) {
     11109                    USTPUTC(CTLESC, out);
     11110                    USTPUTC('\\', out);
     11111                }
     11112                if (SIT(c, SQSYNTAX) == CCTL)
    993311113                    USTPUTC(CTLESC, out);
    993411114                USTPUTC(c, out);
    9935                 break;
    9936             case CBACK:     /* backslash */
    9937                 c = pgetc2();
    9938                 if (c == PEOF) {
    9939                     USTPUTC(CTLESC, out);
    9940                     USTPUTC('\\', out);
     11115                quotef = 1;
     11116            }
     11117            break;
     11118        case CSQUOTE:
     11119            syntax = SQSYNTAX;
     11120 quotemark:
     11121            if (eofmark == NULL) {
     11122                USTPUTC(CTLQUOTEMARK, out);
     11123            }
     11124            break;
     11125        case CDQUOTE:
     11126            syntax = DQSYNTAX;
     11127            dblquote = 1;
     11128            goto quotemark;
     11129        case CENDQUOTE:
     11130            IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
     11131            if (eofmark != NULL && arinest == 0
     11132             && varnest == 0
     11133            ) {
     11134                USTPUTC(c, out);
     11135            } else {
     11136                if (dqvarnest == 0) {
     11137                    syntax = BASESYNTAX;
     11138                    dblquote = 0;
     11139                }
     11140                quotef = 1;
     11141                goto quotemark;
     11142            }
     11143            break;
     11144        case CVAR:      /* '$' */
     11145            PARSESUB();             /* parse substitution */
     11146            break;
     11147        case CENDVAR:   /* '}' */
     11148            if (varnest > 0) {
     11149                varnest--;
     11150                if (dqvarnest > 0) {
     11151                    dqvarnest--;
     11152                }
     11153                c = CTLENDVAR;
     11154            }
     11155            USTPUTC(c, out);
     11156            break;
     11157#if ENABLE_SH_MATH_SUPPORT
     11158        case CLP:       /* '(' in arithmetic */
     11159            parenlevel++;
     11160            USTPUTC(c, out);
     11161            break;
     11162        case CRP:       /* ')' in arithmetic */
     11163            if (parenlevel > 0) {
     11164                parenlevel--;
     11165            } else {
     11166                if (pgetc() == ')') {
     11167                    if (--arinest == 0) {
     11168                        syntax = prevsyntax;
     11169                        dblquote = (syntax == DQSYNTAX);
     11170                        c = CTLENDARI;
     11171                    }
     11172                } else {
     11173                    /*
     11174                     * unbalanced parens
     11175                     * (don't 2nd guess - no error)
     11176                     */
    994111177                    pungetc();
    9942                 } else if (c == '\n') {
    9943                     if (doprompt)
    9944                         setprompt(2);
    9945                 } else {
    9946                     if (dblquote &&
    9947                         c != '\\' && c != '`' &&
    9948                         c != '$' && (
    9949                             c != '"' ||
    9950                             eofmark != NULL)
    9951                     ) {
    9952                         USTPUTC(CTLESC, out);
    9953                         USTPUTC('\\', out);
    9954                     }
    9955                     if (SIT(c, SQSYNTAX) == CCTL)
    9956                         USTPUTC(CTLESC, out);
    9957                     USTPUTC(c, out);
    9958                     quotef++;
    995911178                }
    9960                 break;
    9961             case CSQUOTE:
    9962                 syntax = SQSYNTAX;
    9963  quotemark:
    9964                 if (eofmark == NULL) {
    9965                     USTPUTC(CTLQUOTEMARK, out);
     11179            }
     11180            USTPUTC(c, out);
     11181            break;
     11182#endif
     11183        case CBQUOTE:   /* '`' */
     11184            PARSEBACKQOLD();
     11185            break;
     11186        case CENDFILE:
     11187            goto endword;           /* exit outer loop */
     11188        case CIGN:
     11189            break;
     11190        default:
     11191            if (varnest == 0) {
     11192#if ENABLE_ASH_BASH_COMPAT
     11193                if (c == '&') {
     11194                    if (pgetc() == '>')
     11195                        c = 0x100 + '>'; /* flag &> */
     11196                    pungetc();
    996611197                }
    9967                 break;
    9968             case CDQUOTE:
    9969                 syntax = DQSYNTAX;
    9970                 dblquote = 1;
    9971                 goto quotemark;
    9972             case CENDQUOTE:
    9973                 if (eofmark != NULL && arinest == 0
    9974                  && varnest == 0
    9975                 ) {
    9976                     USTPUTC(c, out);
    9977                 } else {
    9978                     if (dqvarnest == 0) {
    9979                         syntax = BASESYNTAX;
    9980                         dblquote = 0;
    9981                     }
    9982                     quotef++;
    9983                     goto quotemark;
    9984                 }
    9985                 break;
    9986             case CVAR:      /* '$' */
    9987                 PARSESUB();             /* parse substitution */
    9988                 break;
    9989             case CENDVAR:   /* '}' */
    9990                 if (varnest > 0) {
    9991                     varnest--;
    9992                     if (dqvarnest > 0) {
    9993                         dqvarnest--;
    9994                     }
    9995                     USTPUTC(CTLENDVAR, out);
    9996                 } else {
    9997                     USTPUTC(c, out);
    9998                 }
    9999                 break;
    10000 #if ENABLE_ASH_MATH_SUPPORT
    10001             case CLP:       /* '(' in arithmetic */
    10002                 parenlevel++;
     11198#endif
     11199                goto endword;   /* exit outer loop */
     11200            }
     11201            IF_ASH_ALIAS(if (c != PEOA))
    1000311202                USTPUTC(c, out);
    10004                 break;
    10005             case CRP:       /* ')' in arithmetic */
    10006                 if (parenlevel > 0) {
    10007                     USTPUTC(c, out);
    10008                     --parenlevel;
    10009                 } else {
    10010                     if (pgetc() == ')') {
    10011                         if (--arinest == 0) {
    10012                             USTPUTC(CTLENDARI, out);
    10013                             syntax = prevsyntax;
    10014                             if (syntax == DQSYNTAX)
    10015                                 dblquote = 1;
    10016                             else
    10017                                 dblquote = 0;
    10018                         } else
    10019                             USTPUTC(')', out);
    10020                     } else {
    10021                         /*
    10022                          * unbalanced parens
    10023                          *  (don't 2nd guess - no error)
    10024                          */
    10025                         pungetc();
    10026                         USTPUTC(')', out);
    10027                     }
    10028                 }
    10029                 break;
    10030 #endif
    10031             case CBQUOTE:   /* '`' */
    10032                 PARSEBACKQOLD();
    10033                 break;
    10034             case CENDFILE:
    10035                 goto endword;           /* exit outer loop */
    10036             case CIGN:
    10037                 break;
    10038             default:
    10039                 if (varnest == 0)
    10040                     goto endword;   /* exit outer loop */
    10041 #if ENABLE_ASH_ALIAS
    10042                 if (c != PEOA)
    10043 #endif
    10044                     USTPUTC(c, out);
    10045 
    10046             }
    10047             c = pgetc_macro();
    10048         }
    10049     }
     11203        }
     11204        c = pgetc_fast();
     11205    } /* for (;;) */
    1005011206 endword:
    10051 #if ENABLE_ASH_MATH_SUPPORT
     11207
     11208#if ENABLE_SH_MATH_SUPPORT
    1005211209    if (syntax == ARISYNTAX)
    10053         raise_error_syntax("Missing '))'");
     11210        raise_error_syntax("missing '))'");
    1005411211#endif
    1005511212    if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
    10056         raise_error_syntax("Unterminated quoted string");
     11213        raise_error_syntax("unterminated quoted string");
    1005711214    if (varnest != 0) {
    10058         startlinno = plinno;
     11215        startlinno = g_parsefile->linno;
    1005911216        /* { */
    10060         raise_error_syntax("Missing '}'");
     11217        raise_error_syntax("missing '}'");
    1006111218    }
    1006211219    USTPUTC('\0', out);
     
    1006411221    out = stackblock();
    1006511222    if (eofmark == NULL) {
    10066         if ((c == '>' || c == '<')
     11223        if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
    1006711224         && quotef == 0
    10068          && len <= 2
    10069          && (*out == '\0' || isdigit(*out))) {
    10070             PARSEREDIR();
    10071             return lasttoken = TREDIR;
    10072         } else {
    10073             pungetc();
    10074         }
     11225        ) {
     11226            if (isdigit_str9(out)) {
     11227                PARSEREDIR(); /* passed as params: out, c */
     11228                lasttoken = TREDIR;
     11229                return lasttoken;
     11230            }
     11231            /* else: non-number X seen, interpret it
     11232             * as "NNNX>file" = "NNNX >file" */
     11233        }
     11234        pungetc();
    1007511235    }
    1007611236    quoteflag = quotef;
     
    1009011250    if (eofmark) {
    1009111251#if ENABLE_ASH_ALIAS
    10092         if (c == PEOA) {
    10093             c = pgetc2();
    10094         }
     11252        if (c == PEOA)
     11253            c = pgetc_without_PEOA();
    1009511254#endif
    1009611255        if (striptabs) {
    1009711256            while (c == '\t') {
    10098                 c = pgetc2();
     11257                c = pgetc_without_PEOA();
    1009911258            }
    1010011259        }
     
    1010411263
    1010511264                p = line;
    10106                 for (q = eofmark + 1; *q && *p == *q; p++, q++);
     11265                for (q = eofmark + 1; *q && *p == *q; p++, q++)
     11266                    continue;
    1010711267                if (*p == '\n' && *q == '\0') {
    1010811268                    c = PEOF;
    10109                     plinno++;
     11269                    g_parsefile->linno++;
    1011011270                    needprompt = doprompt;
    1011111271                } else {
     
    1012411284 */
    1012511285parseredir: {
    10126     char fd = *out;
     11286    /* out is already checked to be a valid number or "" */
     11287    int fd = (*out == '\0' ? -1 : atoi(out));
    1012711288    union node *np;
    1012811289
    10129     np = stalloc(sizeof(struct nfile));
     11290    np = stzalloc(sizeof(struct nfile));
    1013011291    if (c == '>') {
    1013111292        np->nfile.fd = 1;
     
    1013711298        else if (c == '&')
    1013811299            np->type = NTOFD;
     11300            /* it also can be NTO2 (>&file), but we can't figure it out yet */
    1013911301        else {
    1014011302            np->type = NTO;
    1014111303            pungetc();
    1014211304        }
    10143     } else {        /* c == '<' */
    10144         np->nfile.fd = 0;
     11305    }
     11306#if ENABLE_ASH_BASH_COMPAT
     11307    else if (c == 0x100 + '>') { /* this flags &> redirection */
     11308        np->nfile.fd = 1;
     11309        pgetc(); /* this is '>', no need to check */
     11310        np->type = NTO2;
     11311    }
     11312#endif
     11313    else { /* c == '<' */
     11314        /*np->nfile.fd = 0; - stzalloc did it */
    1014511315        c = pgetc();
    1014611316        switch (c) {
    1014711317        case '<':
    1014811318            if (sizeof(struct nfile) != sizeof(struct nhere)) {
    10149                 np = stalloc(sizeof(struct nhere));
    10150                 np->nfile.fd = 0;
     11319                np = stzalloc(sizeof(struct nhere));
     11320                /*np->nfile.fd = 0; - stzalloc did it */
    1015111321            }
    1015211322            np->type = NHERE;
    10153             heredoc = stalloc(sizeof(struct heredoc));
     11323            heredoc = stzalloc(sizeof(struct heredoc));
    1015411324            heredoc->here = np;
    1015511325            c = pgetc();
     
    1015711327                heredoc->striptabs = 1;
    1015811328            } else {
    10159                 heredoc->striptabs = 0;
     11329                /*heredoc->striptabs = 0; - stzalloc did it */
    1016011330                pungetc();
    1016111331            }
     
    1017611346        }
    1017711347    }
    10178     if (fd != '\0')
    10179         np->nfile.fd = fd - '0';
     11348    if (fd >= 0)
     11349        np->nfile.fd = fd;
    1018011350    redirnode = np;
    1018111351    goto parseredir_return;
     
    1019011360 * (assuming ascii char codes, as the original implementation did) */
    1019111361#define is_special(c) \
    10192     ((((unsigned int)c) - 33 < 32) \
    10193             && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
     11362    (((unsigned)(c) - 33 < 32) \
     11363            && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
    1019411364parsesub: {
    10195     int subtype;
     11365    unsigned char subtype;
    1019611366    int typeloc;
    1019711367    int flags;
    10198     char *p;
    10199     static const char types[] ALIGN1 = "}-+?=";
    1020011368
    1020111369    c = pgetc();
    10202     if (
    10203         c <= PEOA_OR_PEOF  ||
    10204         (c != '(' && c != '{' && !is_name(c) && !is_special(c))
     11370    if (c > 255 /* PEOA or PEOF */
     11371     || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
    1020511372    ) {
    10206         USTPUTC('$', out);
     11373#if ENABLE_ASH_BASH_COMPAT
     11374        if (c == '\'')
     11375            bash_dollar_squote = 1;
     11376        else
     11377#endif
     11378            USTPUTC('$', out);
    1020711379        pungetc();
    10208     } else if (c == '(') {  /* $(command) or $((arith)) */
     11380    } else if (c == '(') {
     11381        /* $(command) or $((arith)) */
    1020911382        if (pgetc() == '(') {
    10210 #if ENABLE_ASH_MATH_SUPPORT
     11383#if ENABLE_SH_MATH_SUPPORT
    1021111384            PARSEARITH();
    1021211385#else
    10213             raise_error_syntax("We unsupport $((arith))");
     11386            raise_error_syntax("you disabled math support for $((arith)) syntax");
    1021411387#endif
    1021511388        } else {
     
    1021811391        }
    1021911392    } else {
     11393        /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
    1022011394        USTPUTC(CTLVAR, out);
    1022111395        typeloc = out - (char *)stackblock();
     
    1022711401                c = pgetc();
    1022811402                if (c == '}')
    10229                     c = '#';
     11403                    c = '#'; /* ${#} - same as $# */
    1023011404                else
    10231                     subtype = VSLENGTH;
    10232             } else
     11405                    subtype = VSLENGTH; /* ${#VAR} */
     11406            } else {
    1023311407                subtype = 0;
    10234         }
    10235         if (c > PEOA_OR_PEOF && is_name(c)) {
     11408            }
     11409        }
     11410        if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
     11411            /* $[{[#]]NAME[}] */
    1023611412            do {
    1023711413                STPUTC(c, out);
    1023811414                c = pgetc();
    10239             } while (c > PEOA_OR_PEOF && is_in_name(c));
     11415            } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
    1024011416        } else if (isdigit(c)) {
     11417            /* $[{[#]]NUM[}] */
    1024111418            do {
    1024211419                STPUTC(c, out);
     
    1024411421            } while (isdigit(c));
    1024511422        } else if (is_special(c)) {
     11423            /* $[{[#]]<specialchar>[}] */
    1024611424            USTPUTC(c, out);
    1024711425            c = pgetc();
    10248         } else
    10249  badsub:        raise_error_syntax("Bad substitution");
     11426        } else {
     11427 badsub:
     11428            raise_error_syntax("bad substitution");
     11429        }
     11430        if (c != '}' && subtype == VSLENGTH) {
     11431            /* ${#VAR didn't end with } */
     11432            goto badsub;
     11433        }
    1025011434
    1025111435        STPUTC('=', out);
    1025211436        flags = 0;
    1025311437        if (subtype == 0) {
     11438            /* ${VAR...} but not $VAR or ${#VAR} */
     11439            /* c == first char after VAR */
    1025411440            switch (c) {
    1025511441            case ':':
     11442                c = pgetc();
     11443#if ENABLE_ASH_BASH_COMPAT
     11444                if (c == ':' || c == '$' || isdigit(c)) {
     11445//TODO: support more general format ${v:EXPR:EXPR},
     11446// where EXPR follows $(()) rules
     11447                    subtype = VSSUBSTR;
     11448                    pungetc();
     11449                    break; /* "goto do_pungetc" is bigger (!) */
     11450                }
     11451#endif
    1025611452                flags = VSNUL;
    10257                 c = pgetc();
    1025811453                /*FALLTHROUGH*/
    10259             default:
    10260                 p = strchr(types, c);
     11454            default: {
     11455                static const char types[] ALIGN1 = "}-+?=";
     11456                const char *p = strchr(types, c);
    1026111457                if (p == NULL)
    1026211458                    goto badsub;
    1026311459                subtype = p - types + VSNORMAL;
    1026411460                break;
     11461            }
    1026511462            case '%':
    10266             case '#':
    10267                 {
    10268                     int cc = c;
    10269                     subtype = c == '#' ? VSTRIMLEFT :
    10270                                          VSTRIMRIGHT;
    10271                     c = pgetc();
    10272                     if (c == cc)
    10273                         subtype++;
    10274                     else
    10275                         pungetc();
    10276                     break;
    10277                 }
     11463            case '#': {
     11464                int cc = c;
     11465                subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
     11466                c = pgetc();
     11467                if (c != cc)
     11468                    goto do_pungetc;
     11469                subtype++;
     11470                break;
     11471            }
     11472#if ENABLE_ASH_BASH_COMPAT
     11473            case '/':
     11474                /* ${v/[/]pattern/repl} */
     11475//TODO: encode pattern and repl separately.
     11476// Currently ${v/$var_with_slash/repl} is horribly broken
     11477                subtype = VSREPLACE;
     11478                c = pgetc();
     11479                if (c != '/')
     11480                    goto do_pungetc;
     11481                subtype++; /* VSREPLACEALL */
     11482                break;
     11483#endif
    1027811484            }
    1027911485        } else {
     11486 do_pungetc:
    1028011487            pungetc();
    1028111488        }
    1028211489        if (dblquote || arinest)
    1028311490            flags |= VSQUOTE;
    10284         *((char *)stackblock() + typeloc) = subtype | flags;
     11491        ((unsigned char *)stackblock())[typeloc] = subtype | flags;
    1028511492        if (subtype != VSNORMAL) {
    1028611493            varnest++;
     
    1030111508parsebackq: {
    1030211509    struct nodelist **nlpp;
    10303     int savepbq;
     11510    smallint savepbq;
    1030411511    union node *n;
    1030511512    char *volatile str;
     
    1030711514    struct jmploc *volatile savehandler;
    1030811515    size_t savelen;
    10309     int saveprompt = 0;
     11516    smallint saveprompt = 0;
     11517
    1031011518#ifdef __GNUC__
    1031111519    (void) &saveprompt;
    1031211520#endif
    10313 
    1031411521    savepbq = parsebackquote;
    1031511522    if (setjmp(jmploc.loc)) {
    10316         if (str)
    10317             free(str);
     11523        free(str);
    1031811524        parsebackquote = 0;
    1031911525        exception_handler = savehandler;
     
    1033511541           reread it as input, interpreting it normally.  */
    1033611542        char *pout;
    10337         int pc;
    1033811543        size_t psavelen;
    1033911544        char *pstr;
    1034011545
    10341 
    1034211546        STARTSTACKSTR(pout);
    1034311547        for (;;) {
    10344             if (needprompt) {
    10345                 setprompt(2);
    10346             }
     11548            int pc;
     11549
     11550            setprompt_if(needprompt, 2);
    1034711551            pc = pgetc();
    1034811552            switch (pc) {
     
    1035311557                pc = pgetc();
    1035411558                if (pc == '\n') {
    10355                     plinno++;
    10356                     if (doprompt)
    10357                         setprompt(2);
     11559                    g_parsefile->linno++;
     11560                    setprompt_if(doprompt, 2);
    1035811561                    /*
    1035911562                     * If eating a newline, avoid putting
     
    1036511568                }
    1036611569                if (pc != '\\' && pc != '`' && pc != '$'
    10367                  && (!dblquote || pc != '"'))
     11570                 && (!dblquote || pc != '"')
     11571                ) {
    1036811572                    STPUTC('\\', pout);
    10369                 if (pc > PEOA_OR_PEOF) {
     11573                }
     11574                if (pc <= 255 /* not PEOA or PEOF */) {
    1037011575                    break;
    1037111576                }
     
    1037311578
    1037411579            case PEOF:
    10375 #if ENABLE_ASH_ALIAS
    10376             case PEOA:
    10377 #endif
    10378                 startlinno = plinno;
     11580            IF_ASH_ALIAS(case PEOA:)
     11581                startlinno = g_parsefile->linno;
    1037911582                raise_error_syntax("EOF in backquote substitution");
    1038011583
    1038111584            case '\n':
    10382                 plinno++;
     11585                g_parsefile->linno++;
    1038311586                needprompt = doprompt;
    1038411587                break;
     
    1040011603    while (*nlpp)
    1040111604        nlpp = &(*nlpp)->next;
    10402     *nlpp = stalloc(sizeof(**nlpp));
    10403     (*nlpp)->next = NULL;
     11605    *nlpp = stzalloc(sizeof(**nlpp));
     11606    /* (*nlpp)->next = NULL; - stzalloc did it */
    1040411607    parsebackquote = oldstyle;
    1040511608
     
    1044711650}
    1044811651
    10449 #if ENABLE_ASH_MATH_SUPPORT
     11652#if ENABLE_SH_MATH_SUPPORT
    1045011653/*
    1045111654 * Parse an arithmetic expansion (indicate start of one and set state)
     
    1049411697/* singles must be first! */
    1049511698static const char xxreadtoken_chars[7] ALIGN1 = {
    10496     '\n', '(', ')', '&', '|', ';', 0
     11699    '\n', '(', ')', /* singles */
     11700    '&', '|', ';',  /* doubles */
     11701    0
    1049711702};
     11703
     11704#define xxreadtoken_singles 3
     11705#define xxreadtoken_doubles 3
    1049811706
    1049911707static const char xxreadtoken_tokens[] ALIGN1 = {
     
    1050411712};
    1050511713
    10506 #define xxreadtoken_doubles \
    10507     (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
    10508 #define xxreadtoken_singles \
    10509     (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
    10510 
    1051111714static int
    1051211715xxreadtoken(void)
     
    1051811721        return lasttoken;
    1051911722    }
    10520     if (needprompt) {
    10521         setprompt(2);
    10522     }
    10523     startlinno = plinno;
     11723    setprompt_if(needprompt, 2);
     11724    startlinno = g_parsefile->linno;
    1052411725    for (;;) {                      /* until token or start of word found */
    10525         c = pgetc_macro();
    10526 
    10527         if ((c != ' ') && (c != '\t')
    10528 #if ENABLE_ASH_ALIAS
    10529          && (c != PEOA)
    10530 #endif
    10531         ) {
    10532             if (c == '#') {
    10533                 while ((c = pgetc()) != '\n' && c != PEOF);
     11726        c = pgetc_fast();
     11727        if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
     11728            continue;
     11729
     11730        if (c == '#') {
     11731            while ((c = pgetc()) != '\n' && c != PEOF)
     11732                continue;
     11733            pungetc();
     11734        } else if (c == '\\') {
     11735            if (pgetc() != '\n') {
    1053411736                pungetc();
    10535             } else if (c == '\\') {
    10536                 if (pgetc() != '\n') {
    10537                     pungetc();
    10538                     goto READTOKEN1;
     11737                break; /* return readtoken1(...) */
     11738            }
     11739            startlinno = ++g_parsefile->linno;
     11740            setprompt_if(doprompt, 2);
     11741        } else {
     11742            const char *p;
     11743
     11744            p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
     11745            if (c != PEOF) {
     11746                if (c == '\n') {
     11747                    g_parsefile->linno++;
     11748                    needprompt = doprompt;
    1053911749                }
    10540                 startlinno = ++plinno;
    10541                 if (doprompt)
    10542                     setprompt(2);
    10543             } else {
    10544                 const char *p
    10545                     = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
    10546 
    10547                 if (c != PEOF) {
    10548                     if (c == '\n') {
    10549                         plinno++;
    10550                         needprompt = doprompt;
    10551                     }
    10552 
    10553                     p = strchr(xxreadtoken_chars, c);
    10554                     if (p == NULL) {
    10555  READTOKEN1:
    10556                         return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
    10557                     }
    10558 
    10559                     if (p - xxreadtoken_chars >= xxreadtoken_singles) {
    10560                         if (pgetc() == *p) {    /* double occurrence? */
    10561                             p += xxreadtoken_doubles + 1;
    10562                         } else {
    10563                             pungetc();
    10564                         }
     11750
     11751                p = strchr(xxreadtoken_chars, c);
     11752                if (p == NULL)
     11753                    break; /* return readtoken1(...) */
     11754
     11755                if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
     11756                    int cc = pgetc();
     11757                    if (cc == c) {    /* double occurrence? */
     11758                        p += xxreadtoken_doubles + 1;
     11759                    } else {
     11760                        pungetc();
     11761#if ENABLE_ASH_BASH_COMPAT
     11762                        if (c == '&' && cc == '>') /* &> */
     11763                            break; /* return readtoken1(...) */
     11764#endif
    1056511765                    }
    1056611766                }
    10567                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
    1056811767            }
    10569         }
    10570     } /* for */
    10571 }
    10572 #else
     11768            lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
     11769            return lasttoken;
     11770        }
     11771    } /* for (;;) */
     11772
     11773    return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
     11774}
     11775#else /* old xxreadtoken */
    1057311776#define RETURN(token)   return lasttoken = token
    1057411777static int
     
    1058111784        return lasttoken;
    1058211785    }
    10583     if (needprompt) {
    10584         setprompt(2);
    10585     }
    10586     startlinno = plinno;
     11786    setprompt_if(needprompt, 2);
     11787    startlinno = g_parsefile->linno;
    1058711788    for (;;) {      /* until token or start of word found */
    10588         c = pgetc_macro();
     11789        c = pgetc_fast();
    1058911790        switch (c) {
    1059011791        case ' ': case '\t':
    10591 #if ENABLE_ASH_ALIAS
    10592         case PEOA:
    10593 #endif
     11792        IF_ASH_ALIAS(case PEOA:)
    1059411793            continue;
    1059511794        case '#':
    10596             while ((c = pgetc()) != '\n' && c != PEOF);
     11795            while ((c = pgetc()) != '\n' && c != PEOF)
     11796                continue;
    1059711797            pungetc();
    1059811798            continue;
    1059911799        case '\\':
    1060011800            if (pgetc() == '\n') {
    10601                 startlinno = ++plinno;
    10602                 if (doprompt)
    10603                     setprompt(2);
     11801                startlinno = ++g_parsefile->linno;
     11802                setprompt_if(doprompt, 2);
    1060411803                continue;
    1060511804            }
     
    1060711806            goto breakloop;
    1060811807        case '\n':
    10609             plinno++;
     11808            g_parsefile->linno++;
    1061011809            needprompt = doprompt;
    1061111810            RETURN(TNL);
     
    1063911838#undef RETURN
    1064011839}
    10641 #endif /* NEW_xxreadtoken */
     11840#endif /* old xxreadtoken */
    1064211841
    1064311842static int
     
    1064611845    int t;
    1064711846#if DEBUG
    10648     int alreadyseen = tokpushback;
     11847    smallint alreadyseen = tokpushback;
    1064911848#endif
    1065011849
     
    1067811877        if (pp) {
    1067911878            lasttoken = t = pp - tokname_array;
    10680             TRACE(("keyword %s recognized\n", tokname(t)));
     11879            TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
    1068111880            goto out;
    1068211881        }
     
    1069911898#if DEBUG
    1070011899    if (!alreadyseen)
    10701         TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
     11900        TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
    1070211901    else
    10703         TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
     11902        TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
    1070411903#endif
    1070511904    return t;
     
    1071211911
    1071311912    t = readtoken();
    10714     tokpushback++;
     11913    tokpushback = 1;
    1071511914    return tokname_array[t][0];
    1071611915}
    1071711916
    1071811917/*
    10719  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
    10720  * valid parse tree indicating a blank line.)
     11918 * Read and parse a command.  Returns NODE_EOF on end of file.
     11919 * (NULL is a valid parse tree indicating a blank line.)
    1072111920 */
    1072211921static union node *
     
    1072711926    tokpushback = 0;
    1072811927    doprompt = interact;
    10729     if (doprompt)
    10730         setprompt(doprompt);
     11928    setprompt_if(doprompt, doprompt);
    1073111929    needprompt = 0;
    1073211930    t = readtoken();
    1073311931    if (t == TEOF)
    10734         return NEOF;
     11932        return NODE_EOF;
    1073511933    if (t == TNL)
    1073611934        return NULL;
    10737     tokpushback++;
     11935    tokpushback = 1;
    1073811936    return list(1);
    1073911937}
     
    1074911947
    1075011948    here = heredoclist;
    10751     heredoclist = 0;
     11949    heredoclist = NULL;
    1075211950
    1075311951    while (here) {
    10754         if (needprompt) {
    10755             setprompt(2);
    10756         }
    10757         readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
     11952        setprompt_if(needprompt, 2);
     11953        readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
    1075811954                here->eofmark, here->striptabs);
    10759         n = stalloc(sizeof(struct narg));
     11955        n = stzalloc(sizeof(struct narg));
    1076011956        n->narg.type = NARG;
    10761         n->narg.next = NULL;
     11957        /*n->narg.next = NULL; - stzalloc did it */
    1076211958        n->narg.text = wordtext;
    1076311959        n->narg.backquote = backquotelist;
     
    1077711973    union node n;
    1077811974
    10779     /* XXX Fix (char *) cast. */
     11975    /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
     11976     * and token processing _can_ alter it (delete NULs etc). */
    1078011977    setinputstring((char *)ps);
    10781     readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
     11978    readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
    1078211979    popfile();
    1078311980
     
    1080612003
    1080712004    skip = 0;
    10808     while ((n = parsecmd(0)) != NEOF) {
     12005    while ((n = parsecmd(0)) != NODE_EOF) {
    1080912006        evaltree(n, 0);
    1081012007        popstackmark(&smark);
     
    1082312020 * The eval command.
    1082412021 */
    10825 static int
    10826 evalcmd(int argc, char **argv)
     12022static int FAST_FUNC
     12023evalcmd(int argc UNUSED_PARAM, char **argv)
    1082712024{
    1082812025    char *p;
    1082912026    char *concat;
    10830     char **ap;
    10831 
    10832     if (argc > 1) {
     12027
     12028    if (argv[1]) {
    1083312029        p = argv[1];
    10834         if (argc > 2) {
     12030        argv += 2;
     12031        if (argv[0]) {
    1083512032            STARTSTACKSTR(concat);
    10836             ap = argv + 2;
    1083712033            for (;;) {
    1083812034                concat = stack_putstr(p, concat);
    10839                 p = *ap++;
     12035                p = *argv++;
    1084012036                if (p == NULL)
    1084112037                    break;
     
    1084612042        }
    1084712043        evalstring(p, ~SKIPEVAL);
    10848 
    1084912044    }
    1085012045    return exitstatus;
     
    1085212047
    1085312048/*
    10854  * Read and execute commands.  "Top" is nonzero for the top level command
    10855  * loop; it turns on prompting if the shell is interactive.
     12049 * Read and execute commands.
     12050 * "Top" is nonzero for the top level command loop;
     12051 * it turns on prompting if the shell is interactive.
    1085612052 */
    1085712053static int
     
    1086912065        setstackmark(&smark);
    1087012066#if JOBS
    10871         if (jobctl)
     12067        if (doing_jobctl)
    1087212068            showjobs(stderr, SHOW_CHANGED);
    1087312069#endif
     
    1088012076        }
    1088112077        n = parsecmd(inter);
    10882         /* showtree(n); DEBUG */
    10883         if (n == NEOF) {
     12078#if DEBUG
     12079        if (DEBUG > 2 && debug && (n != NODE_EOF))
     12080            showtree(n);
     12081#endif
     12082        if (n == NODE_EOF) {
    1088412083            if (!top || numeof >= 50)
    1088512084                break;
     
    1092212121        return name;
    1092312122
    10924     while ((fullname = padvance(&path, name)) != NULL) {
     12123    /* IIRC standards do not say whether . is to be searched.
     12124     * And it is even smaller this way, making it unconditional for now:
     12125     */
     12126    if (1) { /* ENABLE_ASH_BASH_COMPAT */
     12127        fullname = name;
     12128        goto try_cur_dir;
     12129    }
     12130
     12131    while ((fullname = path_advance(&path, name)) != NULL) {
     12132 try_cur_dir:
    1092512133        if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
    1092612134            /*
     
    1093012138            return fullname;
    1093112139        }
    10932         stunalloc(fullname);
     12140        if (fullname != name)
     12141            stunalloc(fullname);
    1093312142    }
    1093412143
     
    1093812147}
    1093912148
    10940 static int
     12149static int FAST_FUNC
    1094112150dotcmd(int argc, char **argv)
    1094212151{
     12152    char *fullname;
    1094312153    struct strlist *sp;
    1094412154    volatile struct shparam saveparam;
    10945     int status = 0;
    1094612155
    1094712156    for (sp = cmdenviron; sp; sp = sp->next)
    1094812157        setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
    1094912158
    10950     if (argc >= 2) {        /* That's what SVR2 does */
    10951         char *fullname;
    10952 
    10953         fullname = find_dot_file(argv[1]);
    10954 
    10955         if (argc > 2) {
    10956             saveparam = shellparam;
    10957             shellparam.malloc = 0;
    10958             shellparam.nparam = argc - 2;
    10959             shellparam.p = argv + 2;
    10960         };
    10961 
    10962         setinputfile(fullname, INPUT_PUSH_FILE);
    10963         commandname = fullname;
    10964         cmdloop(0);
    10965         popfile();
    10966 
    10967         if (argc > 2) {
    10968             freeparam(&shellparam);
    10969             shellparam = saveparam;
    10970         };
    10971         status = exitstatus;
    10972     }
    10973     return status;
    10974 }
    10975 
    10976 static int
    10977 exitcmd(int argc, char **argv)
     12159    if (!argv[1]) {
     12160        /* bash says: "bash: .: filename argument required" */
     12161        return 2; /* bash compat */
     12162    }
     12163
     12164    /* "false; . empty_file; echo $?" should print 0, not 1: */
     12165    exitstatus = 0;
     12166
     12167    fullname = find_dot_file(argv[1]);
     12168
     12169    argv += 2;
     12170    argc -= 2;
     12171    if (argc) { /* argc > 0, argv[0] != NULL */
     12172        saveparam = shellparam;
     12173        shellparam.malloced = 0;
     12174        shellparam.nparam = argc;
     12175        shellparam.p = argv;
     12176    };
     12177
     12178    setinputfile(fullname, INPUT_PUSH_FILE);
     12179    commandname = fullname;
     12180    cmdloop(0);
     12181    popfile();
     12182
     12183    if (argc) {
     12184        freeparam(&shellparam);
     12185        shellparam = saveparam;
     12186    };
     12187
     12188    return exitstatus;
     12189}
     12190
     12191static int FAST_FUNC
     12192exitcmd(int argc UNUSED_PARAM, char **argv)
    1097812193{
    1097912194    if (stoppedjobs())
    1098012195        return 0;
    10981     if (argc > 1)
     12196    if (argv[1])
    1098212197        exitstatus = number(argv[1]);
    1098312198    raise_exception(EXEXIT);
    1098412199    /* NOTREACHED */
    1098512200}
    10986 
    10987 #if ENABLE_ASH_BUILTIN_ECHO
    10988 static int
    10989 echocmd(int argc, char **argv)
    10990 {
    10991     return bb_echo(argv);
    10992 }
    10993 #endif
    10994 
    10995 #if ENABLE_ASH_BUILTIN_TEST
    10996 static int
    10997 testcmd(int argc, char **argv)
    10998 {
    10999     return test_main(argc, argv);
    11000 }
    11001 #endif
    1100212201
    1100312202/*
     
    1109912298
    1110012299#if ENABLE_FEATURE_SH_STANDALONE
    11101     if (find_applet_by_name(name)) {
    11102         entry->cmdtype = CMDNORMAL;
    11103         entry->u.index = -1;
    11104         return;
     12300    {
     12301        int applet_no = find_applet_by_name(name);
     12302        if (applet_no >= 0) {
     12303            entry->cmdtype = CMDNORMAL;
     12304            entry->u.index = -2 - applet_no;
     12305            return;
     12306        }
    1110512307    }
    1110612308#endif
     
    1111812320    idx = -1;
    1111912321 loop:
    11120     while ((fullname = padvance(&path, name)) != NULL) {
     12322    while ((fullname = path_advance(&path, name)) != NULL) {
    1112112323        stunalloc(fullname);
    1112212324        /* NB: code below will still use fullname
     
    1112812330                    goto builtin_success;
    1112912331                continue;
    11130             } else if (!(act & DO_NOFUNC)
    11131              && prefix(pathopt, "func")) {
    11132                 /* handled below */
    11133             } else {
    11134                 /* ignore unimplemented options */
     12332            }
     12333            if ((act & DO_NOFUNC)
     12334             || !prefix(pathopt, "func")
     12335            ) {     /* ignore unimplemented options */
    1113512336                continue;
    1113612337            }
     
    1121212413 * The trap builtin.
    1121312414 */
    11214 static int
    11215 trapcmd(int argc, char **argv)
     12415static int FAST_FUNC
     12416trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    1121612417{
    1121712418    char *action;
    1121812419    char **ap;
    11219     int signo;
     12420    int signo, exitcode;
    1122012421
    1122112422    nextopt(nullstr);
     
    1122312424    if (!*ap) {
    1122412425        for (signo = 0; signo < NSIG; signo++) {
    11225             if (trap[signo] != NULL) {
    11226                 const char *sn;
    11227 
    11228                 sn = get_signame(signo);
     12426            char *tr = trap_ptr[signo];
     12427            if (tr) {
     12428                /* note: bash adds "SIG", but only if invoked
     12429                 * as "bash". If called as "sh", or if set -o posix,
     12430                 * then it prints short signal names.
     12431                 * We are printing short names: */
    1122912432                out1fmt("trap -- %s %s\n",
    11230                     single_quote(trap[signo]), sn);
     12433                        single_quote(tr),
     12434                        get_signame(signo));
     12435        /* trap_ptr != trap only if we are in special-cased `trap` code.
     12436         * In this case, we will exit very soon, no need to free(). */
     12437                /* if (trap_ptr != trap && tp[0]) */
     12438                /*  free(tr); */
    1123112439            }
    1123212440        }
     12441        /*
     12442        if (trap_ptr != trap) {
     12443            free(trap_ptr);
     12444            trap_ptr = trap;
     12445        }
     12446        */
    1123312447        return 0;
    1123412448    }
    11235     if (!ap[1])
    11236         action = NULL;
    11237     else
     12449
     12450    action = NULL;
     12451    if (ap[1])
    1123812452        action = *ap++;
     12453    exitcode = 0;
    1123912454    while (*ap) {
    1124012455        signo = get_signum(*ap);
    11241         if (signo < 0)
    11242             ash_msg_and_raise_error("%s: bad trap", *ap);
     12456        if (signo < 0) {
     12457            /* Mimic bash message exactly */
     12458            ash_msg("%s: invalid signal specification", *ap);
     12459            exitcode = 1;
     12460            goto next;
     12461        }
    1124312462        INT_OFF;
    1124412463        if (action) {
     
    1124812467                action = ckstrdup(action);
    1124912468        }
    11250         if (trap[signo])
    11251             free(trap[signo]);
     12469        free(trap[signo]);
     12470        if (action)
     12471            may_have_traps = 1;
    1125212472        trap[signo] = action;
    1125312473        if (signo != 0)
    1125412474            setsignal(signo);
    1125512475        INT_ON;
     12476 next:
    1125612477        ap++;
    1125712478    }
    11258     return 0;
     12479    return exitcode;
    1125912480}
    1126012481
     
    1126612487 * Lists available builtins
    1126712488 */
    11268 static int
    11269 helpcmd(int argc, char **argv)
    11270 {
    11271     int col, i;
    11272 
    11273     out1fmt("\nBuilt-in commands:\n-------------------\n");
     12489static int FAST_FUNC
     12490helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
     12491{
     12492    unsigned col;
     12493    unsigned i;
     12494
     12495    out1fmt(
     12496        "Built-in commands:\n"
     12497        "------------------\n");
    1127412498    for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
    1127512499        col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
     
    1128112505    }
    1128212506#if ENABLE_FEATURE_SH_STANDALONE
    11283     for (i = 0; i < NUM_APPLETS; i++) {
    11284         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
    11285         if (col > 60) {
    11286             out1fmt("\n");
    11287             col = 0;
     12507    {
     12508        const char *a = applet_names;
     12509        while (*a) {
     12510            col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
     12511            if (col > 60) {
     12512                out1fmt("\n");
     12513                col = 0;
     12514            }
     12515            a += strlen(a) + 1;
    1128812516        }
    1128912517    }
     
    1129712525 * The export and readonly commands.
    1129812526 */
    11299 static int
    11300 exportcmd(int argc, char **argv)
     12527static int FAST_FUNC
     12528exportcmd(int argc UNUSED_PARAM, char **argv)
    1130112529{
    1130212530    struct var *vp;
     
    1130412532    const char *p;
    1130512533    char **aptr;
    11306     int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
     12534    int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
    1130712535
    1130812536    if (nextopt("p") != 'p') {
     
    1133912567
    1134012568    cmdp = cmdlookup(name, 0);
    11341     if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
     12569    if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
    1134212570        delete_cmd_entry();
    1134312571}
     
    1134812576 * with the same name.
    1134912577 */
    11350 static int
    11351 unsetcmd(int argc, char **argv)
     12578static int FAST_FUNC
     12579unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
    1135212580{
    1135312581    char **ap;
     
    1135612584    int ret = 0;
    1135712585
    11358     while ((i = nextopt("vf")) != '\0') {
     12586    while ((i = nextopt("vf")) != 0) {
    1135912587        flag = i;
    1136012588    }
     
    1137212600    return ret & 1;
    1137312601}
    11374 
    11375 
    11376 /*      setmode.c      */
    11377 
    11378 #include <sys/times.h>
    1137912602
    1138012603static const unsigned char timescmd_str[] ALIGN1 = {
     
    1138512608    0
    1138612609};
    11387 
    11388 static int
    11389 timescmd(int ac, char **av)
    11390 {
    11391     long clk_tck, s, t;
     12610static int FAST_FUNC
     12611timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
     12612{
     12613    unsigned long clk_tck, s, t;
    1139212614    const unsigned char *p;
    1139312615    struct tms buf;
     
    1140012622        t = *(clock_t *)(((char *) &buf) + p[1]);
    1140112623        s = t / clk_tck;
    11402         out1fmt("%ldm%ld.%.3lds%c",
    11403             s/60, s%60,
    11404             ((t - s * clk_tck) * 1000) / clk_tck,
     12624        t = t % clk_tck;
     12625        out1fmt("%lum%lu.%03lus%c",
     12626            s / 60, s % 60,
     12627            (t * 1000) / clk_tck,
    1140512628            p[0]);
    11406     } while (*(p += 2));
     12629        p += 2;
     12630    } while (*p);
    1140712631
    1140812632    return 0;
    1140912633}
    1141012634
    11411 #if ENABLE_ASH_MATH_SUPPORT
    11412 static arith_t
    11413 dash_arith(const char *s)
    11414 {
    11415     arith_t result;
    11416     int errcode = 0;
    11417 
    11418     INT_OFF;
    11419     result = arith(s, &errcode);
    11420     if (errcode < 0) {
    11421         if (errcode == -3)
    11422             ash_msg_and_raise_error("exponent less than 0");
    11423         if (errcode == -2)
    11424             ash_msg_and_raise_error("divide by zero");
    11425         if (errcode == -5)
    11426             ash_msg_and_raise_error("expression recursion loop detected");
    11427         raise_error_syntax(s);
    11428     }
    11429     INT_ON;
    11430 
    11431     return result;
    11432 }
    11433 
    11434 /*
    11435  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
    11436  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
     12635#if ENABLE_SH_MATH_SUPPORT
     12636/*
     12637 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
     12638 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
    1143712639 *
    11438  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
    11439  */
    11440 static int
    11441 letcmd(int argc, char **argv)
    11442 {
    11443     char **ap;
    11444     arith_t i = 0;
    11445 
    11446     ap = argv + 1;
    11447     if (!*ap)
     12640 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
     12641 */
     12642static int FAST_FUNC
     12643letcmd(int argc UNUSED_PARAM, char **argv)
     12644{
     12645    arith_t i;
     12646
     12647    argv++;
     12648    if (!*argv)
    1144812649        ash_msg_and_raise_error("expression expected");
    11449     for (ap = argv + 1; *ap; ap++) {
    11450         i = dash_arith(*ap);
    11451     }
     12650    do {
     12651        i = ash_arith(*argv);
     12652    } while (*++argv);
    1145212653
    1145312654    return !i;
    1145412655}
    11455 #endif /* ASH_MATH_SUPPORT */
    11456 
    11457 
    11458 /* ============ miscbltin.c
    11459  *
    11460  * Miscellaneous builtins.
    11461  */
    11462 
    11463 #undef rflag
    11464 
    11465 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
    11466 typedef enum __rlimit_resource rlim_t;
    11467 #endif
    11468 
    11469 /*
    11470  * The read builtin.  The -e option causes backslashes to escape the
    11471  * following character.
    11472  *
     12656#endif
     12657
     12658/*
     12659 * The read builtin. Options:
     12660 *      -r              Do not interpret '\' specially
     12661 *      -s              Turn off echo (tty only)
     12662 *      -n NCHARS       Read NCHARS max
     12663 *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
     12664 *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
     12665 *      -u FD           Read from given FD instead of fd 0
    1147312666 * This uses unbuffered input, which may be avoidable in some cases.
    11474  */
    11475 static int
    11476 readcmd(int argc, char **argv)
    11477 {
    11478     char **ap;
    11479     int backslash;
    11480     char c;
    11481     int rflag;
    11482     char *prompt;
    11483     const char *ifs;
    11484     char *p;
    11485     int startword;
    11486     int status;
     12667 * TODO: bash also has:
     12668 *      -a ARRAY        Read into array[0],[1],etc
     12669 *      -d DELIM        End on DELIM char, not newline
     12670 *      -e              Use line editing (tty only)
     12671 */
     12672static int FAST_FUNC
     12673readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
     12674{
     12675    char *opt_n = NULL;
     12676    char *opt_p = NULL;
     12677    char *opt_t = NULL;
     12678    char *opt_u = NULL;
     12679    int read_flags = 0;
     12680    const char *r;
    1148712681    int i;
    11488 #if ENABLE_ASH_READ_NCHARS
    11489     int nch_flag = 0;
    11490     int nchars = 0;
    11491     int silent = 0;
    11492     struct termios tty, old_tty;
    11493 #endif
    11494 #if ENABLE_ASH_READ_TIMEOUT
    11495     fd_set set;
    11496     struct timeval ts;
    11497 
    11498     ts.tv_sec = ts.tv_usec = 0;
    11499 #endif
    11500 
    11501     rflag = 0;
    11502     prompt = NULL;
    11503 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
    11504     while ((i = nextopt("p:rt:n:s")) != '\0')
    11505 #elif ENABLE_ASH_READ_NCHARS
    11506     while ((i = nextopt("p:rn:s")) != '\0')
    11507 #elif ENABLE_ASH_READ_TIMEOUT
    11508     while ((i = nextopt("p:rt:")) != '\0')
    11509 #else
    11510     while ((i = nextopt("p:r")) != '\0')
    11511 #endif
    11512     {
     12682
     12683    while ((i = nextopt("p:u:rt:n:s")) != '\0') {
    1151312684        switch (i) {
    1151412685        case 'p':
    11515             prompt = optionarg;
     12686            opt_p = optionarg;
    1151612687            break;
    11517 #if ENABLE_ASH_READ_NCHARS
    1151812688        case 'n':
    11519             nchars = strtol(optionarg, &p, 10);
    11520             if (*p)
    11521                 ash_msg_and_raise_error("invalid count");
    11522             nch_flag = (nchars > 0);
     12689            opt_n = optionarg;
    1152312690            break;
    1152412691        case 's':
    11525             silent = 1;
     12692            read_flags |= BUILTIN_READ_SILENT;
    1152612693            break;
    11527 #endif
    11528 #if ENABLE_ASH_READ_TIMEOUT
    1152912694        case 't':
    11530             ts.tv_sec = strtol(optionarg, &p, 10);
    11531             ts.tv_usec = 0;
    11532             if (*p == '.') {
    11533                 char *p2;
    11534                 if (*++p) {
    11535                     int scale;
    11536                     ts.tv_usec = strtol(p, &p2, 10);
    11537                     if (*p2)
    11538                         ash_msg_and_raise_error("invalid timeout");
    11539                     scale = p2 - p;
    11540                     /* normalize to usec */
    11541                     if (scale > 6)
    11542                         ash_msg_and_raise_error("invalid timeout");
    11543                     while (scale++ < 6)
    11544                         ts.tv_usec *= 10;
    11545                 }
    11546             } else if (*p) {
    11547                 ash_msg_and_raise_error("invalid timeout");
    11548             }
    11549             if ( ! ts.tv_sec && ! ts.tv_usec)
    11550                 ash_msg_and_raise_error("invalid timeout");
     12695            opt_t = optionarg;
    1155112696            break;
    11552 #endif
    1155312697        case 'r':
    11554             rflag = 1;
     12698            read_flags |= BUILTIN_READ_RAW;
     12699            break;
     12700        case 'u':
     12701            opt_u = optionarg;
    1155512702            break;
    1155612703        default:
     
    1155812705        }
    1155912706    }
    11560     if (prompt && isatty(0)) {
    11561         out2str(prompt);
    11562     }
    11563     ap = argptr;
    11564     if (*ap == NULL)
    11565         ash_msg_and_raise_error("arg count");
    11566     ifs = bltinlookup("IFS");
    11567     if (ifs == NULL)
    11568         ifs = defifs;
    11569 #if ENABLE_ASH_READ_NCHARS
    11570     if (nch_flag || silent) {
    11571         tcgetattr(0, &tty);
    11572         old_tty = tty;
    11573         if (nch_flag) {
    11574             tty.c_lflag &= ~ICANON;
    11575             tty.c_cc[VMIN] = nchars;
    11576         }
    11577         if (silent) {
    11578             tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
    11579 
    11580         }
    11581         tcsetattr(0, TCSANOW, &tty);
    11582     }
    11583 #endif
    11584 #if ENABLE_ASH_READ_TIMEOUT
    11585     if (ts.tv_sec || ts.tv_usec) {
    11586         FD_ZERO(&set);
    11587         FD_SET(0, &set);
    11588 
    11589         i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
    11590         if (!i) {
    11591 #if ENABLE_ASH_READ_NCHARS
    11592             if (nch_flag)
    11593                 tcsetattr(0, TCSANOW, &old_tty);
    11594 #endif
    11595             return 1;
    11596         }
    11597     }
    11598 #endif
    11599     status = 0;
    11600     startword = 1;
    11601     backslash = 0;
    11602     STARTSTACKSTR(p);
    11603 #if ENABLE_ASH_READ_NCHARS
    11604     while (!nch_flag || nchars--)
    11605 #else
    11606     for (;;)
    11607 #endif
    11608     {
    11609         if (read(0, &c, 1) != 1) {
    11610             status = 1;
    11611             break;
    11612         }
    11613         if (c == '\0')
    11614             continue;
    11615         if (backslash) {
    11616             backslash = 0;
    11617             if (c != '\n')
    11618                 goto put;
    11619             continue;
    11620         }
    11621         if (!rflag && c == '\\') {
    11622             backslash++;
    11623             continue;
    11624         }
    11625         if (c == '\n')
    11626             break;
    11627         if (startword && *ifs == ' ' && strchr(ifs, c)) {
    11628             continue;
    11629         }
    11630         startword = 0;
    11631         if (ap[1] != NULL && strchr(ifs, c) != NULL) {
    11632             STACKSTRNUL(p);
    11633             setvar(*ap, stackblock(), 0);
    11634             ap++;
    11635             startword = 1;
    11636             STARTSTACKSTR(p);
    11637         } else {
    11638  put:
    11639             STPUTC(c, p);
    11640         }
    11641     }
    11642 #if ENABLE_ASH_READ_NCHARS
    11643     if (nch_flag || silent)
    11644         tcsetattr(0, TCSANOW, &old_tty);
    11645 #endif
    11646 
    11647     STACKSTRNUL(p);
    11648     /* Remove trailing blanks */
    11649     while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
    11650         *p = '\0';
    11651     setvar(*ap, stackblock(), 0);
    11652     while (*++ap != NULL)
    11653         setvar(*ap, nullstr, 0);
    11654     return status;
    11655 }
    11656 
    11657 static int
    11658 umaskcmd(int argc, char **argv)
     12707
     12708    r = shell_builtin_read(setvar2,
     12709        argptr,
     12710        bltinlookup("IFS"), /* can be NULL */
     12711        read_flags,
     12712        opt_n,
     12713        opt_p,
     12714        opt_t,
     12715        opt_u
     12716    );
     12717
     12718    if ((uintptr_t)r > 1)
     12719        ash_msg_and_raise_error(r);
     12720
     12721    return (uintptr_t)r;
     12722}
     12723
     12724static int FAST_FUNC
     12725umaskcmd(int argc UNUSED_PARAM, char **argv)
    1165912726{
    1166012727    static const char permuser[3] ALIGN1 = "ugo";
     
    1166512732        S_IROTH, S_IWOTH, S_IXOTH
    1166612733    };
     12734
     12735    /* TODO: use bb_parse_mode() instead */
    1166712736
    1166812737    char *ap;
     
    1170812777            do {
    1170912778                if (*ap >= '8' || *ap < '0')
    11710                     ash_msg_and_raise_error(illnum, argv[1]);
     12779                    ash_msg_and_raise_error(msg_illnum, argv[1]);
    1171112780                mask = (mask << 3) + (*ap - '0');
    1171212781            } while (*++ap != '\0');
     
    1172312792}
    1172412793
    11725 /*
    11726  * ulimit builtin
    11727  *
    11728  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
    11729  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
    11730  * ash by J.T. Conklin.
    11731  *
    11732  * Public domain.
    11733  */
    11734 
    11735 struct limits {
    11736     const char *name;
    11737     int     cmd;
    11738     int     factor; /* multiply by to get rlim_{cur,max} values */
    11739     char    option;
    11740 };
    11741 
    11742 static const struct limits limits[] = {
    11743 #ifdef RLIMIT_CPU
    11744     { "time(seconds)",              RLIMIT_CPU,        1, 't' },
    11745 #endif
    11746 #ifdef RLIMIT_FSIZE
    11747     { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
    11748 #endif
    11749 #ifdef RLIMIT_DATA
    11750     { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
    11751 #endif
    11752 #ifdef RLIMIT_STACK
    11753     { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
    11754 #endif
    11755 #ifdef  RLIMIT_CORE
    11756     { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
    11757 #endif
    11758 #ifdef RLIMIT_RSS
    11759     { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
    11760 #endif
    11761 #ifdef RLIMIT_MEMLOCK
    11762     { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
    11763 #endif
    11764 #ifdef RLIMIT_NPROC
    11765     { "process",                    RLIMIT_NPROC,      1, 'p' },
    11766 #endif
    11767 #ifdef RLIMIT_NOFILE
    11768     { "nofiles",                    RLIMIT_NOFILE,     1, 'n' },
    11769 #endif
    11770 #ifdef RLIMIT_AS
    11771     { "vmemory(kbytes)",            RLIMIT_AS,      1024, 'v' },
    11772 #endif
    11773 #ifdef RLIMIT_LOCKS
    11774     { "locks",                      RLIMIT_LOCKS,      1, 'w' },
    11775 #endif
    11776     { NULL,                         0,                 0,  '\0' }
    11777 };
    11778 
    11779 enum limtype { SOFT = 0x1, HARD = 0x2 };
    11780 
    11781 static void
    11782 printlim(enum limtype how, const struct rlimit *limit,
    11783             const struct limits *l)
    11784 {
    11785     rlim_t val;
    11786 
    11787     val = limit->rlim_max;
    11788     if (how & SOFT)
    11789         val = limit->rlim_cur;
    11790 
    11791     if (val == RLIM_INFINITY)
    11792         out1fmt("unlimited\n");
    11793     else {
    11794         val /= l->factor;
    11795         out1fmt("%lld\n", (long long) val);
    11796     }
    11797 }
    11798 
    11799 static int
    11800 ulimitcmd(int argc, char **argv)
    11801 {
    11802     int c;
    11803     rlim_t val = 0;
    11804     enum limtype how = SOFT | HARD;
    11805     const struct limits *l;
    11806     int set, all = 0;
    11807     int optc, what;
    11808     struct rlimit limit;
    11809 
    11810     what = 'f';
    11811     while ((optc = nextopt("HSa"
    11812 #ifdef RLIMIT_CPU
    11813                 "t"
    11814 #endif
    11815 #ifdef RLIMIT_FSIZE
    11816                 "f"
    11817 #endif
    11818 #ifdef RLIMIT_DATA
    11819                 "d"
    11820 #endif
    11821 #ifdef RLIMIT_STACK
    11822                 "s"
    11823 #endif
    11824 #ifdef RLIMIT_CORE
    11825                 "c"
    11826 #endif
    11827 #ifdef RLIMIT_RSS
    11828                 "m"
    11829 #endif
    11830 #ifdef RLIMIT_MEMLOCK
    11831                 "l"
    11832 #endif
    11833 #ifdef RLIMIT_NPROC
    11834                 "p"
    11835 #endif
    11836 #ifdef RLIMIT_NOFILE
    11837                 "n"
    11838 #endif
    11839 #ifdef RLIMIT_AS
    11840                 "v"
    11841 #endif
    11842 #ifdef RLIMIT_LOCKS
    11843                 "w"
    11844 #endif
    11845                     )) != '\0')
    11846         switch (optc) {
    11847         case 'H':
    11848             how = HARD;
    11849             break;
    11850         case 'S':
    11851             how = SOFT;
    11852             break;
    11853         case 'a':
    11854             all = 1;
    11855             break;
    11856         default:
    11857             what = optc;
    11858         }
    11859 
    11860     for (l = limits; l->option != what; l++)
    11861         ;
    11862 
    11863     set = *argptr ? 1 : 0;
    11864     if (set) {
    11865         char *p = *argptr;
    11866 
    11867         if (all || argptr[1])
    11868             ash_msg_and_raise_error("too many arguments");
    11869         if (strncmp(p, "unlimited\n", 9) == 0)
    11870             val = RLIM_INFINITY;
    11871         else {
    11872             val = (rlim_t) 0;
    11873 
    11874             while ((c = *p++) >= '0' && c <= '9') {
    11875                 val = (val * 10) + (long)(c - '0');
    11876                 if (val < (rlim_t) 0)
    11877                     break;
    11878             }
    11879             if (c)
    11880                 ash_msg_and_raise_error("bad number");
    11881             val *= l->factor;
    11882         }
    11883     }
    11884     if (all) {
    11885         for (l = limits; l->name; l++) {
    11886             getrlimit(l->cmd, &limit);
    11887             out1fmt("%-20s ", l->name);
    11888             printlim(how, &limit, l);
    11889         }
    11890         return 0;
    11891     }
    11892 
    11893     getrlimit(l->cmd, &limit);
    11894     if (set) {
    11895         if (how & HARD)
    11896             limit.rlim_max = val;
    11897         if (how & SOFT)
    11898             limit.rlim_cur = val;
    11899         if (setrlimit(l->cmd, &limit) < 0)
    11900             ash_msg_and_raise_error("error setting limit (%m)");
    11901     } else {
    11902         printlim(how, &limit, l);
    11903     }
    11904     return 0;
    11905 }
    11906 
    11907 
    11908 /* ============ Math support */
    11909 
    11910 #if ENABLE_ASH_MATH_SUPPORT
    11911 
    11912 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
    11913 
    11914    Permission is hereby granted, free of charge, to any person obtaining
    11915    a copy of this software and associated documentation files (the
    11916    "Software"), to deal in the Software without restriction, including
    11917    without limitation the rights to use, copy, modify, merge, publish,
    11918    distribute, sublicense, and/or sell copies of the Software, and to
    11919    permit persons to whom the Software is furnished to do so, subject to
    11920    the following conditions:
    11921 
    11922    The above copyright notice and this permission notice shall be
    11923    included in all copies or substantial portions of the Software.
    11924 
    11925    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    11926    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    11927    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    11928    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    11929    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    11930    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    11931    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    11932 */
    11933 
    11934 /* This is my infix parser/evaluator. It is optimized for size, intended
    11935  * as a replacement for yacc-based parsers. However, it may well be faster
    11936  * than a comparable parser written in yacc. The supported operators are
    11937  * listed in #defines below. Parens, order of operations, and error handling
    11938  * are supported. This code is thread safe. The exact expression format should
    11939  * be that which POSIX specifies for shells. */
    11940 
    11941 /* The code uses a simple two-stack algorithm. See
    11942  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
    11943  * for a detailed explanation of the infix-to-postfix algorithm on which
    11944  * this is based (this code differs in that it applies operators immediately
    11945  * to the stack instead of adding them to a queue to end up with an
    11946  * expression). */
    11947 
    11948 /* To use the routine, call it with an expression string and error return
    11949  * pointer */
    11950 
    11951 /*
    11952  * Aug 24, 2001              Manuel Novoa III
    11953  *
    11954  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
    11955  *
    11956  * 1) In arith_apply():
    11957  *    a) Cached values of *numptr and &(numptr[-1]).
    11958  *    b) Removed redundant test for zero denominator.
    11959  *
    11960  * 2) In arith():
    11961  *    a) Eliminated redundant code for processing operator tokens by moving
    11962  *       to a table-based implementation.  Also folded handling of parens
    11963  *       into the table.
    11964  *    b) Combined all 3 loops which called arith_apply to reduce generated
    11965  *       code size at the cost of speed.
    11966  *
    11967  * 3) The following expressions were treated as valid by the original code:
    11968  *       1()  ,    0!  ,    1 ( *3 )   .
    11969  *    These bugs have been fixed by internally enclosing the expression in
    11970  *    parens and then checking that all binary ops and right parens are
    11971  *    preceded by a valid expression (NUM_TOKEN).
    11972  *
    11973  * Note: It may be desirable to replace Aaron's test for whitespace with
    11974  * ctype's isspace() if it is used by another busybox applet or if additional
    11975  * whitespace chars should be considered.  Look below the "#include"s for a
    11976  * precompiler test.
    11977  */
    11978 
    11979 /*
    11980  * Aug 26, 2001              Manuel Novoa III
    11981  *
    11982  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
    11983  *
    11984  * Merge in Aaron's comments previously posted to the busybox list,
    11985  * modified slightly to take account of my changes to the code.
    11986  *
    11987  */
    11988 
    11989 /*
    11990  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
    11991  *
    11992  * - allow access to variable,
    11993  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
    11994  * - realize assign syntax (VAR=expr, +=, *= etc)
    11995  * - realize exponentiation (** operator)
    11996  * - realize comma separated - expr, expr
    11997  * - realise ++expr --expr expr++ expr--
    11998  * - realise expr ? expr : expr (but, second expr calculate always)
    11999  * - allow hexadecimal and octal numbers
    12000  * - was restored loses XOR operator
    12001  * - remove one goto label, added three ;-)
    12002  * - protect $((num num)) as true zero expr (Manuel`s error)
    12003  * - always use special isspace(), see comment from bash ;-)
    12004  */
    12005 
    12006 #define arith_isspace(arithval) \
    12007     (arithval == ' ' || arithval == '\n' || arithval == '\t')
    12008 
    12009 typedef unsigned char operator;
    12010 
    12011 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
    12012  * precedence, and 3 high bits are an ID unique across operators of that
    12013  * precedence. The ID portion is so that multiple operators can have the
    12014  * same precedence, ensuring that the leftmost one is evaluated first.
    12015  * Consider * and /. */
    12016 
    12017 #define tok_decl(prec,id) (((id)<<5)|(prec))
    12018 #define PREC(op) ((op) & 0x1F)
    12019 
    12020 #define TOK_LPAREN tok_decl(0,0)
    12021 
    12022 #define TOK_COMMA tok_decl(1,0)
    12023 
    12024 #define TOK_ASSIGN tok_decl(2,0)
    12025 #define TOK_AND_ASSIGN tok_decl(2,1)
    12026 #define TOK_OR_ASSIGN tok_decl(2,2)
    12027 #define TOK_XOR_ASSIGN tok_decl(2,3)
    12028 #define TOK_PLUS_ASSIGN tok_decl(2,4)
    12029 #define TOK_MINUS_ASSIGN tok_decl(2,5)
    12030 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
    12031 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
    12032 
    12033 #define TOK_MUL_ASSIGN tok_decl(3,0)
    12034 #define TOK_DIV_ASSIGN tok_decl(3,1)
    12035 #define TOK_REM_ASSIGN tok_decl(3,2)
    12036 
    12037 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
    12038 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
    12039 
    12040 /* conditional is right associativity too */
    12041 #define TOK_CONDITIONAL tok_decl(4,0)
    12042 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
    12043 
    12044 #define TOK_OR tok_decl(5,0)
    12045 
    12046 #define TOK_AND tok_decl(6,0)
    12047 
    12048 #define TOK_BOR tok_decl(7,0)
    12049 
    12050 #define TOK_BXOR tok_decl(8,0)
    12051 
    12052 #define TOK_BAND tok_decl(9,0)
    12053 
    12054 #define TOK_EQ tok_decl(10,0)
    12055 #define TOK_NE tok_decl(10,1)
    12056 
    12057 #define TOK_LT tok_decl(11,0)
    12058 #define TOK_GT tok_decl(11,1)
    12059 #define TOK_GE tok_decl(11,2)
    12060 #define TOK_LE tok_decl(11,3)
    12061 
    12062 #define TOK_LSHIFT tok_decl(12,0)
    12063 #define TOK_RSHIFT tok_decl(12,1)
    12064 
    12065 #define TOK_ADD tok_decl(13,0)
    12066 #define TOK_SUB tok_decl(13,1)
    12067 
    12068 #define TOK_MUL tok_decl(14,0)
    12069 #define TOK_DIV tok_decl(14,1)
    12070 #define TOK_REM tok_decl(14,2)
    12071 
    12072 /* exponent is right associativity */
    12073 #define TOK_EXPONENT tok_decl(15,1)
    12074 
    12075 /* For now unary operators. */
    12076 #define UNARYPREC 16
    12077 #define TOK_BNOT tok_decl(UNARYPREC,0)
    12078 #define TOK_NOT tok_decl(UNARYPREC,1)
    12079 
    12080 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
    12081 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
    12082 
    12083 #define PREC_PRE (UNARYPREC+2)
    12084 
    12085 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
    12086 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
    12087 
    12088 #define PREC_POST (UNARYPREC+3)
    12089 
    12090 #define TOK_POST_INC tok_decl(PREC_POST, 0)
    12091 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
    12092 
    12093 #define SPEC_PREC (UNARYPREC+4)
    12094 
    12095 #define TOK_NUM tok_decl(SPEC_PREC, 0)
    12096 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
    12097 
    12098 #define NUMPTR (*numstackptr)
    12099 
    12100 static int
    12101 tok_have_assign(operator op)
    12102 {
    12103     operator prec = PREC(op);
    12104 
    12105     convert_prec_is_assing(prec);
    12106     return (prec == PREC(TOK_ASSIGN) ||
    12107             prec == PREC_PRE || prec == PREC_POST);
    12108 }
    12109 
    12110 static int
    12111 is_right_associativity(operator prec)
    12112 {
    12113     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
    12114             || prec == PREC(TOK_CONDITIONAL));
    12115 }
    12116 
    12117 typedef struct ARITCH_VAR_NUM {
    12118     arith_t val;
    12119     arith_t contidional_second_val;
    12120     char contidional_second_val_initialized;
    12121     char *var;      /* if NULL then is regular number,
    12122                else is variable name */
    12123 } v_n_t;
    12124 
    12125 typedef struct CHK_VAR_RECURSIVE_LOOPED {
    12126     const char *var;
    12127     struct CHK_VAR_RECURSIVE_LOOPED *next;
    12128 } chk_var_recursive_looped_t;
    12129 
    12130 static chk_var_recursive_looped_t *prev_chk_var_recursive;
    12131 
    12132 static int
    12133 arith_lookup_val(v_n_t *t)
    12134 {
    12135     if (t->var) {
    12136         const char * p = lookupvar(t->var);
    12137 
    12138         if (p) {
    12139             int errcode;
    12140 
    12141             /* recursive try as expression */
    12142             chk_var_recursive_looped_t *cur;
    12143             chk_var_recursive_looped_t cur_save;
    12144 
    12145             for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
    12146                 if (strcmp(cur->var, t->var) == 0) {
    12147                     /* expression recursion loop detected */
    12148                     return -5;
    12149                 }
    12150             }
    12151             /* save current lookuped var name */
    12152             cur = prev_chk_var_recursive;
    12153             cur_save.var = t->var;
    12154             cur_save.next = cur;
    12155             prev_chk_var_recursive = &cur_save;
    12156 
    12157             t->val = arith (p, &errcode);
    12158             /* restore previous ptr after recursiving */
    12159             prev_chk_var_recursive = cur;
    12160             return errcode;
    12161         }
    12162         /* allow undefined var as 0 */
    12163         t->val = 0;
    12164     }
    12165     return 0;
    12166 }
    12167 
    12168 /* "applying" a token means performing it on the top elements on the integer
    12169  * stack. For a unary operator it will only change the top element, but a
    12170  * binary operator will pop two arguments and push a result */
    12171 static int
    12172 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
    12173 {
    12174     v_n_t *numptr_m1;
    12175     arith_t numptr_val, rez;
    12176     int ret_arith_lookup_val;
    12177 
    12178     /* There is no operator that can work without arguments */
    12179     if (NUMPTR == numstack) goto err;
    12180     numptr_m1 = NUMPTR - 1;
    12181 
    12182     /* check operand is var with noninteger value */
    12183     ret_arith_lookup_val = arith_lookup_val(numptr_m1);
    12184     if (ret_arith_lookup_val)
    12185         return ret_arith_lookup_val;
    12186 
    12187     rez = numptr_m1->val;
    12188     if (op == TOK_UMINUS)
    12189         rez *= -1;
    12190     else if (op == TOK_NOT)
    12191         rez = !rez;
    12192     else if (op == TOK_BNOT)
    12193         rez = ~rez;
    12194     else if (op == TOK_POST_INC || op == TOK_PRE_INC)
    12195         rez++;
    12196     else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
    12197         rez--;
    12198     else if (op != TOK_UPLUS) {
    12199         /* Binary operators */
    12200 
    12201         /* check and binary operators need two arguments */
    12202         if (numptr_m1 == numstack) goto err;
    12203 
    12204         /* ... and they pop one */
    12205         --NUMPTR;
    12206         numptr_val = rez;
    12207         if (op == TOK_CONDITIONAL) {
    12208             if (! numptr_m1->contidional_second_val_initialized) {
    12209                 /* protect $((expr1 ? expr2)) without ": expr" */
    12210                 goto err;
    12211             }
    12212             rez = numptr_m1->contidional_second_val;
    12213         } else if (numptr_m1->contidional_second_val_initialized) {
    12214             /* protect $((expr1 : expr2)) without "expr ? " */
    12215             goto err;
    12216         }
    12217         numptr_m1 = NUMPTR - 1;
    12218         if (op != TOK_ASSIGN) {
    12219             /* check operand is var with noninteger value for not '=' */
    12220             ret_arith_lookup_val = arith_lookup_val(numptr_m1);
    12221             if (ret_arith_lookup_val)
    12222                 return ret_arith_lookup_val;
    12223         }
    12224         if (op == TOK_CONDITIONAL) {
    12225             numptr_m1->contidional_second_val = rez;
    12226         }
    12227         rez = numptr_m1->val;
    12228         if (op == TOK_BOR || op == TOK_OR_ASSIGN)
    12229             rez |= numptr_val;
    12230         else if (op == TOK_OR)
    12231             rez = numptr_val || rez;
    12232         else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
    12233             rez &= numptr_val;
    12234         else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
    12235             rez ^= numptr_val;
    12236         else if (op == TOK_AND)
    12237             rez = rez && numptr_val;
    12238         else if (op == TOK_EQ)
    12239             rez = (rez == numptr_val);
    12240         else if (op == TOK_NE)
    12241             rez = (rez != numptr_val);
    12242         else if (op == TOK_GE)
    12243             rez = (rez >= numptr_val);
    12244         else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
    12245             rez >>= numptr_val;
    12246         else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
    12247             rez <<= numptr_val;
    12248         else if (op == TOK_GT)
    12249             rez = (rez > numptr_val);
    12250         else if (op == TOK_LT)
    12251             rez = (rez < numptr_val);
    12252         else if (op == TOK_LE)
    12253             rez = (rez <= numptr_val);
    12254         else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
    12255             rez *= numptr_val;
    12256         else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
    12257             rez += numptr_val;
    12258         else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
    12259             rez -= numptr_val;
    12260         else if (op == TOK_ASSIGN || op == TOK_COMMA)
    12261             rez = numptr_val;
    12262         else if (op == TOK_CONDITIONAL_SEP) {
    12263             if (numptr_m1 == numstack) {
    12264                 /* protect $((expr : expr)) without "expr ? " */
    12265                 goto err;
    12266             }
    12267             numptr_m1->contidional_second_val_initialized = op;
    12268             numptr_m1->contidional_second_val = numptr_val;
    12269         } else if (op == TOK_CONDITIONAL) {
    12270             rez = rez ?
    12271                 numptr_val : numptr_m1->contidional_second_val;
    12272         } else if (op == TOK_EXPONENT) {
    12273             if (numptr_val < 0)
    12274                 return -3;      /* exponent less than 0 */
    12275             else {
    12276                 arith_t c = 1;
    12277 
    12278                 if (numptr_val)
    12279                     while (numptr_val--)
    12280                         c *= rez;
    12281                 rez = c;
    12282             }
    12283         } else if (numptr_val==0)          /* zero divisor check */
    12284             return -2;
    12285         else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
    12286             rez /= numptr_val;
    12287         else if (op == TOK_REM || op == TOK_REM_ASSIGN)
    12288             rez %= numptr_val;
    12289     }
    12290     if (tok_have_assign(op)) {
    12291         char buf[sizeof(arith_t_type)*3 + 2];
    12292 
    12293         if (numptr_m1->var == NULL) {
    12294             /* Hmm, 1=2 ? */
    12295             goto err;
    12296         }
    12297         /* save to shell variable */
    12298 #if ENABLE_ASH_MATH_SUPPORT_64
    12299         snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
    12300 #else
    12301         snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
    12302 #endif
    12303         setvar(numptr_m1->var, buf, 0);
    12304         /* after saving, make previous value for v++ or v-- */
    12305         if (op == TOK_POST_INC)
    12306             rez--;
    12307         else if (op == TOK_POST_DEC)
    12308             rez++;
    12309     }
    12310     numptr_m1->val = rez;
    12311     /* protect geting var value, is number now */
    12312     numptr_m1->var = NULL;
    12313     return 0;
    12314  err:
    12315     return -1;
    12316 }
    12317 
    12318 /* longest must be first */
    12319 static const char op_tokens[] ALIGN1 = {
    12320     '<','<','=',0, TOK_LSHIFT_ASSIGN,
    12321     '>','>','=',0, TOK_RSHIFT_ASSIGN,
    12322     '<','<',    0, TOK_LSHIFT,
    12323     '>','>',    0, TOK_RSHIFT,
    12324     '|','|',    0, TOK_OR,
    12325     '&','&',    0, TOK_AND,
    12326     '!','=',    0, TOK_NE,
    12327     '<','=',    0, TOK_LE,
    12328     '>','=',    0, TOK_GE,
    12329     '=','=',    0, TOK_EQ,
    12330     '|','=',    0, TOK_OR_ASSIGN,
    12331     '&','=',    0, TOK_AND_ASSIGN,
    12332     '*','=',    0, TOK_MUL_ASSIGN,
    12333     '/','=',    0, TOK_DIV_ASSIGN,
    12334     '%','=',    0, TOK_REM_ASSIGN,
    12335     '+','=',    0, TOK_PLUS_ASSIGN,
    12336     '-','=',    0, TOK_MINUS_ASSIGN,
    12337     '-','-',    0, TOK_POST_DEC,
    12338     '^','=',    0, TOK_XOR_ASSIGN,
    12339     '+','+',    0, TOK_POST_INC,
    12340     '*','*',    0, TOK_EXPONENT,
    12341     '!',        0, TOK_NOT,
    12342     '<',        0, TOK_LT,
    12343     '>',        0, TOK_GT,
    12344     '=',        0, TOK_ASSIGN,
    12345     '|',        0, TOK_BOR,
    12346     '&',        0, TOK_BAND,
    12347     '*',        0, TOK_MUL,
    12348     '/',        0, TOK_DIV,
    12349     '%',        0, TOK_REM,
    12350     '+',        0, TOK_ADD,
    12351     '-',        0, TOK_SUB,
    12352     '^',        0, TOK_BXOR,
    12353     /* uniq */
    12354     '~',        0, TOK_BNOT,
    12355     ',',        0, TOK_COMMA,
    12356     '?',        0, TOK_CONDITIONAL,
    12357     ':',        0, TOK_CONDITIONAL_SEP,
    12358     ')',        0, TOK_RPAREN,
    12359     '(',        0, TOK_LPAREN,
    12360     0
    12361 };
    12362 /* ptr to ")" */
    12363 #define endexpression &op_tokens[sizeof(op_tokens)-7]
    12364 
    12365 static arith_t
    12366 arith(const char *expr, int *perrcode)
    12367 {
    12368     char arithval; /* Current character under analysis */
    12369     operator lasttok, op;
    12370     operator prec;
    12371 
    12372     const char *p = endexpression;
    12373     int errcode;
    12374 
    12375     size_t datasizes = strlen(expr) + 2;
    12376 
    12377     /* Stack of integers */
    12378     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
    12379      * in any given correct or incorrect expression is left as an exercise to
    12380      * the reader. */
    12381     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
    12382                 *numstackptr = numstack;
    12383     /* Stack of operator tokens */
    12384     operator *stack = alloca((datasizes) * sizeof(operator)),
    12385                 *stackptr = stack;
    12386 
    12387     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
    12388     *perrcode = errcode = 0;
    12389 
    12390     while (1) {
    12391         arithval = *expr;
    12392         if (arithval == 0) {
    12393             if (p == endexpression) {
    12394                 /* Null expression. */
    12395                 return 0;
    12396             }
    12397 
    12398             /* This is only reached after all tokens have been extracted from the
    12399              * input stream. If there are still tokens on the operator stack, they
    12400              * are to be applied in order. At the end, there should be a final
    12401              * result on the integer stack */
    12402 
    12403             if (expr != endexpression + 1) {
    12404                 /* If we haven't done so already, */
    12405                 /* append a closing right paren */
    12406                 expr = endexpression;
    12407                 /* and let the loop process it. */
    12408                 continue;
    12409             }
    12410             /* At this point, we're done with the expression. */
    12411             if (numstackptr != numstack+1) {
    12412                 /* ... but if there isn't, it's bad */
    12413  err:
    12414                 return (*perrcode = -1);
    12415             }
    12416             if (numstack->var) {
    12417                 /* expression is $((var)) only, lookup now */
    12418                 errcode = arith_lookup_val(numstack);
    12419             }
    12420  ret:
    12421             *perrcode = errcode;
    12422             return numstack->val;
    12423         }
    12424 
    12425         /* Continue processing the expression. */
    12426         if (arith_isspace(arithval)) {
    12427             /* Skip whitespace */
    12428             goto prologue;
    12429         }
    12430         p = endofname(expr);
    12431         if (p != expr) {
    12432             size_t var_name_size = (p-expr) + 1;  /* trailing zero */
    12433 
    12434             numstackptr->var = alloca(var_name_size);
    12435             safe_strncpy(numstackptr->var, expr, var_name_size);
    12436             expr = p;
    12437  num:
    12438             numstackptr->contidional_second_val_initialized = 0;
    12439             numstackptr++;
    12440             lasttok = TOK_NUM;
    12441             continue;
    12442         }
    12443         if (isdigit(arithval)) {
    12444             numstackptr->var = NULL;
    12445 #if ENABLE_ASH_MATH_SUPPORT_64
    12446             numstackptr->val = strtoll(expr, (char **) &expr, 0);
    12447 #else
    12448             numstackptr->val = strtol(expr, (char **) &expr, 0);
    12449 #endif
    12450             goto num;
    12451         }
    12452         for (p = op_tokens; ; p++) {
    12453             const char *o;
    12454 
    12455             if (*p == 0) {
    12456                 /* strange operator not found */
    12457                 goto err;
    12458             }
    12459             for (o = expr; *p && *o == *p; p++)
    12460                 o++;
    12461             if (! *p) {
    12462                 /* found */
    12463                 expr = o - 1;
    12464                 break;
    12465             }
    12466             /* skip tail uncompared token */
    12467             while (*p)
    12468                 p++;
    12469             /* skip zero delim */
    12470             p++;
    12471         }
    12472         op = p[1];
    12473 
    12474         /* post grammar: a++ reduce to num */
    12475         if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
    12476             lasttok = TOK_NUM;
    12477 
    12478         /* Plus and minus are binary (not unary) _only_ if the last
    12479          * token was as number, or a right paren (which pretends to be
    12480          * a number, since it evaluates to one). Think about it.
    12481          * It makes sense. */
    12482         if (lasttok != TOK_NUM) {
    12483             switch (op) {
    12484             case TOK_ADD:
    12485                 op = TOK_UPLUS;
    12486                 break;
    12487             case TOK_SUB:
    12488                 op = TOK_UMINUS;
    12489                 break;
    12490             case TOK_POST_INC:
    12491                 op = TOK_PRE_INC;
    12492                 break;
    12493             case TOK_POST_DEC:
    12494                 op = TOK_PRE_DEC;
    12495                 break;
    12496             }
    12497         }
    12498         /* We don't want a unary operator to cause recursive descent on the
    12499          * stack, because there can be many in a row and it could cause an
    12500          * operator to be evaluated before its argument is pushed onto the
    12501          * integer stack. */
    12502         /* But for binary operators, "apply" everything on the operator
    12503          * stack until we find an operator with a lesser priority than the
    12504          * one we have just extracted. */
    12505         /* Left paren is given the lowest priority so it will never be
    12506          * "applied" in this way.
    12507          * if associativity is right and priority eq, applied also skip
    12508          */
    12509         prec = PREC(op);
    12510         if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
    12511             /* not left paren or unary */
    12512             if (lasttok != TOK_NUM) {
    12513                 /* binary op must be preceded by a num */
    12514                 goto err;
    12515             }
    12516             while (stackptr != stack) {
    12517                 if (op == TOK_RPAREN) {
    12518                     /* The algorithm employed here is simple: while we don't
    12519                      * hit an open paren nor the bottom of the stack, pop
    12520                      * tokens and apply them */
    12521                     if (stackptr[-1] == TOK_LPAREN) {
    12522                         --stackptr;
    12523                         /* Any operator directly after a */
    12524                         lasttok = TOK_NUM;
    12525                         /* close paren should consider itself binary */
    12526                         goto prologue;
    12527                     }
    12528                 } else {
    12529                     operator prev_prec = PREC(stackptr[-1]);
    12530 
    12531                     convert_prec_is_assing(prec);
    12532                     convert_prec_is_assing(prev_prec);
    12533                     if (prev_prec < prec)
    12534                         break;
    12535                     /* check right assoc */
    12536                     if (prev_prec == prec && is_right_associativity(prec))
    12537                         break;
    12538                 }
    12539                 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
    12540                 if (errcode) goto ret;
    12541             }
    12542             if (op == TOK_RPAREN) {
    12543                 goto err;
    12544             }
    12545         }
    12546 
    12547         /* Push this operator to the stack and remember it. */
    12548         *stackptr++ = lasttok = op;
    12549  prologue:
    12550         ++expr;
    12551     } /* while */
    12552 }
    12553 #endif /* ASH_MATH_SUPPORT */
    12554 
     12794static int FAST_FUNC
     12795ulimitcmd(int argc UNUSED_PARAM, char **argv)
     12796{
     12797    return shell_builtin_ulimit(argv);
     12798}
    1255512799
    1255612800/* ============ main() and helpers */
     
    1255912803 * Called to exit the shell.
    1256012804 */
    12561 static void exitshell(void) ATTRIBUTE_NORETURN;
     12805static void exitshell(void) NORETURN;
    1256212806static void
    1256312807exitshell(void)
     
    1257012814    TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
    1257112815    if (setjmp(loc.loc)) {
    12572         if (exception == EXEXIT)
     12816        if (exception_type == EXEXIT)
    1257312817/* dash bug: it just does _exit(exitstatus) here
    1257412818 * but we have to do setjobctl(0) first!
     
    1258312827        trap[0] = NULL;
    1258412828        evalstring(p, 0);
     12829        free(p);
    1258512830    }
    1258612831    flush_stdout_stderr();
     
    1259512840{
    1259612841    /* from input.c: */
    12597     basepf.nextc = basepf.buf = basebuf;
     12842    /* we will never free this */
     12843    basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
    1259812844
    1259912845    /* from trap.c: */
    1260012846    signal(SIGCHLD, SIG_DFL);
     12847    /* bash re-enables SIGHUP which is SIG_IGNed on entry.
     12848     * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
     12849     */
     12850    signal(SIGHUP, SIG_DFL);
    1260112851
    1260212852    /* from var.c: */
    1260312853    {
    1260412854        char **envp;
    12605         char ppid[sizeof(int)*3 + 1];
    1260612855        const char *p;
    1260712856        struct stat st1, st2;
     
    1261412863        }
    1261512864
    12616         snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
    12617         setvar("PPID", ppid, 0);
     12865        setvar("PPID", utoa(getppid()), 0);
    1261812866
    1261912867        p = lookupvar("PWD");
     
    1263012878 */
    1263112879static void
    12632 procargs(int argc, char **argv)
     12880procargs(char **argv)
    1263312881{
    1263412882    int i;
     
    1263812886    xargv = argv;
    1263912887    arg0 = xargv[0];
    12640     if (argc > 0)
     12888    /* if (xargv[0]) - mmm, this is always true! */
    1264112889        xargv++;
    1264212890    for (i = 0; i < NOPTS; i++)
    1264312891        optlist[i] = 2;
    1264412892    argptr = xargv;
    12645     options(1);
     12893    if (options(1)) {
     12894        /* it already printed err message */
     12895        raise_exception(EXERROR);
     12896    }
    1264612897    xargv = argptr;
    1264712898    xminusc = minusc;
     
    1267812929    shellparam.optoff = -1;
    1267912930#endif
    12680     /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
     12931    /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
    1268112932    while (*xargv) {
    1268212933        shellparam.nparam++;
     
    1271312964    loopnest = 0;
    1271412965    /* from input.c: */
    12715     parselleft = parsenleft = 0;      /* clear input buffer */
     12966    g_parsefile->left_in_buffer = 0;
     12967    g_parsefile->left_in_line = 0;      /* clear input buffer */
    1271612968    popallfiles();
    1271712969    /* from parser.c: */
     
    1271912971    checkkwd = 0;
    1272012972    /* from redir.c: */
    12721     clearredir(0);
     12973    clearredir(/*drop:*/ 0);
    1272212974}
    1272312975
     
    1273412986 * is used to figure out how far we had gotten.
    1273512987 */
    12736 int ash_main(int argc, char **argv);
    12737 int ash_main(int argc, char **argv)
    12738 {
    12739     char *shinit;
    12740     volatile int state;
     12988int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     12989int ash_main(int argc UNUSED_PARAM, char **argv)
     12990{
     12991    const char *shinit;
     12992    volatile smallint state;
    1274112993    struct jmploc jmploc;
    1274212994    struct stackmark smark;
    1274312995
     12996    /* Initialize global data */
     12997    INIT_G_misc();
     12998    INIT_G_memstack();
     12999    INIT_G_var();
     13000#if ENABLE_ASH_ALIAS
     13001    INIT_G_alias();
     13002#endif
     13003    INIT_G_cmdtable();
     13004
    1274413005#if PROFILE
    1274513006    monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
     
    1275113012    state = 0;
    1275213013    if (setjmp(jmploc.loc)) {
    12753         int e;
    12754         int s;
     13014        smallint e;
     13015        smallint s;
    1275513016
    1275613017        reset();
    1275713018
    12758         e = exception;
     13019        e = exception_type;
    1275913020        if (e == EXERROR)
    1276013021            exitstatus = 2;
    1276113022        s = state;
    12762         if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
     13023        if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
    1276313024            exitshell();
    12764 
     13025        }
    1276513026        if (e == EXINT) {
    1276613027            outcslow('\n', stderr);
    1276713028        }
     13029
    1276813030        popstackmark(&smark);
    1276913031        FORCE_INT_ON; /* enable interrupts */
     
    1277913041#if DEBUG
    1278013042    opentrace();
    12781     trace_puts("Shell args: ");
     13043    TRACE(("Shell args: "));
    1278213044    trace_puts_args(argv);
    1278313045#endif
    1278413046    rootpid = getpid();
    1278513047
    12786 #if ENABLE_ASH_RANDOM_SUPPORT
    12787     rseed = rootpid + time(NULL);
    12788 #endif
    1278913048    init();
    1279013049    setstackmark(&smark);
    12791     procargs(argc, argv);
     13050    procargs(argv);
     13051
    1279213052#if ENABLE_FEATURE_EDITING_SAVEHISTORY
    1279313053    if (iflag) {
     
    1280413064    }
    1280513065#endif
    12806     if (argv[0] && argv[0][0] == '-')
     13066    if (/* argv[0] && */ argv[0][0] == '-')
    1280713067        isloginsh = 1;
    1280813068    if (isloginsh) {
     
    1282813088 state3:
    1282913089    state = 4;
    12830     if (minusc)
     13090    if (minusc) {
     13091        /* evalstring pushes parsefile stack.
     13092         * Ensure we don't falsely claim that 0 (stdin)
     13093         * is one of stacked source fds.
     13094         * Testcase: ash -c 'exec 1>&0' must not complain. */
     13095        // if (!sflag) g_parsefile->pf_fd = -1;
     13096        // ^^ not necessary since now we special-case fd 0
     13097        // in is_hidden_fd() to not be considered "hidden fd"
    1283113098        evalstring(minusc, 0);
     13099    }
    1283213100
    1283313101    if (sflag || minusc == NULL) {
    12834 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
    12835         if ( iflag ) {
     13102#if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
     13103        if (iflag) {
    1283613104            const char *hp = lookupvar("HISTFILE");
    12837 
    12838             if (hp != NULL)
     13105            if (hp)
    1283913106                line_input_state->hist_file = hp;
    1284013107        }
     
    1285213119    }
    1285313120#endif
     13121    TRACE(("End of main reached\n"));
    1285413122    exitshell();
    1285513123    /* NOTREACHED */
    1285613124}
    12857 
    12858 #if DEBUG
    12859 const char *applet_name = "debug stuff usage";
    12860 int main(int argc, char **argv)
    12861 {
    12862     return ash_main(argc, argv);
    12863 }
    12864 #endif
    1286513125
    1286613126
Note: See TracChangeset for help on using the changeset viewer.