- typo in documentation
[oweals/busybox.git] / shell / ash.c
index 1fe1e8290c72fadd196e56312f69c6087f5dae98..7271535aa14faabeec87a67747c522a655cf7984 100644 (file)
  * rewrite arith.y to micro stack based cryptic algorithm by
  * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
  *
- * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2003 to be
+ * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
+ * dynamic variables.
+ *
+ * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
  * used in busybox and size optimizations,
- * support locale, rewrited arith (see notes to this)
+ * rewrote arith (see notes to this), added locale support,
+ * rewrote dynamic variables.
  *
  */
 
@@ -88,7 +92,7 @@
 #include <signal.h>
 #include <stdint.h>
 #include <sysexits.h>
-
+#include <time.h>
 #include <fnmatch.h>
 
 
 #undef JOBS
 #endif
 
-#if JOBS
+#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
 #include <termios.h>
 #endif
 
@@ -170,7 +174,7 @@ static const char not_found_msg[] = "%s: not found";
  * We enclose jmp_buf in a structure so that we can declare pointers to
  * jump locations.  The global variable handler contains the location to
  * jump to when an exception occurs, and the global variable exception
- * contains a code identifying the exeception.  To implement nested
+ * contains a code identifying the exception.  To implement nested
  * exception handlers, the user should save the value of handler on entry
  * to an inner scope, set handler to point to a jmploc structure for the
  * inner scope, and restore handler on exit from the scope.
@@ -208,24 +212,24 @@ static volatile sig_atomic_t pendingsigs;
  * more fun than worrying about efficiency and portability. :-))
  */
 
-#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
+#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
 #define INTOFF \
        ({ \
                suppressint++; \
-               barrier(); \
+               xbarrier(); \
                0; \
        })
 #define SAVEINT(v) ((v) = suppressint)
 #define RESTOREINT(v) \
        ({ \
-               barrier(); \
+               xbarrier(); \
                if ((suppressint = (v)) == 0 && intpending) onint(); \
                0; \
        })
 #define EXSIGON() \
        ({ \
                exsig++; \
-               barrier(); \
+               xbarrier(); \
                if (pendingsigs) \
                        exraise(EXSIG); \
                0; \
@@ -259,29 +263,19 @@ static void forceinton(void)
 #else
 #define INTON \
        ({ \
-               barrier(); \
+               xbarrier(); \
                if (--suppressint == 0 && intpending) onint(); \
                0; \
        })
 #define FORCEINTON \
        ({ \
-               barrier(); \
+               xbarrier(); \
                suppressint = 0; \
                if (intpending) onint(); \
                0; \
        })
 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
 
-/*
- * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
- * so we use _setjmp instead.
- */
-
-#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
-#define setjmp(jmploc)  _setjmp(jmploc)
-#define longjmp(jmploc, val)    _longjmp(jmploc, val)
-#endif
-
 /*      $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $     */
 
 struct strlist {
@@ -620,7 +614,7 @@ static const char homestr[] = "HOME";
 #define __builtin_expect(x, expected_value) (x)
 #endif
 
-#define likely(x)       __builtin_expect((x),1)
+#define xlikely(x)       __builtin_expect((x),1)
 
 
 #define TEOF 0
@@ -1245,6 +1239,9 @@ static int commandcmd(int, char **);
 #endif
 static int dotcmd(int, char **);
 static int evalcmd(int, char **);
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+static int echocmd(int, char **);
+#endif
 static int execcmd(int, char **);
 static int exitcmd(int, char **);
 static int exportcmd(int, char **);
@@ -1304,39 +1301,12 @@ struct builtincmd {
        /* unsigned flags; */
 };
 
-#ifdef CONFIG_ASH_CMDCMD
-# ifdef JOBS
-#  ifdef CONFIG_ASH_ALIAS
-#    define COMMANDCMD (builtincmd + 7)
-#    define EXECCMD (builtincmd + 10)
-#  else
-#    define COMMANDCMD (builtincmd + 6)
-#    define EXECCMD (builtincmd + 9)
-#  endif
-# else /* ! JOBS */
-#  ifdef CONFIG_ASH_ALIAS
-#    define COMMANDCMD (builtincmd + 6)
-#    define EXECCMD (builtincmd + 9)
-#  else
-#    define COMMANDCMD (builtincmd + 5)
-#    define EXECCMD (builtincmd + 8)
-#  endif
-# endif /* JOBS */
-#else   /* ! CONFIG_ASH_CMDCMD */
-# ifdef JOBS
-#  ifdef CONFIG_ASH_ALIAS
-#    define EXECCMD (builtincmd + 9)
-#  else
-#    define EXECCMD (builtincmd + 8)
-#  endif
-# else /* ! JOBS */
-#  ifdef CONFIG_ASH_ALIAS
-#    define EXECCMD (builtincmd + 8)
-#  else
-#    define EXECCMD (builtincmd + 7)
-#  endif
-# endif /* JOBS */
-#endif /* CONFIG_ASH_CMDCMD */
+
+#define COMMANDCMD (builtincmd + 5 + \
+       ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
+#define EXECCMD (builtincmd + 7 + \
+       ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
+       ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
 
 #define BUILTIN_NOSPEC  "0"
 #define BUILTIN_SPECIAL "1"
@@ -1349,6 +1319,7 @@ struct builtincmd {
 
 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
+#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
 
 static const struct builtincmd builtincmd[] = {
        { BUILTIN_SPEC_REG      ".", dotcmd },
@@ -1366,6 +1337,9 @@ static const struct builtincmd builtincmd[] = {
        { BUILTIN_REGULAR       "command", commandcmd },
 #endif
        { BUILTIN_SPEC_REG      "continue", breakcmd },
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+       { BUILTIN_REGULAR       "echo", echocmd },
+#endif
        { BUILTIN_SPEC_REG      "eval", evalcmd },
        { BUILTIN_SPEC_REG      "exec", execcmd },
        { BUILTIN_SPEC_REG      "exit", exitcmd },
@@ -1441,8 +1415,23 @@ static void changepath(const char *);
 static void defun(char *, union node *);
 static void unsetfunc(const char *);
 
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+typedef int64_t arith_t;
+#else
+typedef long arith_t;
+#endif
+
 #ifdef CONFIG_ASH_MATH_SUPPORT
-static int dash_arith(const char *);
+static arith_t dash_arith(const char *);
+static arith_t arith(const char *expr, int *perrcode);
+#endif
+
+#ifdef CONFIG_ASH_RANDOM_SUPPORT
+static unsigned long rseed;
+static void change_random(const char *);
+# ifndef DYNAMIC_VAR
+#  define DYNAMIC_VAR
+# endif
 #endif
 
 /*      $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
@@ -1465,14 +1454,17 @@ static void reset(void);
 #define VNOFUNC         0x40    /* don't call the callback function */
 #define VNOSET          0x80    /* do not set variable - just readonly test */
 #define VNOSAVE         0x100   /* when text is on the heap before setvareq */
-
+#ifdef DYNAMIC_VAR
+# define VDYNAMIC        0x200   /* dynamic variable */
+# else
+# define VDYNAMIC        0
+#endif
 
 struct var {
        struct var *next;               /* next entry in hash list */
        int flags;                      /* flags are defined above */
        const char *text;               /* name=value */
-       void (*func)(const char *);
-                                       /* function to be called when  */
+       void (*func)(const char *);     /* function to be called when  */
                                        /* the variable gets set/unset */
 };
 
@@ -1500,6 +1492,7 @@ static void change_lc_all(const char *value);
 static void change_lc_ctype(const char *value);
 #endif
 
+
 #define VTABSIZE 39
 
 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
@@ -1524,18 +1517,21 @@ static struct var varinit[] = {
 #endif
 
        { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
-       { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0 },
-       { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0 },
-       { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0 },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0          },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0          },
+       { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0          },
 #ifdef CONFIG_ASH_GETOPTS
        { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
 #endif
+#ifdef CONFIG_ASH_RANDOM_SUPPORT
+       {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
+#endif
 #ifdef CONFIG_LOCALE_SUPPORT
-       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
-       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
+       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
+       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
 #endif
 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
-       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
+       {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
 #endif
 };
 
@@ -1551,7 +1547,11 @@ static struct var varinit[] = {
 #define vps2 (&vps1)[1]
 #define vps4 (&vps2)[1]
 #define voptind (&vps4)[1]
-
+#ifdef CONFIG_ASH_GETOPTS
+#define vrandom (&voptind)[1]
+#else
+#define vrandom (&vps4)[1]
+#endif
 #define defpath (defpathvar + 5)
 
 /*
@@ -1619,12 +1619,11 @@ extern char **environ;
 static void outstr(const char *, FILE *);
 static void outcslow(int, FILE *);
 static void flushall(void);
-static void flushout(FILE *);
+static void flusherr(void);
 static int  out1fmt(const char *, ...)
     __attribute__((__format__(__printf__,1,2)));
 static int fmtstr(char *, size_t, const char *, ...)
     __attribute__((__format__(__printf__,3,4)));
-static void xwrite(int, const void *, size_t);
 
 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
 
@@ -1637,7 +1636,7 @@ static void out1str(const char *p)
 static void out2str(const char *p)
 {
        outstr(p, stderr);
-       flushout(stderr);
+       flusherr();
 }
 
 /*
@@ -1691,9 +1690,11 @@ init(void)
       {
              char **envp;
              char ppid[32];
+             const char *p;
+             struct stat st1, st2;
 
              initvar();
-             for (envp = environ ; *envp ; envp++) {
+             for (envp = environ ; envp && *envp ; envp++) {
                      if (strchr(*envp, '=')) {
                              setvareq(*envp, VEXPORT|VTEXTFIXED);
                      }
@@ -1701,7 +1702,13 @@ init(void)
 
              snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
              setvar("PPID", ppid, 0);
-             setpwd(0, 0);
+
+             p = lookupvar("PWD");
+             if (p)
+             if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
+                 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+                     p = 0;
+             setpwd(p, 0);
       }
 }
 
@@ -1919,19 +1926,21 @@ struct shparam {
 #define bflag optlist[11]
 #define uflag optlist[12]
 #define qflag optlist[13]
+#define viflag optlist[14]
 
 #ifdef DEBUG
-#define nolog optlist[14]
-#define debug optlist[15]
-#define NOPTS   16
-#else
-#define NOPTS   14
+#define nolog optlist[15]
+#define debug optlist[16]
+#endif
+
+#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
+#define setvimode(on) viflag = 0   /* forcibly keep the option off */
 #endif
 
 /*      $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
 
 
-static const char *const optletters_optnames[NOPTS] = {
+static const char *const optletters_optnames[] = {
        "e"   "errexit",
        "f"   "noglob",
        "I"   "ignoreeof",
@@ -1946,6 +1955,7 @@ static const char *const optletters_optnames[NOPTS] = {
        "b"   "notify",
        "u"   "nounset",
        "q"   "quietprofile",
+       "\0"  "vi",
 #ifdef DEBUG
        "\0"  "nolog",
        "\0"  "debug",
@@ -1955,6 +1965,7 @@ static const char *const optletters_optnames[NOPTS] = {
 #define optletters(n) optletters_optnames[(n)][0]
 #define optnames(n) (&optletters_optnames[(n)][1])
 
+#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
 
 static char optlist[NOPTS];
 
@@ -2288,7 +2299,6 @@ cdcmd(int argc, char **argv)
        else if (dest[0] == '-' && dest[1] == '\0') {
                dest = bltinlookup("OLDPWD");
                flags |= CD_PRINT;
-               goto step7;
        }
        if (!dest)
                dest = nullstr;
@@ -2549,20 +2559,17 @@ onint(void) {
 static void
 exvwarning(const char *msg, va_list ap)
 {
-       FILE *errs;
-       const char *name;
-       const char *fmt;
+        FILE *errs;
 
-       errs = stderr;
-       name = arg0;
-       fmt = "%s: ";
-       if (commandname) {
-               name = commandname;
-               fmt = "%s: %d: ";
-       }
-       fprintf(errs, fmt, name, startlinno);
-       vfprintf(errs, msg, ap);
-       outcslow('\n', errs);
+        errs = stderr;
+        fprintf(errs, "%s: ", arg0);
+        if (commandname) {
+                const char *fmt = (!iflag || parsefile->fd) ?
+                                       "%s: %d: " : "%s: ";
+                fprintf(errs, fmt, commandname, startlinno);
+        }
+        vfprintf(errs, msg, ap);
+        outcslow('\n', errs);
 }
 
 /*
@@ -2680,7 +2687,7 @@ static const struct builtincmd bltin = {
  */
 
 /*
- * The eval commmand.
+ * The eval command.
  */
 
 static int
@@ -3178,7 +3185,20 @@ parse_command_args(char **argv, const char **path)
 }
 #endif
 
+static inline int
+isassignment(const char *p)
+{
+       const char *q = endofname(p);
+       if (p == q)
+               return 0;
+       return *q == '=';
+}
 
+#ifdef CONFIG_ASH_EXPAND_PRMT
+static const char *expandstr(const char *ps);
+#else
+#define expandstr(s) s
+#endif
 
 /*
  * Execute a simple command.
@@ -3202,6 +3222,8 @@ evalcommand(union node *cmd, int flags)
        int cmd_is_exec;
        int status;
        char **nargv;
+       struct builtincmd *bcmd;
+       int pseudovarflag = 0;
 
        /* First expand the arguments. */
        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
@@ -3216,11 +3238,21 @@ evalcommand(union node *cmd, int flags)
        *arglist.lastp = NULL;
 
        argc = 0;
+       if (cmd->ncmd.args)
+       {
+               bcmd = find_builtin(cmd->ncmd.args->narg.text);
+               pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
+       }
+
        for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
                struct strlist **spp;
 
                spp = arglist.lastp;
-               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+               if (pseudovarflag && isassignment(argp->narg.text))
+                       expandarg(argp, &arglist, EXP_VARTILDE);
+               else
+                       expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+
                for (sp = *spp; sp; sp = sp->next)
                        argc++;
        }
@@ -3263,7 +3295,7 @@ evalcommand(union node *cmd, int flags)
                const char *p = " %s";
 
                p++;
-               dprintf(preverrout_fd, p, ps4val());
+               dprintf(preverrout_fd, p, expandstr(ps4val()));
 
                sp = varlist.list;
                for(n = 0; n < 2; n++) {
@@ -3276,7 +3308,7 @@ evalcommand(union node *cmd, int flags)
                        }
                        sp = arglist.list;
                }
-               xwrite(preverrout_fd, "\n", 1);
+               bb_full_write(preverrout_fd, "\n", 1);
        }
 
        cmd_is_exec = 0;
@@ -3293,7 +3325,7 @@ evalcommand(union node *cmd, int flags)
                        find_command(argv[0], &cmdentry, cmd_flag, path);
                        if (cmdentry.cmdtype == CMDUNKNOWN) {
                                status = 127;
-                               flushout(stderr);
+                               flusherr();
                                goto bail;
                        }
 
@@ -3692,33 +3724,13 @@ tryexec(char *cmd, char **argv, char **envp)
 {
        int repeated = 0;
 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
-       int flg_bb = 0;
-       char *name = cmd;
-
-#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
-       name = bb_get_last_path_component(name);
-       if(find_applet_by_name(name) != NULL)
-               flg_bb = 1;
-#else
-       if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
-               flg_bb = 1;
-       }
-#endif
-       if(flg_bb) {
-               char **ap;
-               char **new;
-
-               *argv = name;
-               if(strcmp(name, "busybox")) {
-                       for (ap = argv; *ap; ap++);
-                       ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
-                       *ap++ = cmd = "/bin/busybox";
-                       while ((*ap++ = *argv++));
-                       argv = new;
-                       repeated++;
-               } else {
-                       cmd = "/bin/busybox";
-               }
+       if(find_applet_by_name(cmd) != NULL) {
+               /* re-exec ourselves with the new arguments */
+               execve("/proc/self/exe",argv,envp);
+               /* If proc isn't mounted, try hardcoded path to busybox binary*/
+               execve("/bin/busybox",argv,envp);
+               /* If they called chroot or otherwise made the binary no longer
+                * executable, fall through */
        }
 #endif
 
@@ -4126,9 +4138,6 @@ changepath(const char *newval)
                firstchange = 0;
        clearcmdentry(firstchange);
        builtinloc = idx_bltin;
-#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
-       cmdedit_path_lookup = newval;
-#endif
 }
 
 
@@ -4518,7 +4527,7 @@ static void ifsfree(void);
 static void expandmeta(struct strlist *, int);
 static int patmatch(char *, const char *);
 
-static int cvtnum(long);
+static int cvtnum(arith_t);
 static size_t esclen(const char *, const char *);
 static char *scanleft(char *, char *, char *, char *, int, int);
 static char *scanright(char *, char *, char *, char *, int, int);
@@ -4563,7 +4572,7 @@ expandhere(union node *arg, int fd)
 {
        herefd = fd;
        expandarg(arg, (struct arglist *)NULL, 0);
-       xwrite(fd, stackblock(), expdest - (char *)stackblock());
+       bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
 }
 
 
@@ -4585,11 +4594,12 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
        ifsfirst.next = NULL;
        ifslastp = NULL;
        argstr(arg->narg.text, flag);
+       p = _STPUTC('\0', expdest);
+       expdest = p - 1;
        if (arglist == NULL) {
                return;                 /* here document expanded */
        }
-       STPUTC('\0', expdest);
-       p = grabstackstr(expdest);
+       p = grabstackstr(p);
        exparg.lastp = &exparg.list;
        /*
         * TODO - EXP_REDIR
@@ -5345,9 +5355,12 @@ param:
                        size_t partlen;
 
                        partlen = strlen(p);
-
                        len += partlen;
-                       if (len > partlen && sep) {
+
+                       if (!(subtype == VSPLUS || subtype == VSLENGTH))
+                               memtodest(p, partlen, syntax, quotes);
+
+                       if (*ap && sep) {
                                char *q;
 
                                len++;
@@ -5360,9 +5373,6 @@ param:
                                STPUTC(sep, q);
                                expdest = q;
                        }
-
-                       if (!(subtype == VSPLUS || subtype == VSLENGTH))
-                               memtodest(p, partlen, syntax, quotes);
                }
                return len;
        case '0':
@@ -5889,12 +5899,16 @@ casematch(union node *pattern, char *val)
  */
 
 static int
-cvtnum(long num)
+cvtnum(arith_t num)
 {
        int len;
 
        expdest = makestrspace(32, expdest);
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+       len = fmtstr(expdest, 32, "%lld", (long long) num);
+#else
        len = fmtstr(expdest, 32, "%ld", num);
+#endif
        STADJUST(len, expdest);
        return len;
 }
@@ -5929,33 +5943,6 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
 
 static void pushfile(void);
 
-/*
- * Read a line from the script.
- */
-
-static inline char *
-pfgets(char *line, int len)
-{
-       char *p = line;
-       int nleft = len;
-       int c;
-
-       while (--nleft > 0) {
-               c = pgetc2();
-               if (c == PEOF) {
-                       if (p == line)
-                               return NULL;
-                       break;
-               }
-               *p++ = c;
-               if (c == '\n')
-                       break;
-       }
-       *p = '\0';
-       return line;
-}
-
-
 /*
  * Read a character from the script, returning PEOF on end of file.
  * Nul characters in the input are silently discarded.
@@ -6000,6 +5987,33 @@ static inline int pgetc2(void)
 }
 #endif
 
+/*
+ * Read a line from the script.
+ */
+
+static inline char *
+pfgets(char *line, int len)
+{
+       char *p = line;
+       int nleft = len;
+       int c;
+
+       while (--nleft > 0) {
+               c = pgetc2();
+               if (c == PEOF) {
+                       if (p == line)
+                               return NULL;
+                       break;
+               }
+               *p++ = c;
+               if (c == '\n')
+                       break;
+       }
+       *p = '\0';
+       return line;
+}
+
+
 
 #ifdef CONFIG_FEATURE_COMMAND_EDITING
 static const char *cmdedit_prompt;
@@ -6026,6 +6040,9 @@ retry:
        if (!iflag || parsefile->fd)
                nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
        else {
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+               cmdedit_path_lookup = pathval();
+#endif
                nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
                if(nr == 0) {
                        /* Ctrl+C presend */
@@ -6037,7 +6054,7 @@ retry:
                        }
                        goto retry;
                }
-               if(nr < 0) {
+               if(nr < 0 && errno == 0) {
                        /* Ctrl+D presend */
                        nr = 0;
                }
@@ -6586,10 +6603,12 @@ usage:
                if (**argv == '%') {
                        jp = getjob(*argv, 0);
                        pid = -jp->ps[0].pid;
-               } else
-                       pid = number(*argv);
+               } else {
+                       pid = **argv == '-' ?
+                               -number(*argv + 1) : number(*argv);
+               }
                if (kill(pid, signo) != 0) {
-                       sh_warnx("%m\n");
+                       sh_warnx("(%d) - %m", pid);
                        i = 1;
                }
        } while (*++argv);
@@ -7059,7 +7078,7 @@ growjobtab(void)
                        jq--;
 #define joff(p) ((struct job *)((char *)(p) + l))
 #define jmove(p) (p) = (void *)((char *)(p) + offset)
-                       if (likely(joff(jp)->ps == &jq->ps0))
+                       if (xlikely(joff(jp)->ps == &jq->ps0))
                                jmove(joff(jp)->ps);
                        if (joff(jp)->prev_job)
                                jmove(joff(jp)->prev_job);
@@ -7214,7 +7233,7 @@ forkshell(struct job *jp, union node *n, int mode)
  * the interactive program catches interrupts, the user doesn't want
  * these interrupts to also abort the loop.  The approach we take here
  * is to have the shell ignore interrupt signals while waiting for a
- * forground process to terminate, and then send itself an interrupt
+ * foreground process to terminate, and then send itself an interrupt
  * signal if the child process was terminated by an interrupt signal.
  * Unfortunately, some programs want to do a bit of cleanup and then
  * exit on interrupt; unless these processes terminate themselves by
@@ -7604,11 +7623,10 @@ cmdputs(const char *s)
        char *nextc;
        int subtype = 0;
        int quoted = 0;
-       static const char *const vstype[16] = {
-               nullstr, "}", "-", "+", "?", "=",
-               "#", "##", "%", "%%"
+       static const char vstype[VSTYPE + 1][4] = {
+               "", "}", "-", "+", "?", "=",
+               "%", "%%", "#", "##"
        };
-
        nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
        p = s;
        while ((c = *p++) != 0) {
@@ -7630,14 +7648,10 @@ cmdputs(const char *s)
                                goto dostr;
                        break;
                case CTLENDVAR:
+                       str = "\"}" + !(quoted & 1);
                        quoted >>= 1;
                        subtype = 0;
-                       if (quoted & 1) {
-                               str = "\"}";
-                               goto dostr;
-                       }
-                       c = '}';
-                       break;
+                       goto dostr;
                case CTLBACKQ:
                        str = "$(...)";
                        goto dostr;
@@ -7659,13 +7673,13 @@ cmdputs(const char *s)
                case '=':
                        if (subtype == 0)
                                break;
+                       if ((subtype & VSTYPE) != VSNORMAL)
+                               quoted <<= 1;
                        str = vstype[subtype & VSTYPE];
                        if (subtype & VSNUL)
                                c = ':';
                        else
-                               c = *str++;
-                       if (c != '}')
-                               quoted <<= 1;
+                               goto checkstr;
                        break;
                case '\'':
                case '\\':
@@ -7680,6 +7694,7 @@ cmdputs(const char *s)
                        break;
                }
                USTPUTC(c, nextc);
+checkstr:
                if (!str)
                        continue;
 dostr:
@@ -7896,6 +7911,10 @@ ash_main(int argc, char **argv)
        trputs("Shell args:  ");  trargs(argv);
 #endif
        rootpid = getpid();
+
+#ifdef CONFIG_ASH_RANDOM_SUPPORT
+       rseed = rootpid + ((time_t)time((time_t *)0));
+#endif
        rootshell = 1;
        init();
        setstackmark(&smark);
@@ -8107,21 +8126,40 @@ find_dot_file(char *name)
        /* NOTREACHED */
 }
 
-int
-dotcmd(int argc, char **argv)
+static int dotcmd(int argc, char **argv)
 {
+       struct strlist *sp;
+       volatile struct shparam saveparam;
+
        exitstatus = 0;
 
-       if (argc >= 2) {                /* That's what SVR2 does */
+       for (sp = cmdenviron; sp; sp = sp->next)
+               setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
+
+       if (argc >= 2) {        /* That's what SVR2 does */
                char *fullname;
                struct stackmark smark;
 
                setstackmark(&smark);
                fullname = find_dot_file(argv[1]);
+
+               if (argc > 2) {
+                       saveparam = shellparam;
+                       shellparam.malloc = 0;
+                       shellparam.nparam = argc - 2;
+                       shellparam.p = argv + 2;
+               };
+
                setinputfile(fullname, 1);
                commandname = fullname;
                cmdloop(0);
                popfile();
+
+               if (argc > 2) {
+                       freeparam(&shellparam);
+                       shellparam = saveparam;
+               };
+
                popstackmark(&smark);
        }
        return exitstatus;
@@ -8139,6 +8177,13 @@ exitcmd(int argc, char **argv)
        /* NOTREACHED */
 }
 
+#ifdef CONFIG_ASH_BUILTIN_ECHO
+static int
+echocmd(int argc, char **argv)
+{
+       return bb_echo(argc, argv);
+}
+#endif
 /*      $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $        */
 
 /*
@@ -8356,7 +8401,7 @@ growstackstr(void)
 {
        size_t len = stackblocksize();
        if (herefd >= 0 && len >= 1024) {
-               xwrite(herefd, stackblock(), len);
+               bb_full_write(herefd, stackblock(), len);
                return stackblock();
        }
        growstackblock();
@@ -8805,6 +8850,7 @@ optschanged(void)
 #endif
        setinteractive(iflag);
        setjobctl(mflag);
+       setvimode(viflag);
 }
 
 static inline void
@@ -9021,6 +9067,27 @@ static void change_lc_ctype(const char *value)
 
 #endif
 
+#ifdef CONFIG_ASH_RANDOM_SUPPORT
+/* Roughly copied from bash.. */
+static void change_random(const char *value)
+{
+       if(value == NULL) {
+               /* "get", generate */
+               char buf[16];
+
+               rseed = rseed * 1103515245 + 12345;
+               sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
+               /* set without recursion */
+               setvar(vrandom.text, buf, VNOFUNC);
+               vrandom.flags &= ~VNOFUNC;
+       } else {
+               /* set/reset */
+               rseed = strtoul(value, (char **)NULL, 10);
+       }
+}
+#endif
+
+
 #ifdef CONFIG_ASH_GETOPTS
 static int
 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
@@ -9209,10 +9276,10 @@ flushall(void)
 }
 
 void
-flushout(FILE *dest)
+flusherr(void)
 {
        INTOFF;
-       fflush(dest);
+       fflush(stderr);
        INTON;
 }
 
@@ -9256,20 +9323,6 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 }
 
 
-/*
- * Version of write which resumes after a signal is caught.
- */
-
-static void
-xwrite(int fd, const void *p, size_t n)
-{
-       ssize_t i;
-
-       do {
-               i = bb_full_write(fd, p, n);
-       } while (i < 0 && errno == EINTR);
-}
-
 
 /*      $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $     */
 
@@ -9312,15 +9365,6 @@ static void setprompt(int);
 
 
 
-static inline int
-isassignment(const char *p)
-{
-       const char *q = endofname(p);
-       if (p == q)
-               return 0;
-       return *q == '=';
-}
-
 
 /*
  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
@@ -9846,7 +9890,6 @@ parseheredoc(void)
        while (here) {
                if (needprompt) {
                        setprompt(2);
-                       needprompt = 0;
                }
                readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
                                here->eofmark, here->striptabs);
@@ -9979,7 +10022,6 @@ static int xxreadtoken()
        }
        if (needprompt) {
                setprompt(2);
-               needprompt = 0;
        }
        startlinno = plinno;
        for (;;) {                      /* until token or start of word found */
@@ -10047,7 +10089,6 @@ xxreadtoken(void)
        }
        if (needprompt) {
                setprompt(2);
-               needprompt = 0;
        }
        startlinno = plinno;
        for (;;) {      /* until token or start of word found */
@@ -10603,7 +10644,6 @@ parsebackq: {
                for (;;) {
                        if (needprompt) {
                                setprompt(2);
-                               needprompt = 0;
                        }
                        switch (pc = pgetc()) {
                        case '`':
@@ -10813,9 +10853,35 @@ synerror(const char *msg)
  *    should be added here.
  */
 
+#ifdef CONFIG_ASH_EXPAND_PRMT
+static const char *
+expandstr(const char *ps)
+{
+       union node n;
+
+       /* XXX Fix (char *) cast. */
+       setinputstring((char *)ps);
+       readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
+       popfile();
+
+       n.narg.type = NARG;
+       n.narg.next = NULL;
+       n.narg.text = wordtext;
+       n.narg.backquote = backquotelist;
+
+       expandarg(&n, NULL, 0);
+       return stackblock();
+}
+#endif
+
 static void setprompt(int whichprompt)
 {
        const char *prompt;
+#ifdef CONFIG_ASH_EXPAND_PRMT
+       struct stackmark smark;
+#endif
+
+       needprompt = 0;
 
        switch (whichprompt) {
        case 1:
@@ -10827,7 +10893,14 @@ static void setprompt(int whichprompt)
        default:                        /* 0 */
                prompt = nullstr;
        }
-       putprompt(prompt);
+#ifdef CONFIG_ASH_EXPAND_PRMT
+       setstackmark(&smark);
+       stalloc(stackblocksize());
+#endif
+       putprompt(expandstr(prompt));
+#ifdef CONFIG_ASH_EXPAND_PRMT
+       popstackmark(&smark);
+#endif
 }
 
 
@@ -10926,7 +10999,7 @@ openhere(union node *redir)
        if (redir->type == NHERE) {
                len = strlen(redir->nhere.doc->narg.text);
                if (len <= PIPESIZE) {
-                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
+                       bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
                        goto out;
                }
        }
@@ -10940,7 +11013,7 @@ openhere(union node *redir)
 #endif
                signal(SIGPIPE, SIG_DFL);
                if (redir->type == NHERE)
-                       xwrite(pip[1], redir->nhere.doc->narg.text, len);
+                       bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
                else
                        expandhere(redir->nhere.doc, pip[1]);
                _exit(0);
@@ -11758,7 +11831,7 @@ dotrap(void)
 
        savestatus = exitstatus;
        q = gotsig;
-       while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
+       while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
                *p = 0;
                p = trap[p - q + 1];
                if (!p)
@@ -11859,6 +11932,7 @@ exitshell(void)
                evalstring(p);
        }
        flushall();
+       setjobctl(0);
 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
        if (iflag && rootshell) {
                const char *hp = lookupvar("HISTFILE");
@@ -11888,7 +11962,7 @@ static int vpcmp(const void *, const void *);
 static struct var **findvar(struct var **, const char *);
 
 /*
- * Initialize the varable symbol tables and import the environment
+ * Initialize the variable symbol tables and import the environment
  */
 
 
@@ -11946,7 +12020,7 @@ setvar(const char *name, const char *val, int flags)
        INTOFF;
        p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
        *p++ = '\0';
-       if (vallen) {
+       if (val) {
                p[-1] = '=';
                p = mempcpy(p, val, vallen);
        }
@@ -11973,10 +12047,13 @@ setvareq(char *s, int flags)
        flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
        vp = *findvar(vpp, s);
        if (vp) {
-               if (vp->flags & VREADONLY) {
+               if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
+                       const char *n;
+
                        if (flags & VNOSAVE)
                                free(s);
-                       error("%.*s: is read only", strchrnul(s, '=') - s, s);
+                       n = vp->text;
+                       error("%.*s: is read only", strchrnul(n, '=') - n, n);
                }
 
                if (flags & VNOSET)
@@ -12033,9 +12110,21 @@ lookupvar(const char *name)
 {
        struct var *v;
 
-       if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
-               return strchrnul(v->text, '=') + 1;
+       if ((v = *findvar(hashvar(name), name))) {
+#ifdef DYNAMIC_VAR
+       /*
+        * Dynamic variables are implemented roughly the same way they are
+        * in bash. Namely, they're "special" so long as they aren't unset.
+        * As soon as they're unset, they're no longer dynamic, and dynamic
+        * lookup will no longer happen at that point. -- PFM.
+        */
+               if((v->flags & VDYNAMIC))
+                       (*v->func)(NULL);
+#endif
+               if(!(v->flags & VUNSET))
+                       return strchrnul(v->text, '=') + 1;
        }
+
        return NULL;
 }
 
@@ -12310,6 +12399,9 @@ unsetvar(const char *s)
                retval = 1;
                if (flags & VREADONLY)
                        goto out;
+#ifdef DYNAMIC_VAR
+               vp->flags &= ~VDYNAMIC;
+#endif
                if (flags & VUNSET)
                        goto ok;
                if ((flags & VSTRFIXED) == 0) {
@@ -12426,10 +12518,10 @@ static int timescmd(int ac, char **av)
 }
 
 #ifdef CONFIG_ASH_MATH_SUPPORT
-static int
+static arith_t
 dash_arith(const char *s)
 {
-       long result;
+       arith_t result;
        int errcode = 0;
 
        INTOFF;
@@ -12461,7 +12553,7 @@ static int
 letcmd(int argc, char **argv)
 {
        char **ap;
-       long i;
+       arith_t i;
 
        ap = argv + 1;
        if(!*ap)
@@ -12477,7 +12569,7 @@ letcmd(int argc, char **argv)
 /*      $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $  */
 
 /*
- * Miscelaneous builtins.
+ * Miscellaneous builtins.
  */
 
 #undef rflag
@@ -12509,14 +12601,77 @@ readcmd(int argc, char **argv)
        int startword;
        int status;
        int i;
+#if defined(CONFIG_ASH_READ_NCHARS)
+       int nch_flag = 0;
+       int nchars = 0;
+       int silent = 0;
+       struct termios tty, old_tty;
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+       fd_set set;
+       struct timeval ts;
+
+       ts.tv_sec = ts.tv_usec = 0;
+#endif
 
        rflag = 0;
        prompt = NULL;
-       while ((i = nextopt("p:r")) != '\0') {
-               if (i == 'p')
+#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
+       while ((i = nextopt("p:rt:n:s")) != '\0')
+#elif defined(CONFIG_ASH_READ_NCHARS)
+       while ((i = nextopt("p:rn:s")) != '\0')
+#elif defined(CONFIG_ASH_READ_TIMEOUT)
+       while ((i = nextopt("p:rt:")) != '\0')
+#else
+       while ((i = nextopt("p:r")) != '\0')
+#endif
+       {
+               switch(i) {
+               case 'p':
                        prompt = optionarg;
-               else
+                       break;
+#if defined(CONFIG_ASH_READ_NCHARS)
+               case 'n':
+                       nchars = strtol(optionarg, &p, 10);
+                       if (*p)
+                               error("invalid count");
+                       nch_flag = (nchars > 0);
+                       break;
+               case 's':
+                       silent = 1;
+                       break;
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+               case 't':
+                       ts.tv_sec = strtol(optionarg, &p, 10);
+                       ts.tv_usec = 0;
+                       if (*p == '.') {
+                               char *p2;
+                               if (*++p) {
+                                       int scale;
+                                       ts.tv_usec = strtol(p, &p2, 10);
+                                       if (*p2)
+                                               error("invalid timeout");
+                                       scale = p2 - p;
+                                       /* normalize to usec */
+                                       if (scale > 6)
+                                               error("invalid timeout");
+                                       while (scale++ < 6)
+                                               ts.tv_usec *= 10;
+                               }
+                       } else if (*p) {
+                               error("invalid timeout");
+                       }
+                       if ( ! ts.tv_sec && ! ts.tv_usec)
+                               error("invalid timeout");
+                       break;
+#endif
+               case 'r':
                        rflag = 1;
+                       break;
+               default:
+                       break;
+               }
        }
        if (prompt && isatty(0)) {
                out2str(prompt);
@@ -12525,11 +12680,46 @@ readcmd(int argc, char **argv)
                error("arg count");
        if ((ifs = bltinlookup("IFS")) == NULL)
                ifs = defifs;
+#if defined(CONFIG_ASH_READ_NCHARS)
+       if (nch_flag || silent) {
+               tcgetattr(0, &tty);
+               old_tty = tty;
+               if (nch_flag) {
+                   tty.c_lflag &= ~ICANON;
+                   tty.c_cc[VMIN] = nchars;
+               }
+               if (silent) {
+                   tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
+
+               }
+               tcsetattr(0, TCSANOW, &tty);
+       }
+#endif
+#if defined(CONFIG_ASH_READ_TIMEOUT)
+       if (ts.tv_sec || ts.tv_usec) {
+               FD_ZERO (&set);
+               FD_SET (0, &set);
+
+               i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
+               if (!i) {
+#if defined(CONFIG_ASH_READ_NCHARS)
+                       if (nch_flag)
+                               tcsetattr(0, TCSANOW, &old_tty);
+#endif
+                       return 1;
+               }
+       }
+#endif
        status = 0;
        startword = 1;
        backslash = 0;
        STARTSTACKSTR(p);
-       for (;;) {
+#if defined(CONFIG_ASH_READ_NCHARS)
+       while (!nch_flag || nchars--)
+#else
+       for (;;)
+#endif
+       {
                if (read(0, &c, 1) != 1) {
                        status = 1;
                        break;
@@ -12563,6 +12753,11 @@ put:
                        STPUTC(c, p);
                }
        }
+#if defined(CONFIG_ASH_READ_NCHARS)
+       if (nch_flag || silent)
+               tcsetattr(0, TCSANOW, &old_tty);
+#endif
+
        STACKSTRNUL(p);
        /* Remove trailing blanks */
        while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
@@ -12849,14 +13044,14 @@ ulimitcmd(int argc, char **argv)
 
 /* This is my infix parser/evaluator. It is optimized for size, intended
  * as a replacement for yacc-based parsers. However, it may well be faster
- * than a comparable parser writen in yacc. The supported operators are
+ * than a comparable parser written in yacc. The supported operators are
  * listed in #defines below. Parens, order of operations, and error handling
- * are supported. This code is threadsafe. The exact expression format should
+ * are supported. This code is thread safe. The exact expression format should
  * be that which POSIX specifies for shells. */
 
 /* The code uses a simple two-stack algorithm. See
  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
- * for a detailed explaination of the infix-to-postfix algorithm on which
+ * for a detailed explanation of the infix-to-postfix algorithm on which
  * this is based (this code differs in that it applies operators immediately
  * to the stack instead of adding them to a queue to end up with an
  * expression). */
@@ -12886,7 +13081,7 @@ ulimitcmd(int argc, char **argv)
  *    parens and then checking that all binary ops and right parens are
  *    preceded by a valid expression (NUM_TOKEN).
  *
- * Note: It may be desireable to replace Aaron's test for whitespace with
+ * Note: It may be desirable to replace Aaron's test for whitespace with
  * ctype's isspace() if it is used by another busybox applet or if additional
  * whitespace chars should be considered.  Look below the "#include"s for a
  * precompiler test.
@@ -12912,7 +13107,7 @@ ulimitcmd(int argc, char **argv)
  * - realize comma separated - expr, expr
  * - realise ++expr --expr expr++ expr--
  * - realise expr ? expr : expr (but, second expr calculate always)
- * - allow hexdecimal and octal numbers
+ * - allow hexadecimal and octal numbers
  * - was restored loses XOR operator
  * - remove one goto label, added three ;-)
  * - protect $((num num)) as true zero expr (Manuel`s error)
@@ -12927,7 +13122,7 @@ ulimitcmd(int argc, char **argv)
 typedef unsigned char operator;
 
 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
- * precedence, and 3 high bits are an ID unique accross operators of that
+ * precedence, and 3 high bits are an ID unique across operators of that
  * precedence. The ID portion is so that multiple operators can have the
  * same precedence, ensuring that the leftmost one is evaluated first.
  * Consider * and /. */
@@ -13032,11 +13227,11 @@ static inline int is_right_associativity(operator prec)
 
 
 typedef struct ARITCH_VAR_NUM {
-       long val;
-       long contidional_second_val;
+       arith_t val;
+       arith_t contidional_second_val;
        char contidional_second_val_initialized;
        char *var;      /* if NULL then is regular number,
-                          else is varable name */
+                          else is variable name */
 } v_n_t;
 
 
@@ -13090,9 +13285,8 @@ static int arith_lookup_val(v_n_t *t)
 static inline int
 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
 {
-       long numptr_val;
        v_n_t *numptr_m1;
-       long rez;
+       arith_t numptr_val, rez;
        int ret_arith_lookup_val;
 
        if (NUMPTR == numstack) goto err; /* There is no operator that can work
@@ -13195,7 +13389,7 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
                        if(numptr_val < 0)
                                return -3;      /* exponent less than 0 */
                        else {
-                               long c = 1;
+                               arith_t c = 1;
 
                                if(numptr_val)
                                        while(numptr_val--)
@@ -13218,7 +13412,11 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
                        goto err;
                }
                /* save to shell variable */
-               sprintf(buf, "%ld", rez);
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+               snprintf(buf, sizeof(buf), "%lld", rez);
+#else
+               snprintf(buf, sizeof(buf), "%ld", rez);
+#endif
                setvar(numptr_m1->var, buf, 0);
                /* after saving, make previous value for v++ or v-- */
                if(op == TOK_POST_INC)
@@ -13281,7 +13479,7 @@ static const char op_tokens[] = {
 #define endexpression &op_tokens[sizeof(op_tokens)-7]
 
 
-extern long arith (const char *expr, int *perrcode)
+static arith_t arith (const char *expr, int *perrcode)
 {
     register char arithval; /* Current character under analysis */
     operator lasttok, op;
@@ -13294,7 +13492,7 @@ extern long arith (const char *expr, int *perrcode)
 
     /* Stack of integers */
     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
-     * in any given correct or incorrect expression is left as an excersize to
+     * in any given correct or incorrect expression is left as an exercise to
      * the reader. */
     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
            *numstackptr = numstack;
@@ -13344,7 +13542,7 @@ extern long arith (const char *expr, int *perrcode)
                        goto prologue;
                }
                if((p = endofname(expr)) != expr) {
-                       int var_name_size = (p-expr) + 1;  /* trailing zero */
+                       size_t var_name_size = (p-expr) + 1;  /* trailing zero */
 
                        numstackptr->var = alloca(var_name_size);
                        safe_strncpy(numstackptr->var, expr, var_name_size);
@@ -13356,7 +13554,11 @@ extern long arith (const char *expr, int *perrcode)
                        continue;
                } else if (is_digit(arithval)) {
                        numstackptr->var = NULL;
+#ifdef CONFIG_ASH_MATH_SUPPORT_64
+                       numstackptr->val = strtoll(expr, (char **) &expr, 0);
+#else
                        numstackptr->val = strtol(expr, (char **) &expr, 0);
+#endif
                        goto num;
                }
                for(p = op_tokens; ; p++) {