Update web page...
[oweals/busybox.git] / ash.c
diff --git a/ash.c b/ash.c
index 489ccaa95088734a0c267d2807acb8c953a3b975..4250f50e2186c1505804011468c2e357eb861555 100644 (file)
--- a/ash.c
+++ b/ash.c
@@ -42,7 +42,7 @@
 
 /* Enable job control.  This allows you to run jobs in the background,
  * which is great when ash is being  used as an interactive shell, but
- * it completely useless for is all you are doing is running scripts.  
+ * it completely useless for is all you are doing is running scripts.
  * This adds about 2.5k on an x86 system. */
 #define JOBS
 
@@ -79,6 +79,9 @@
  * a little bit faster, but leaving this disabled will save you 2k. */
 #undef ASH_BBAPPS_AS_BUILTINS
 
+/* Optimize size vs speed as size */
+#define ASH_OPTIMIZE_FOR_SIZE
+
 /* Enable this to compile in extra debugging noise.  When debugging is
  * on, debugging info will be written to $HOME/trace and a quit signal
  * will generate a core dump. */
 #include "busybox.h"
 #include "cmdedit.h"
 
-/* if BB_PWD is defined, then disable ASH_PWD to save space */
-#ifdef BB_PWD
-#undef ASH_PWD
-#endif
-
-
 /*
  * This file was generated by the mksyntax program.
  */
 
 #define _DIAGASSERT(x)
 
-#define ATABSIZE 39
+
 
 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
 #define S_CATCH 2               /* signal is caught */
 
 /* flags passed to redirect */
 #define REDIR_PUSH 01           /* save previous values of file descriptors */
-#define REDIR_BACKQ 02          /* save the command output in memory */
+#define REDIR_BACKQ 02          /* save the command output to pipe */
 
 /*
  * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
@@ -302,13 +299,16 @@ static volatile int suppressint;
 static volatile int intpending;
 
 #define INTOFF suppressint++
-#ifdef ASH_BBAPPS_AS_BUILTINS
+#ifndef ASH_OPTIMIZE_FOR_SIZE
 #define INTON { if (--suppressint == 0 && intpending) onint(); }
+#define FORCEINTON {suppressint = 0; if (intpending) onint();}
 #else
 static void __inton (void);
+static void forceinton (void);
 #define INTON __inton()
+#define FORCEINTON forceinton()
 #endif
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
+
 #define CLEAR_PENDING_INT intpending = 0
 #define int_pending() intpending
 
@@ -326,6 +326,7 @@ static pointer stalloc (int);
 static void stunalloc (pointer);
 static void ungrabstackstr (char *, char *);
 static char * growstackstr(void);
+static char * makestrspace(size_t newlen);
 static char *sstrdup (const char *);
 
 /*
@@ -357,10 +358,13 @@ static int stacknleft = MINSIZE;
 #define stackblock() stacknxt
 #define stackblocksize() stacknleft
 #define STARTSTACKSTR(p)        p = stackblock(), sstrnleft = stackblocksize()
+
 #define STPUTC(c, p)    (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
 #define CHECKSTRSPACE(n, p)     { if (sstrnleft < n) p = makestrspace(n); }
-#define USTPUTC(c, p)   (--sstrnleft, *p++ = (c))
 #define STACKSTRNUL(p)  (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+
+
+#define USTPUTC(c, p)   (--sstrnleft, *p++ = (c))
 #define STUNPUTC(p)     (++sstrnleft, --p)
 #define STTOPC(p)       p[-1]
 #define STADJUST(amount, p)     (p += (amount), sstrnleft -= (amount))
@@ -368,7 +372,6 @@ static int stacknleft = MINSIZE;
 
 #define ckfree(p)       free((pointer)(p))
 
-static char * makestrspace(size_t newlen);
 
 #ifdef DEBUG
 #define TRACE(param)    trace param
@@ -659,71 +662,18 @@ struct shparam {
        int optoff;             /* used by getopts */
 };
 
-struct output {
-#ifdef USE_GLIBC_STDIO
-       FILE *stream;
-#endif
-       char *nextc;
-       int nleft;
-       char *buf;
-       int bufsize;
-       int fd;
-       short flags;
-};
-
-#define OUTBUFSIZ BUFSIZ
-#define MEM_OUT -3              /* output to dynamically allocated memory */
-
-
-#ifdef USE_GLIBC_STDIO
-static struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
-static struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
-static struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
-#else
-static struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
-static struct output errout = {NULL, 0, NULL, 0, 2, 0};
-static struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
-#endif
-static struct output *out1 = &output;
-static struct output *out2 = &errout;
-
-#ifndef USE_GLIBC_STDIO
-static void outcslow (char, struct output *);
-#endif
 static void flushall (void);
-static void flushout (struct output *);
-static void freestdout (void);
-static void outfmt (struct output *, const char *, ...)
-    __attribute__((__format__(__printf__,2,3)));
+static void out2fmt (const char *, ...)
+    __attribute__((__format__(__printf__,1,2)));
 static void out1fmt (const char *, ...)
     __attribute__((__format__(__printf__,1,2)));
-static void fmtstr (char *, size_t, const char *, ...)
-    __attribute__((__format__(__printf__,3,4)));
-#ifndef USE_GLIBC_STDIO
-static void doformat (struct output *, const char *, va_list);
-#endif
 static int xwrite (int, const char *, int);
-#ifdef USE_GLIBC_STDIO
-static void initstreams (void);
-static void openmemout (void);
-static int __closememout (void);
-#endif
 
-static void outstr(const char *p, struct output *file);
+static void outstr (const char *p, FILE *file) { fputs(p, file); }
+static void out1str(const char *p) { outstr(p, stdout); }
+static void out2str(const char *p) { outstr(p, stderr); }
 
-#define OUTPUT_ERR 01           /* error occurred on output */
-
-#ifdef USE_GLIBC_STDIO
-#define outc(c, o)      putc((c), (o)->stream)
-#define doformat(d, f, a)       vfprintf((d)->stream, (f), (a))
-#else
-#define outc(c, file)   (--(file)->nleft < 0? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++))
-#endif
-#define out1c(c)        outc((c), out1)
-#define out2c(c)        outc((c), out2)
-#define out1str(s)      outstr((s), out1)
-#define out2str(s)      outstr((s), out2)
-#define outerr(f)       ((f)->flags & OUTPUT_ERR)
+#define out2c(c)        putc((c), stderr)
 
 /* syntax table used when not in quotes */
 static const char basesyntax[257] = {
@@ -1389,6 +1339,8 @@ static char *minusc;                    /* argument to -c option */
 #define ALIASINUSE      1
 #define ALIASDEAD       2
 
+#define ATABSIZE 39
+
 struct alias {
        struct alias *next;
        char *name;
@@ -1508,7 +1460,7 @@ aliascmd(int argc, char **argv)
        while ((n = *++argv) != NULL) {
                if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
                        if ((ap = *__lookupalias(n)) == NULL) {
-                               outfmt(out2, "%s: %s not found\n", "alias", n);
+                               out2fmt("%s: %s not found\n", "alias", n);
                                ret = 1;
                        } else
                                printalias(ap);
@@ -1535,7 +1487,7 @@ unaliascmd(int argc, char **argv)
        }
        for (i = 0; *argptr; argptr++) {
                if (unalias(*argptr)) {
-                       outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
+                       out2fmt("%s: %s not found\n", "unalias", *argptr);
                        i = 1;
                }
        }
@@ -1638,9 +1590,7 @@ static int bgcmd (int, char **);
 static int fgcmd (int, char **);
 static int killcmd (int, char **);
 #endif
-#ifdef ASH_BBAPPS_AS_BUILTINS
 static int bltincmd (int, char **);
-#endif
 static int cdcmd (int, char **);
 static int breakcmd (int, char **);
 #ifdef ASH_CMDCMD
@@ -1653,9 +1603,10 @@ static int exitcmd (int, char **);
 static int exportcmd (int, char **);
 static int histcmd (int, char **);
 static int hashcmd (int, char **);
+static int helpcmd (int, char **);
 static int jobscmd (int, char **);
 static int localcmd (int, char **);
-#ifdef ASH_PWD
+#ifndef BB_PWD
 static int pwdcmd (int, char **);
 #endif
 static int readcmd (int, char **);
@@ -1727,9 +1678,7 @@ static const struct builtincmd builtincmds[] = {
        { BUILTIN_REGULAR   "bg", bgcmd },
 #endif
        { BUILTIN_SPECIAL   "break", breakcmd },
-#ifdef ASH_BBAPPS_AS_BUILTINS
        { BUILTIN_SPECIAL   "builtin", bltincmd },
-#endif
        { BUILTIN_REGULAR   "cd", cdcmd },
 #ifdef ASH_BBAPPS_AS_BUILTINS
        { BUILTIN_NOSPEC    "chdir", cdcmd },
@@ -1756,6 +1705,7 @@ static const struct builtincmd builtincmds[] = {
        { BUILTIN_REGULAR   "getopts", getoptscmd },
 #endif
        { BUILTIN_NOSPEC    "hash", hashcmd },
+       { BUILTIN_NOSPEC    "help", helpcmd },
        { BUILTIN_REGULAR   "jobs", jobscmd },
 #ifdef JOBS
        { BUILTIN_REGULAR   "kill", killcmd },
@@ -1764,7 +1714,7 @@ static const struct builtincmd builtincmds[] = {
        { BUILTIN_NOSPEC    "let", expcmd },
 #endif
        { BUILTIN_ASSIGN    "local", localcmd },
-#ifdef ASH_PWD
+#ifndef BB_PWD
        { BUILTIN_NOSPEC    "pwd", pwdcmd },
 #endif
        { BUILTIN_REGULAR   "read", readcmd },
@@ -2053,7 +2003,7 @@ updatepwd(const char *dir)
 }
 
 
-#ifdef ASH_PWD
+#ifndef BB_PWD
 static int
 pwdcmd(argc, argv)
        int argc;
@@ -2202,13 +2152,9 @@ exverror(int cond, const char *msg, va_list ap)
 #endif
        if (msg) {
                if (commandname)
-                       outfmt(&errout, "%s: ", commandname);
-               doformat(&errout, msg, ap);
-#if FLUSHERR
-               outc('\n', &errout);
-#else
-               outcslow('\n', &errout);
-#endif
+                       out2fmt("%s: ", commandname);
+               vfprintf(stderr, msg, ap);
+               out2c('\n');
        }
        flushall();
        exraise(cond);
@@ -2361,18 +2307,23 @@ errmsg(int e, int action)
                        return strerror(e);
        }
 
-       fmtstr(buf, sizeof buf, "error %d", e);
+       snprintf(buf, sizeof buf, "error %d", e);
        return buf;
 }
 
 
-#ifndef ASH_BBAPPS_AS_BUILTINS
+#ifdef ASH_OPTIMIZE_FOR_SIZE
 static void
 __inton() {
        if (--suppressint == 0 && intpending) {
                onint();
        }
 }
+static void forceinton (void) {
+       suppressint = 0;
+       if (intpending)
+               onint();
+}
 #endif
 
 /* flags in argument to evaltree */
@@ -2398,11 +2349,7 @@ static void evalcase (union node *, int);
 static void evalsubshell (union node *, int);
 static void expredir (union node *);
 static void evalpipe (union node *);
-#ifdef notyet
-static void evalcommand (union node *, int, struct backcmd *);
-#else
 static void evalcommand (union node *, int);
-#endif
 static void prehash (union node *);
 static void eprintlist (struct strlist *);
 
@@ -2549,7 +2496,7 @@ evaltree(n, flags)
                        (bcmd = find_builtin(n->narg.text)) &&
                        IS_BUILTIN_SPECIAL(bcmd)
                ) {
-                       outfmt(out2, "%s is a special built-in\n", n->narg.text);
+                       out2fmt("%s is a special built-in\n", n->narg.text);
                        exitstatus = 1;
                        break;
                }
@@ -2567,19 +2514,12 @@ evaltree(n, flags)
                checkexit = 1;
                break;
        case NCMD:
-#ifdef notyet
-               evalcommand(n, flags, (struct backcmd *)NULL);
-#else
                evalcommand(n, flags);
-#endif
                checkexit = 1;
                break;
 #ifdef DEBUG
        default:
                out1fmt("Node type = %d\n", n->type);
-#ifndef USE_GLIBC_STDIO
-               flushout(out1);
-#endif
                break;
 #endif
        }
@@ -2730,7 +2670,6 @@ evalsubshell(n, flags)
 }
 
 
-
 /*
  * Compute the names of the files in a redirection list.
  */
@@ -2859,38 +2798,24 @@ evalbackcmd(union node *n, struct backcmd *result)
                exitstatus = 0;
                goto out;
        }
-#ifdef notyet
-       /*
-        * For now we disable executing builtins in the same
-        * context as the shell, because we are not keeping
-        * enough state to recover from changes that are
-        * supposed only to affect subshells. eg. echo "`cd /`"
-        */
-       if (n->type == NCMD) {
-               exitstatus = oexitstatus;
-               evalcommand(n, EV_BACKCMD, result);
-       } else
-#endif
-       {
-               exitstatus = 0;
-               if (pipe(pip) < 0)
-                       error("Pipe call failed");
-               jp = makejob(n, 1);
-               if (forkshell(jp, n, FORK_NOJOB) == 0) {
-                       FORCEINTON;
-                       close(pip[0]);
-                       if (pip[1] != 1) {
-                               close(1);
-                               dup_as_newfd(pip[1], 1);
-                               close(pip[1]);
-                       }
-                       eflag = 0;
-                       evaltree(n, EV_EXIT);
+       exitstatus = 0;
+       if (pipe(pip) < 0)
+               error("Pipe call failed");
+       jp = makejob(n, 1);
+       if (forkshell(jp, n, FORK_NOJOB) == 0) {
+               FORCEINTON;
+               close(pip[0]);
+               if (pip[1] != 1) {
+                       close(1);
+                       dup_as_newfd(pip[1], 1);
+                       close(pip[1]);
                }
-               close(pip[1]);
-               result->fd = pip[0];
-               result->jp = jp;
+               eflag = 0;
+               evaltree(n, EV_EXIT);
        }
+       close(pip[1]);
+       result->fd = pip[0];
+       result->jp = jp;
 out:
        popstackmark(&smark);
        TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
@@ -2917,16 +2842,7 @@ isassignment(const char *word) {
 }
 
 static void
-#ifdef notyet
-evalcommand(cmd, flags, backcmd)
-       union node *cmd;
-       int flags;
-       struct backcmd *backcmd;
-#else
-evalcommand(cmd, flags)
-       union node *cmd;
-       int flags;
-#endif
+evalcommand(union node *cmd, int flags)
 {
        struct stackmark smark;
        union node *argp;
@@ -2937,9 +2853,6 @@ evalcommand(cmd, flags)
        char **envp;
        struct strlist *sp;
        int mode;
-#ifdef notyet
-       int pip[2];
-#endif
        struct cmdentry cmdentry;
        struct job *jp;
        char *volatile savecmdname;
@@ -3010,19 +2923,10 @@ evalcommand(cmd, flags)
 
        /* Print the command if xflag is set. */
        if (xflag) {
-#ifdef FLUSHERR
-               outc('+', &errout);
-#else
-               outcslow('+', &errout);
-#endif
+               out2c('+');
                eprintlist(varlist.list);
                eprintlist(arglist.list);
-#ifdef FLUSHERR
-               outc('\n', &errout);
-               flushout(&errout);
-#else
-               outcslow('\n', &errout);
-#endif
+               out2c('\n');
        }
 
        /* Now locate the command. */
@@ -3050,9 +2954,6 @@ evalcommand(cmd, flags)
                        find_command(argv[0], &cmdentry, findflag, path);
                        if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
                                exitstatus = 127;
-#ifdef FLUSHERR
-                               flushout(&errout);
-#endif
                                goto out;
                        }
                        /* implement bltin and command here */
@@ -3070,11 +2971,8 @@ evalcommand(cmd, flags)
                                        if (--argc == 0)
                                                goto found;
                                        if (!(bcmd = find_builtin(*argv))) {
-                                               outfmt(&errout, "%s: not found\n", *argv);
+                                               out2fmt("%s: not found\n", *argv);
                                                exitstatus = 127;
-#ifdef FLUSHERR
-                                               flushout(&errout);
-#endif
                                                goto out;
                                        }
                                        cmdentry.u.cmd = bcmd;
@@ -3114,35 +3012,11 @@ found:
        /* Fork off a child process if necessary. */
        if (cmd->ncmd.backgnd
         || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
-#ifdef notyet
-        || ((flags & EV_BACKCMD) != 0
-           && (cmdentry.cmdtype != CMDBUILTIN
-                || cmdentry.u.bcmd == DOTCMD
-                || cmdentry.u.bcmd == EVALCMD))
-#endif
        ) {
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
-#ifdef notyet
-               if (flags & EV_BACKCMD) {
-                       mode = FORK_NOJOB;
-                       if (pipe(pip) < 0)
-                               error("Pipe call failed");
-               }
-#endif
                if (forkshell(jp, cmd, mode) != 0)
                        goto parent;    /* at end of routine */
-#ifdef notyet
-               if (flags & EV_BACKCMD) {
-                       FORCEINTON;
-                       close(pip[0]);
-                       if (pip[1] != 1) {
-                               close(1);
-                               dup_as_newfd(pip[1], 1);
-                               close(pip[1]);
-                       }
-               }
-#endif
                flags |= EV_EXIT;
        }
 
@@ -3205,18 +3079,6 @@ found:
                trputs("builtin command:  ");  trargs(argv);
 #endif
                mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
-#ifdef notyet
-               if (flags == EV_BACKCMD) {
-#ifdef USE_GLIBC_STDIO
-                       openmemout();
-#else
-                       memout.nleft = 0;
-                       memout.nextc = memout.buf;
-                       memout.bufsize = 64;
-#endif
-                       mode |= REDIR_BACKQ;
-               }
-#endif
                redirect(cmd->ncmd.redirect, mode);
                savecmdname = commandname;
                if (IS_BUILTIN_SPECIAL(firstbltin)) {
@@ -3238,10 +3100,6 @@ found:
                exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
                flushall();
 cmddone:
-               exitstatus |= outerr(out1);
-               out1 = &output;
-               out2 = &errout;
-               freestdout();
                cmdenviron = NULL;
                if (e != EXSHELLPROC) {
                        commandname = savecmdname;
@@ -3260,23 +3118,6 @@ cmddone:
                }
                if (cmdentry.u.cmd != EXECCMD)
                        popredir();
-#ifdef notyet
-               if (flags == EV_BACKCMD) {
-                       INTOFF;
-#ifdef USE_GLIBC_STDIO
-                       if (__closememout())
-                               error("__closememout() failed: %m");
-#endif
-                       backcmd->buf = memout.buf;
-#ifdef USE_GLIBC_STDIO
-                       backcmd->nleft = memout.bufsize;
-#else
-                       backcmd->nleft = memout.nextc - memout.buf;
-#endif
-                       memout.buf = NULL;
-                       INTON;
-               }
-#endif
        } else {
 #ifdef DEBUG
                trputs("normal command:  ");  trargs(argv);
@@ -3295,12 +3136,6 @@ parent: /* parent process gets here (if we forked) */
                INTOFF;
                exitstatus = waitforjob(jp);
                INTON;
-#ifdef notyet
-       } else if (mode == 2) {
-               backcmd->fd = pip[0];
-               close(pip[1]);
-               backcmd->jp = jp;
-#endif
        }
 
 out:
@@ -3441,6 +3276,7 @@ static void
 setinteractive(int on)
 {
        static int is_interactive;
+       static int do_banner=0;
 
        if (on == is_interactive)
                return;
@@ -3449,6 +3285,12 @@ setinteractive(int on)
        setsignal(SIGTERM);
        chkmail(1);
        is_interactive = on;
+       if (do_banner==0 && is_interactive) {
+               /* Looks like they want an interactive shell */
+               printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
+               printf( "Enter 'help' for a list of built-in commands.\n\n");
+               do_banner=1;
+       }
 }
 
 static void
@@ -3481,7 +3323,7 @@ static void
 eprintlist(struct strlist *sp)
 {
        for (; sp; sp = sp->next) {
-               outfmt(&errout, " %s",sp->text);
+               out2fmt(" %s",sp->text);
        }
 }
 /*
@@ -3657,7 +3499,7 @@ static int preadfd (void);
  * Nul characters in the input are silently discarded.
  */
 
-#ifdef ASH_BBAPPS_AS_BUILTINS
+#ifndef ASH_OPTIMIZE_FOR_SIZE
 #define pgetc_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
 static int
 pgetc(void)
@@ -3797,6 +3639,21 @@ tryexec(cmd, argv, envp)
        {
        int e;
 
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       char *name = cmd;
+       char** argv_l=argv;
+       int argc_l;
+#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
+       name = get_last_path_component(name);
+#endif
+       argv_l=envp;
+       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
+               putenv(*argv_l);
+       argv_l=argv;
+       for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+       optind = 1;
+       run_applet_by_name(name, argc_l, argv);
+#endif
        execve(cmd, argv, envp);
        e = errno;
        if (e == ENOEXEC) {
@@ -3954,6 +3811,51 @@ printentry(cmdp, verbose)
 
 
 
+/*** List the available builtins ***/
+
+
+static int helpcmd(int argc, char** argv)
+{
+       int col, i;
+       const struct builtincmd *x;
+
+       printf("\nBuilt-in commands:\n");
+       printf("-------------------\n");
+       for (col=0, i=0, x = builtincmds; i < NUMBUILTINS; x++, i++) {
+               if (!x->name || ! (x->name+1))
+                       continue;
+               col += printf("%s%s", ((col == 0) ? "\t" : " "), 
+                               (x->name+1));
+               if (col > 60) {
+                       printf("\n");
+                       col = 0;
+               }
+       }
+#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+       {
+               const struct BB_applet *applet;
+               extern const struct BB_applet applets[];
+               extern const size_t NUM_APPLETS;
+
+               for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) {
+                       if (!applet->name)
+                               continue;
+               
+                       col += printf("%s%s", ((col == 0) ? "\t" : " "), 
+                                       applet->name);
+                       if (col > 60) {
+                               printf("\n");
+                               col = 0;
+                       }
+               }
+       }
+#endif
+       printf("\n\n");
+       return EXIT_SUCCESS;
+}
+
+
+
 /*
  * Resolve a command name.  If you change this routine, you may have to
  * change the shellexec routine as well.
@@ -4130,7 +4032,7 @@ loop:
        if (cmdp && updatetbl)
                delete_cmd_entry();
        if (act & DO_ERR)
-               outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
+               out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
        entry->cmdtype = CMDUNKNOWN;
        return;
 
@@ -4519,7 +4421,7 @@ describe_command(char *command, int verbose)
        }
 
 out:
-       out1c('\n');
+       putchar('\n');
        return 0;
 }
 #endif
@@ -4547,16 +4449,16 @@ commandcmd(argc, argv)
                        verbose_verify_only = 1;
                        break;
                default:
-                       outfmt(out2,
+                       out2fmt(
 "command: nextopt returned character code 0%o\n", c);
                        return EX_SOFTWARE;
                }
 
        if (default_path + verify_only + verbose_verify_only > 1 ||
            !*argptr) {
-                       outfmt(out2,
+                       out2fmt(
 "command [-p] command [arg ...]\n");
-                       outfmt(out2,
+                       out2fmt(
 "command {-v|-V} command\n");
                        return EX_USAGE;
        }
@@ -4944,7 +4846,7 @@ expari(int flag)
        if (quotes)
                rmescapes(p+2);
        result = arith(p+2);
-       fmtstr(p, 12, "%d", result);
+       snprintf(p, 12, "%d", result);
 
        while (*p++)
                ;
@@ -5103,7 +5005,7 @@ subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
 
        case VSQUESTION:
                if (*p != CTLENDVAR) {
-                       outfmt(&errout, snlfmt, startp);
+                       out2fmt(snlfmt, startp);
                        error((char *)NULL);
                }
                error("%.*s: parameter %snot set", p - str - 1,
@@ -6264,13 +6166,6 @@ init(void) {
              basepf.nextc = basepf.buf = basebuf;
       }
 
-      /* from output.c: */
-      {
-#ifdef USE_GLIBC_STDIO
-             initstreams();
-#endif
-      }
-
       /* from var.c: */
       {
              char **envp;
@@ -6283,7 +6178,7 @@ init(void) {
                      }
              }
 
-             fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
+             snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
              setvar("PPID", ppid, 0);
       }
 }
@@ -6332,19 +6227,6 @@ reset(void) {
                      popredir();
       }
 
-      /* from output.c: */
-      {
-             out1 = &output;
-             out2 = &errout;
-#ifdef USE_GLIBC_STDIO
-             if (memout.stream != NULL)
-                     __closememout();
-#endif
-             if (memout.buf != NULL) {
-                     ckfree(memout.buf);
-                     memout.buf = NULL;
-             }
-      }
 }
 
 
@@ -6517,10 +6399,7 @@ preadbuffer(void)
        }
        if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
                return PEOF;
-       flushout(&output);
-#ifdef FLUSHERR
-       flushout(&errout);
-#endif
+       flushall();
 
 again:
        if (parselleft <= 0) {
@@ -6561,9 +6440,6 @@ check:
 
        if (vflag) {
                out2str(parsenextc);
-#ifdef FLUSHERR
-               flushout(out2);
-#endif
        }
 
        *q = savec;
@@ -6669,11 +6545,6 @@ fd0_redirected_p () {
        return fd0_redirected != 0;
 }
 
-/*
- * We also keep track of where fileno2 goes.
- */
-static int fileno2 = 2;
-
 static int openredirect (union node *);
 static void dupredirect (union node *, int, char[10 ]);
 static int openhere (union node *);
@@ -6703,9 +6574,9 @@ static void setjobctl(int enable)
        if (enable) {
                do { /* while we are in the background */
 #ifdef OLD_TTY_DRIVER
-                       if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
+                       if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
 #else
-                       initialpgrp = tcgetpgrp(fileno2);
+                       initialpgrp = tcgetpgrp(2);
                        if (initialpgrp < 0) {
 #endif
                                out2str("sh: can't access tty; job cenabletrol turned off\n");
@@ -6720,7 +6591,7 @@ static void setjobctl(int enable)
                        }
                } while (0);
 #ifdef OLD_TTY_DRIVER
-               if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
+               if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
                        out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
                        mflag = 0;
                        return;
@@ -6731,16 +6602,16 @@ static void setjobctl(int enable)
                setsignal(SIGTTIN);
                setpgid(0, rootpid);
 #ifdef OLD_TTY_DRIVER
-               ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
+               ioctl(2, TIOCSPGRP, (char *)&rootpid);
 #else
-               tcsetpgrp(fileno2, rootpid);
+               tcsetpgrp(2, rootpid);
 #endif
        } else { /* turning job cenabletrol off */
                setpgid(0, initialpgrp);
 #ifdef OLD_TTY_DRIVER
-               ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
+               ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
 #else
-               tcsetpgrp(fileno2, initialpgrp);
+               tcsetpgrp(2, initialpgrp);
 #endif
                setsignal(SIGTSTP);
                setsignal(SIGTTOU);
@@ -6928,9 +6799,9 @@ fgcmd(argc, argv)
                error("job not created under job control");
        pgrp = jp->ps[0].pid;
 #ifdef OLD_TTY_DRIVER
-       ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
+       ioctl(2, TIOCSPGRP, (char *)&pgrp);
 #else
-       tcsetpgrp(fileno2, pgrp);
+       tcsetpgrp(2, pgrp);
 #endif
        restartjob(jp);
        INTOFF;
@@ -7026,10 +6897,10 @@ showjobs(change)
                procno = jp->nprocs;
                for (ps = jp->ps ; ; ps++) {    /* for each process */
                        if (ps == jp->ps)
-                               fmtstr(s, 64, "[%d] %ld ", jobno,
+                               snprintf(s, 64, "[%d] %ld ", jobno,
                                    (long)ps->pid);
                        else
-                               fmtstr(s, 64, "    %ld ",
+                               snprintf(s, 64, "    %ld ",
                                    (long)ps->pid);
                        out1str(s);
                        col = strlen(s);
@@ -7037,7 +6908,7 @@ showjobs(change)
                        if (ps->status == -1) {
                                /* don't print anything */
                        } else if (WIFEXITED(ps->status)) {
-                               fmtstr(s, 64, "Exit %d",
+                               snprintf(s, 64, "Exit %d",
                                       WEXITSTATUS(ps->status));
                        } else {
 #ifdef JOBS
@@ -7049,7 +6920,7 @@ showjobs(change)
                                if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
                                        strcpy(s, sys_siglist[i & 0x7F]);
                                else
-                                       fmtstr(s, 64, "Signal %d", i & 0x7F);
+                                       snprintf(s, 64, "Signal %d", i & 0x7F);
                                if (WCOREDUMP(ps->status))
                                        strcat(s, " (core dumped)");
                        }
@@ -7319,10 +7190,10 @@ forkshell(struct job *jp, union node *n, int mode)
                        if (mode == FORK_FG) {
                                /*** this causes superfluous TIOCSPGRPS ***/
 #ifdef OLD_TTY_DRIVER
-                               if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
+                               if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
                                        error("TIOCSPGRP failed, errno=%d", errno);
 #else
-                               if (tcsetpgrp(fileno2, pgrp) < 0)
+                               if (tcsetpgrp(2, pgrp) < 0)
                                        error("tcsetpgrp failed, errno=%d", errno);
 #endif
                        }
@@ -7440,10 +7311,10 @@ waitforjob(jp)
 #ifdef JOBS
        if (jp->jobctl) {
 #ifdef OLD_TTY_DRIVER
-               if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
+               if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
                        error("TIOCSPGRP failed, errno=%d\n", errno);
 #else
-               if (tcsetpgrp(fileno2, mypgrp) < 0)
+               if (tcsetpgrp(2, mypgrp) < 0)
                        error("tcsetpgrp failed, errno=%d\n", errno);
 #endif
        }
@@ -7553,22 +7424,19 @@ dowait(block, job)
 
                if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
                        if (thisjob != job)
-                               outfmt(out2, "%d: ", pid);
+                               out2fmt("%d: ", pid);
 #ifdef JOBS
                        if (sig == SIGTSTP && rootshell && iflag)
-                               outfmt(out2, "%%%ld ",
+                               out2fmt("%%%ld ",
                                    (long)(job - jobtab + 1));
 #endif
                        if (sig < NSIG && sys_siglist[sig])
                                out2str(sys_siglist[sig]);
                        else
-                               outfmt(out2, "Signal %d", sig);
+                               out2fmt("Signal %d", sig);
                        if (core)
                                out2str(" - core dumped");
                        out2c('\n');
-#ifdef FLUSHERR
-                       flushout(&errout);
-#endif
                } else {
                        TRACE(("Not printing status: status=%d, sig=%d\n",
                               status, sig));
@@ -7893,10 +7761,8 @@ chkmail(int silent)
                if (stat(p, &statb) < 0)
                        statb.st_size = 0;
                if (statb.st_size > mailtime[i] && ! silent) {
-                       outfmt(
-                               &errout, snlfmt,
-                               pathopt? pathopt : "you have mail"
-                       );
+                       out2fmt(snlfmt,
+                               pathopt? pathopt : "you have mail");
                }
                mailtime[i] = statb.st_size;
        }
@@ -7943,6 +7809,11 @@ shell_main(argc, argv)
        EXECCMD = find_builtin("exec");
        EVALCMD = find_builtin("eval");
 
+#ifndef BB_FEATURE_SH_FANCY_PROMPT
+       unsetenv("PS1");
+       unsetenv("PS2");
+#endif
+
 #if PROFILE
        monitor(4, etext, profile_buf, sizeof profile_buf, 50);
 #endif
@@ -7984,9 +7855,6 @@ shell_main(argc, argv)
                reset();
                if (exception == EXINT) {
                        out2c('\n');
-#ifdef FLUSHERR
-                       flushout(out2);
-#endif
                }
                popstackmark(&smark);
                FORCEINTON;                             /* enable interrupts */
@@ -8083,7 +7951,7 @@ cmdloop(int top)
                        inter++;
                        showjobs(1);
                        chkmail(0);
-                       flushout(&output);
+                       flushall();
                }
                n = parsecmd(inter);
                /* showtree(n); DEBUG */
@@ -9611,7 +9479,7 @@ atend:
                                err |= setvarsafe("OPTARG", s, 0);
                        }
                        else {
-                               outfmt(&errout, "Illegal option -%c\n", c);
+                               out2fmt("Illegal option -%c\n", c);
                                (void) unsetvar("OPTARG");
                        }
                        c = '?';
@@ -9630,7 +9498,7 @@ atend:
                                c = ':';
                        }
                        else {
-                               outfmt(&errout, "No arg for -%c option\n", c);
+                               out2fmt("No arg for -%c option\n", c);
                                (void) unsetvar("OPTARG");
                                c = '?';
                        }
@@ -9652,7 +9520,7 @@ bad:
        p = NULL;
 out:
        *optoff = p ? p - *(optnext - 1) : -1;
-       fmtstr(s, sizeof(s), "%d", *myoptind);
+       snprintf(s, sizeof(s), "%d", *myoptind);
        err |= setvarsafe("OPTIND", s, VNOFUNC);
        s[0] = c;
        s[1] = '\0';
@@ -9711,249 +9579,33 @@ nextopt(optstring)
        return c;
 }
 
-
-/*
- * Shell output routines.  We use our own output routines because:
- *      When a builtin command is interrupted we have to discard
- *              any pending output.
- *      When a builtin command appears in back quotes, we want to
- *              save the output of the command in a region obtained
- *              via malloc, rather than doing a fork and reading the
- *              output of the command via a pipe.
- *      Our output routines may be smaller than the stdio routines.
- */
-
-
-
-#ifndef USE_GLIBC_STDIO
-static void __outstr (const char *, size_t, struct output*);
-#endif
-
-
-#ifndef USE_GLIBC_STDIO
-static void
-__outstr(const char *p, size_t len, struct output *dest) {
-       if (!dest->bufsize) {
-               dest->nleft = 0;
-       } else if (dest->buf == NULL) {
-               if (len > dest->bufsize && dest->fd == MEM_OUT) {
-                       dest->bufsize = len;
-               }
-               INTOFF;
-               dest->buf = ckmalloc(dest->bufsize);
-               dest->nextc = dest->buf;
-               dest->nleft = dest->bufsize;
-               INTON;
-       } else if (dest->fd == MEM_OUT) {
-               int offset;
-
-               offset = dest->bufsize;
-               INTOFF;
-               if (dest->bufsize >= len) {
-                       dest->bufsize <<= 1;
-               } else {
-                       dest->bufsize += len;
-               }
-               dest->buf = ckrealloc(dest->buf, dest->bufsize);
-               dest->nleft = dest->bufsize - offset;
-               dest->nextc = dest->buf + offset;
-               INTON;
-       } else {
-               flushout(dest);
-       }
-
-       if (len < dest->nleft) {
-               dest->nleft -= len;
-               memcpy(dest->nextc, p, len);
-               dest->nextc += len;
-               return;
-       }
-
-       if (xwrite(dest->fd, p, len) < len)
-               dest->flags |= OUTPUT_ERR;
-}
-#endif
-
-
-static void
-outstr(const char *p, struct output *file)
-{
-#ifdef USE_GLIBC_STDIO
-       INTOFF;
-       fputs(p, file->stream);
-       INTON;
-#else
-       size_t len;
-
-       if (!*p) {
-               return;
-       }
-       len = strlen(p);
-       if ((file->nleft -= len) > 0) {
-               memcpy(file->nextc, p, len);
-               file->nextc += len;
-               return;
-       }
-       __outstr(p, len, file);
-#endif
-}
-
-
-#ifndef USE_GLIBC_STDIO
-
-
-static void
-outcslow(c, dest)
-       char c;
-       struct output *dest;
-       {
-       __outstr(&c, 1, dest);
-}
-#endif
-
-
 static void
 flushall() {
-       flushout(&output);
-#ifdef FLUSHERR
-       flushout(&errout);
-#endif
-}
-
-
-static void
-flushout(dest)
-       struct output *dest;
-       {
-#ifdef USE_GLIBC_STDIO
        INTOFF;
-       fflush(dest->stream);
+       fflush(stdout);
        INTON;
-#else
-       size_t len;
-
-       len = dest->nextc - dest->buf;
-       if (dest->buf == NULL || !len || dest->fd < 0)
-               return;
-       dest->nextc = dest->buf;
-       dest->nleft = dest->bufsize;
-       if (xwrite(dest->fd, dest->buf, len) < len)
-               dest->flags |= OUTPUT_ERR;
-#endif
 }
 
 
 static void
-freestdout() {
-       if (output.buf) {
-               INTOFF;
-               ckfree(output.buf);
-               output.buf = NULL;
-               output.nleft = 0;
-               INTON;
-       }
-       output.flags = 0;
-}
-
-
-static void
-#ifdef __STDC__
-outfmt(struct output *file, const char *fmt, ...)
-#else
-static void
-outfmt(va_alist)
-       va_dcl
-#endif
+out2fmt(const char *fmt, ...)
 {
        va_list ap;
-#ifndef __STDC__
-       struct output *file;
-       const char *fmt;
-
-       va_start(ap);
-       file = va_arg(ap, struct output *);
-       fmt = va_arg(ap, const char *);
-#else
        va_start(ap, fmt);
-#endif
-       doformat(file, fmt, ap);
+       vfprintf(stderr, fmt, ap);
        va_end(ap);
 }
 
 
 static void
-#ifdef __STDC__
 out1fmt(const char *fmt, ...)
-#else
-out1fmt(va_alist)
-       va_dcl
-#endif
 {
        va_list ap;
-#ifndef __STDC__
-       const char *fmt;
-
-       va_start(ap);
-       fmt = va_arg(ap, const char *);
-#else
        va_start(ap, fmt);
-#endif
-       doformat(out1, fmt, ap);
+       vfprintf(stdout, fmt, ap);
        va_end(ap);
 }
 
-static void
-#ifdef __STDC__
-fmtstr(char *outbuf, size_t length, const char *fmt, ...)
-#else
-fmtstr(va_alist)
-       va_dcl
-#endif
-{
-       va_list ap;
-#ifndef __STDC__
-       char *outbuf;
-       size_t length;
-       const char *fmt;
-
-       va_start(ap);
-       outbuf = va_arg(ap, char *);
-       length = va_arg(ap, size_t);
-       fmt = va_arg(ap, const char *);
-#else
-       va_start(ap, fmt);
-#endif
-       INTOFF;
-       vsnprintf(outbuf, length, fmt, ap);
-       INTON;
-}
-
-#ifndef USE_GLIBC_STDIO
-
-static void
-doformat(struct output *dest, const char *f, va_list ap)
-{
-       char *pm;
-       int size = BUFSIZ;
-
-       while(size) {
-               int nchars;
-
-               pm = xmalloc(size);
-               nchars = vsnprintf(pm, size, f, ap);
-               if(nchars > -1) {
-                       outstr(pm, dest);
-                       size = 0;
-                       }
-               else
-                       size *= 2;
-               free(pm);
-       }
-}
-#endif
-
-
-
 /*
  * Version of write which resumes after a signal is caught.
  */
@@ -9984,29 +9636,6 @@ xwrite(int fd, const char *buf, int nbytes)
 }
 
 
-#ifdef USE_GLIBC_STDIO
-static void initstreams() {
-       output.stream = stdout;
-       errout.stream = stderr;
-}
-
-
-static void
-openmemout() {
-       INTOFF;
-       memout.stream = open_memstream(&memout.buf, &memout.bufsize);
-       INTON;
-}
-
-
-static int
-__closememout() {
-       int error;
-       error = fclose(memout.stream);
-       memout.stream = NULL;
-       return error;
-}
-#endif
 /*
  * Shell command parser.
  */
@@ -10726,7 +10355,9 @@ xxreadtoken() {
                c = pgetc_macro();
                switch (c) {
                case ' ': case '\t':
+#ifdef ASH_ALIAS
                case PEOA:
+#endif
                        continue;
                case '#':
                        while ((c = pgetc()) != '\n' && c != PEOF);
@@ -10973,9 +10604,11 @@ readtoken1(firstc, syntax, eofmark, striptabs)
                        default:
                                if (varnest == 0)
                                        goto endword;   /* exit outer loop */
-                               if (c != PEOA) {
+#ifdef ASH_ALIAS
+                               if (c != PEOA)
+#endif
                                        USTPUTC(c, out);
-                               }
+
                        }
                        c = pgetc_macro();
                }
@@ -11463,10 +11096,10 @@ synexpect(token)
        char msg[64];
 
        if (token >= 0) {
-               fmtstr(msg, 64, "%s unexpected (expecting %s)",
+               snprintf(msg, 64, "%s unexpected (expecting %s)",
                        tokname[lasttoken], tokname[token]);
        } else {
-               fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+               snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
        }
        synerror(msg);
        /* NOTREACHED */
@@ -11477,8 +11110,8 @@ static void
 synerror(const char *msg)
 {
        if (commandname)
-               outfmt(&errout, "%s: %d: ", commandname, startlinno);
-       outfmt(&errout, "Syntax error: %s\n", msg);
+               out2fmt("%s: %d: ", commandname, startlinno);
+       out2fmt("Syntax error: %s\n", msg);
        error((char *)NULL);
        /* NOTREACHED */
 }
@@ -11488,7 +11121,7 @@ synerror(const char *msg)
  * called by editline -- any expansions to the prompt
  *    should be added here.
  */
-static const char *
+static inline const char *
 getprompt(void *unused)
 {
        switch (whichprompt) {
@@ -11529,7 +11162,7 @@ setprompt(int which)
  * old file descriptors are stashed away so that the redirection can be
  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  * standard output, and the standard error if it becomes a duplicate of
- * stdout, is saved in memory.
+ * stdout.
  */
 
 static void
@@ -11564,8 +11197,7 @@ redirect(redir, flags)
 
                INTOFF;
                newfd = openredirect(n);
-               if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
-                   (fd == fileno2)) {
+               if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
                        if (newfd == fd) {
                                try++;
                        } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
@@ -11591,9 +11223,6 @@ redirect(redir, flags)
                                if (flags & REDIR_PUSH) {
                                        sv->renamed[fd] = i;
                                }
-                               if (fd == fileno2) {
-                                       fileno2 = i;
-                               }
                        }
                } else if (fd != newfd) {
                        close(fd);
@@ -11604,10 +11233,6 @@ redirect(redir, flags)
                        dupredirect(n, newfd, memory);
                INTON;
        }
-       if (memory[1])
-               out1 = &memout;
-       if (memory[2])
-               out2 = &memout;
 }
 
 
@@ -11769,9 +11394,6 @@ popredir(void)
                                dup_as_newfd(rp->renamed[i], i);
                                close(rp->renamed[i]);
                        }
-                       if (rp->renamed[i] == fileno2) {
-                               fileno2 = i;
-                       }
                }
        }
        redirlist = rp->next;
@@ -11792,17 +11414,10 @@ clearredir(void) {
                for (i = 0 ; i < 10 ; i++) {
                        if (rp->renamed[i] >= 0) {
                                close(rp->renamed[i]);
-                               if (rp->renamed[i] == fileno2) {
-                                       fileno2 = -1;
-                               }
                        }
                        rp->renamed[i] = EMPTY;
                }
        }
-       if (fileno2 != 2 && fileno2 >= 0) {
-               close(fileno2);
-               fileno2 = -1;
-       }
 }
 
 
@@ -13532,7 +13147,7 @@ findvar(struct var **vpp, const char *name)
 /*
  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
  * This file contains code for the times builtin.
- * $Id: ash.c,v 1.4 2001/07/02 17:27:21 andersen Exp $
+ * $Id: ash.c,v 1.7 2001/07/07 00:05:55 andersen Exp $
  */
 static int timescmd (int argc, char **argv)
 {