]> git.pld-linux.org Git - packages/ash.git/commitdiff
Marge with patches from Debian and current NetBSD.
authorMichal Moskal <michal@moskal.me>
Tue, 24 Apr 2001 09:11:52 +0000 (09:11 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
1c59f5b62a081cb0cb3b053c01d79529  ash-0.4.0.tar.gz

Changed files:
    ash-builtin.patch -> 1.1
    ash-debian.patch -> 1.1
    ash-echo.patch -> 1.3
    ash-freebsd.patch -> 1.1
    ash-getcwd.patch -> 1.1
    ash-getopt.patch -> 1.1
    ash-glob.patch -> 1.1
    ash-hetio.patch -> 1.1
    ash-jobs.patch -> 1.1
    ash-kill.patch -> 1.1
    ash-makefile.patch -> 1.1
    ash-manpage.patch -> 1.1
    ash-memout.patch -> 1.1
    ash-misc.patch -> 1.1
    ash-ppid.patch -> 1.1
    ash-redir.patch -> 1.1
    ash-setmode.patch -> 1.1
    ash-syntax.patch -> 1.1
    ash-test.patch -> 1.1
    ash-times.patch -> 1.1

20 files changed:
ash-builtin.patch [new file with mode: 0644]
ash-debian.patch [new file with mode: 0644]
ash-echo.patch [new file with mode: 0644]
ash-freebsd.patch [new file with mode: 0644]
ash-getcwd.patch [new file with mode: 0644]
ash-getopt.patch [new file with mode: 0644]
ash-glob.patch [new file with mode: 0644]
ash-hetio.patch [new file with mode: 0644]
ash-jobs.patch [new file with mode: 0644]
ash-kill.patch [new file with mode: 0644]
ash-makefile.patch [new file with mode: 0644]
ash-manpage.patch [new file with mode: 0644]
ash-memout.patch [new file with mode: 0644]
ash-misc.patch [new file with mode: 0644]
ash-ppid.patch [new file with mode: 0644]
ash-redir.patch [new file with mode: 0644]
ash-setmode.patch [new file with mode: 0644]
ash-syntax.patch [new file with mode: 0644]
ash-test.patch [new file with mode: 0644]
ash-times.patch [new file with mode: 0644]

diff --git a/ash-builtin.patch b/ash-builtin.patch
new file mode 100644 (file)
index 0000000..d0af919
--- /dev/null
@@ -0,0 +1,852 @@
+diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def
+--- netbsd-sh/builtins.def     Mon Apr 10 13:02:58 2000
++++ ash-0.3.7.orig/builtins.def        Mon Apr 23 22:16:46 2001
+@@ -49,12 +49,13 @@
+ #
+ # NOTE: bltincmd must come first!
+-bltincmd      command
++bltincmd      builtin
+ #alloccmd     alloc
+ bgcmd -j      bg
+ breakcmd      break continue
+ #catfcmd      catf
+ cdcmd         cd chdir
++commandcmd    command
+ dotcmd                .
+ echocmd               echo
+ evalcmd               eval
+diff -urN netbsd-sh/eval.c ash-0.3.7.orig/eval.c
+--- netbsd-sh/eval.c   Tue May 23 12:03:18 2000
++++ ash-0.3.7.orig/eval.c      Mon Apr 23 22:16:46 2001
+@@ -45,7 +45,9 @@
+ #endif
+ #endif /* not lint */
++#include <sys/types.h>
+ #include <signal.h>
++#include <malloc.h>
+ #include <unistd.h>
+ /*
+@@ -101,6 +103,8 @@
+ STATIC void evalpipe __P((union node *));
+ STATIC void evalcommand __P((union node *, int, struct backcmd *));
+ STATIC void prehash __P((union node *));
++STATIC int is_assignment_builtin __P((const char *));
++STATIC const char *get_standard_path __P((void));
+ /*
+@@ -257,6 +261,11 @@
+               evalcase(n, flags);
+               break;
+       case NDEFUN:
++              if (is_special_builtin(n->narg.text)) {
++                      outfmt(out2, "%s is a special built-in\n", n->narg.text);
++                      exitstatus = 1;
++                      break;
++              }
+               defun(n->narg.text, n->narg.next);
+               exitstatus = 0;
+               break;
+@@ -279,7 +288,7 @@
+ out:
+       if (pendingsigs)
+               dotrap();
+-      if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
++      if (flags & EV_EXIT)
+               exitshell(exitstatus);
+ }
+@@ -497,9 +507,14 @@
+                               close(0);
+                               copyfd(prevfd, 0);
+                               close(prevfd);
++                              if (pip[0] == 0) {
++                                      pip[0] = -1;
++                              }
+                       }
+                       if (pip[1] >= 0) {
+-                              close(pip[0]);
++                              if (pip[0] >= 0) {
++                                      close(pip[0]);
++                              }
+                               if (pip[1] != 1) {
+                                       close(1);
+                                       copyfd(pip[1], 1);
+@@ -607,6 +622,7 @@
+       int argc;
+       char **envp;
+       int varflag;
++      int pseudovarflag;
+       struct strlist *sp;
+       int mode;
+       int pip[2];
+@@ -619,12 +635,17 @@
+       struct localvar *volatile savelocalvars;
+       volatile int e;
+       char *lastarg;
++      int not_special;
++      const char *path;
++      const char *standard_path;
+ #if __GNUC__
+       /* Avoid longjmp clobbering */
+       (void) &argv;
+       (void) &argc;
+       (void) &lastarg;
+       (void) &flags;
++      (void) &not_special;
++      (void) &standard_path;
+ #endif
+       /* First expand the arguments. */
+@@ -632,21 +653,31 @@
+       setstackmark(&smark);
+       arglist.lastp = &arglist.list;
+       varlist.lastp = &varlist.list;
++      arglist.list = 0;
+       varflag = 1;
++      pseudovarflag = 0;
+       oexitstatus = exitstatus;
+       exitstatus = 0;
++      not_special = 0;
++      path = pathval();
++      standard_path = NULL;
+       for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
+               char *p = argp->narg.text;
+-              if (varflag && is_name(*p)) {
++              if ((varflag || pseudovarflag) && is_name(*p)) {
+                       do {
+                               p++;
+                       } while (is_in_name(*p));
+                       if (*p == '=') {
+-                              expandarg(argp, &varlist, EXP_VARTILDE);
++                              if (varflag)
++                                      expandarg(argp, &varlist, EXP_VARTILDE);
++                              else
++                                      expandarg(argp, &arglist, EXP_VARTILDE);
+                               continue;
+                       }
+               }
+               expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
++              if (varflag && arglist.list && is_assignment_builtin(arglist.list->text))
++                      pseudovarflag = 1;
+               varflag = 0;
+       }
+       *arglist.lastp = NULL;
+@@ -688,37 +719,75 @@
+               cmdentry.u.index = BLTINCMD;
+       } else {
+               static const char PATH[] = "PATH=";
+-              const char *path = pathval();
++              const char *oldpath = NULL;
++              int findflag = DO_ERR;
+               /*
+                * Modify the command lookup path, if a PATH= assignment
+                * is present
+                */
+               for (sp = varlist.list ; sp ; sp = sp->next)
+-                      if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
++                      if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
+                               path = sp->text + sizeof(PATH) - 1;
+-
+-              find_command(argv[0], &cmdentry, DO_ERR, path);
+-              if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
+-                      exitstatus = 127;
+-                      flushout(&errout);
+-                      return;
+-              }
+-              /* implement the bltin builtin here */
+-              if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
+-                      for (;;) {
++                              findflag |= DO_BRUTE;
++                      }
++              for(;;) {
++                      find_command(argv[0], &cmdentry, findflag, path);
++                      if (oldpath) {
++                              path = oldpath;
++                              oldpath = NULL;
++                      }
++                      if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
++                              exitstatus = 127;
++                              flushout(&errout);
++                              goto out;
++                      }
++                      /* implement the bltin builtin here */
++                      if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
++                              not_special = 1;
++                              for(;;) {
++                                      argv++;
++                                      if (--argc == 0)
++                                              break;
++                                      if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
++                                              outfmt(&errout, "%s: not found\n", *argv);
++                                              exitstatus = 127;
++                                              flushout(&errout);
++                                              goto out;
++                                      }
++                                      if (cmdentry.u.index != BLTINCMD)
++                                              break;
++                              }
++                      }
++                      if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == COMMANDCMD) {
++                              not_special = 1;
+                               argv++;
+-                              if (--argc == 0)
+-                                      break;
+-                              if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
+-                                      outfmt(&errout, "%s: not found\n", *argv);
+-                                      exitstatus = 127;
+-                                      flushout(&errout);
+-                                      return;
++                              if (--argc == 0) {
++                                      exitstatus = 0;
++                                      goto out;
+                               }
+-                              if (cmdentry.u.index != BLTINCMD)
+-                                      break;
++                              if (*argv[0] == '-') {
++                                      if (!equal(argv[0], "-p")) {
++                                              argv--;
++                                              argc++;
++                                              break;
++                                      }
++                                      argv++;
++                                      if (--argc == 0) {
++                                              exitstatus = 0;
++                                              goto out;
++                                      }
++                                      if (!standard_path) {
++                                              standard_path = get_standard_path();
++                                      }
++                                      oldpath = path;
++                                      path = standard_path;
++                                      findflag |= DO_BRUTE;
++                              }
++                              findflag |= DO_NOFUN;
++                              continue;
+                       }
++                      break;
+               }
+       }
+@@ -756,13 +825,12 @@
+ #ifdef DEBUG
+               trputs("Shell function:  ");  trargs(argv);
+ #endif
++              exitstatus = oexitstatus;
+               redirect(cmd->ncmd.redirect, REDIR_PUSH);
+               saveparam = shellparam;
+               shellparam.malloc = 0;
+-              shellparam.reset = 1;
+               shellparam.nparam = argc - 1;
+               shellparam.p = argv + 1;
+-              shellparam.optnext = NULL;
+               INTOFF;
+               savelocalvars = localvars;
+               localvars = NULL;
+@@ -772,6 +840,8 @@
+                               freeparam((volatile struct shparam *)
+                                   &saveparam);
+                       } else {
++                              saveparam.optind = shellparam.optind;
++                              saveparam.optoff = shellparam.optoff;
+                               freeparam(&shellparam);
+                               shellparam = saveparam;
+                       }
+@@ -790,6 +860,8 @@
+               INTOFF;
+               poplocalvars();
+               localvars = savelocalvars;
++              saveparam.optind = shellparam.optind;
++              saveparam.optoff = shellparam.optoff;
+               freeparam(&shellparam);
+               shellparam = saveparam;
+               handler = savehandler;
+@@ -832,6 +908,8 @@
+               out1 = &output;
+               out2 = &errout;
+               freestdout();
++              if (!not_special && is_special_builtin(commandname))
++                      listsetvar(cmdenviron);
+               cmdenviron = NULL;
+               if (e != EXSHELLPROC) {
+                       commandname = savecmdname;
+@@ -867,7 +953,7 @@
+               for (sp = varlist.list ; sp ; sp = sp->next)
+                       setvareq(sp->text, VEXPORT|VSTACK);
+               envp = environment();
+-              shellexec(argv, envp, pathval(), cmdentry.u.index);
++              shellexec(argv, envp, path, cmdentry.u.index);
+       }
+       goto out;
+@@ -1025,4 +1111,49 @@
+               shellexec(argv + 1, environment(), pathval(), 0);
+       }
+       return 0;
++}
++
++STATIC int
++is_assignment_builtin (command)
++      const char *command;
++{
++      static const char *assignment_builtins[] = {
++              "alias", "declare", "export", "local", "readonly", "typeset",
++              (char *)NULL
++      };
++      int i;
++
++      for (i = 0; assignment_builtins[i]; i++)
++              if (strcmp(command, assignment_builtins[i]) == 0) return 1;
++      return 0;
++}
++
++int
++is_special_builtin(name)
++      const char *name;
++{
++      static const char *special_builtins[] = {
++              "break", ":", ".", "continue", "eval", "exec", "exit",
++              "export", "readonly", "return", "set", "shift", "times",
++              "trap", "unset", (char *)NULL
++      };
++      int i;
++
++      if (!name) return 0;
++      for (i = 0; special_builtins[i]; i++)
++              if (equal(name, special_builtins[i])) return 1;
++      return 0;
++}
++
++STATIC const char *
++get_standard_path()
++{
++      char *p;
++      size_t len;
++
++      len = confstr(_CS_PATH, NULL, 0);
++      p = stalloc(len + 2);
++      *p = '\0';
++      confstr(_CS_PATH, p, len);
++      return p;
+ }
+diff -urN netbsd-sh/eval.h ash-0.3.7.orig/eval.h
+--- netbsd-sh/eval.h   Fri Jan 28 13:03:00 2000
++++ ash-0.3.7.orig/eval.h      Mon Apr 23 22:16:46 2001
+@@ -61,6 +61,7 @@
+ int falsecmd __P((int, char **));
+ int truecmd __P((int, char **));
+ int execcmd __P((int, char **));
++int is_special_builtin __P((const char *));
+ /* in_function returns nonzero if we are currently evaluating a function */
+ #define in_function() funcnest
+diff -urN netbsd-sh/exec.c ash-0.3.7.orig/exec.c
+--- netbsd-sh/exec.c   Fri Jan 12 17:50:35 2001
++++ ash-0.3.7.orig/exec.c      Mon Apr 23 22:16:46 2001
+@@ -51,6 +51,7 @@
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <stdlib.h>
++#include <sysexits.h>
+ /*
+  * When commands are first encountered, they are entered in a hash table.
+@@ -108,6 +109,9 @@
+ STATIC void clearcmdentry __P((int));
+ STATIC struct tblentry *cmdlookup __P((char *, int));
+ STATIC void delete_cmd_entry __P((void));
++STATIC int describe_command __P((char *, int));
++STATIC int path_change __P((const char *, int *));
++STATIC int is_regular_builtin __P((const char *));
+@@ -164,7 +172,7 @@
+       char **envp;
+       {
+       int e;
+-#ifndef BSD
++#if !defined(BSD) && !defined(linux)
+       char *p;
+ #endif
+@@ -180,7 +188,7 @@
+               initshellproc();
+               setinputfile(cmd, 0);
+               commandname = arg0 = savestr(argv[0]);
+-#ifndef BSD
++#if !defined(BSD) && !defined(linux)
+               pgetc(); pungetc();             /* fill up input buffer */
+               p = parsenextc;
+               if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
+@@ -195,7 +203,7 @@
+ }
+-#ifndef BSD
++#if !defined(BSD) && !defined(linux)
+ /*
+  * Execute an interpreter introduced by "#!", for systems where this
+  * feature has not been built into the kernel.  If the interpreter is
+@@ -351,27 +359,29 @@
+       if (*argptr == NULL) {
+               for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+                       for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+-                              printentry(cmdp, verbose);
++                              if (cmdp->cmdtype != CMDBUILTIN) {
++                                      printentry(cmdp, verbose);
++                              }
+                       }
+               }
+               return 0;
+       }
++      c = 0;
+       while ((name = *argptr) != NULL) {
+               if ((cmdp = cmdlookup(name, 0)) != NULL
+                && (cmdp->cmdtype == CMDNORMAL
+                    || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
+                       delete_cmd_entry();
+               find_command(name, &entry, DO_ERR, pathval());
+-              if (verbose) {
+-                      if (entry.cmdtype != CMDUNKNOWN) {      /* if no error msg */
+-                              cmdp = cmdlookup(name, 0);
+-                              printentry(cmdp, verbose);
+-                      }
++              if (entry.cmdtype == CMDUNKNOWN) c = 1;
++              else if (verbose) {
++                      cmdp = cmdlookup(name, 0);
++                      if (cmdp) printentry(cmdp, verbose);
+                       flushall();
+               }
+               argptr++;
+       }
+-      return 0;
++      return c;
+ }
+@@ -435,6 +445,10 @@
+       struct stat statb;
+       int e;
+       int i;
++      int bltin;
++      int firstchange;
++      int updatetbl;
++      int regular;
+       /* If name contains a slash, don't use the hash table */
+       if (strchr(name, '/') != NULL) {
+@@ -459,12 +473,54 @@
+               return;
+       }
++      updatetbl = 1;
++      if (act & DO_BRUTE) {
++              firstchange = path_change(path, &bltin);
++      } else {
++              bltin = builtinloc;
++              firstchange = 9999;
++      }
++
+       /* If name is in the table, and not invalidated by cd, we're done */
+-      if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
+-              goto success;
++      if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
++              if (cmdp->cmdtype == CMDFUNCTION) {
++                      if (act & DO_NOFUN) {
++                              updatetbl = 0;
++                      } else {
++                              goto success;
++                      }
++              } else if (act & DO_BRUTE) {
++                      if ((cmdp->cmdtype == CMDNORMAL &&
++                           cmdp->param.index >= firstchange) ||
++                          (cmdp->cmdtype == CMDBUILTIN &&
++                           ((builtinloc < 0 && bltin >= 0) ?
++                            bltin : builtinloc) >= firstchange)) {
++                              /* need to recompute the entry */
++                      } else {
++                              goto success;
++                      }
++              } else {
++                      goto success;
++              }
++      }
++
++      if ((regular = is_regular_builtin(name))) {
++              if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
++                      goto success;
++              }
++      } else if (act & DO_BRUTE) {
++              if (firstchange == 0) {
++                      updatetbl = 0;
++              }
++      }
+       /* If %builtin not in path, check for builtin next */
+-      if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
++      if ((bltin < 0 || regular) && (i = find_builtin(name)) >= 0) {
++              if (!updatetbl) {
++                      entry->cmdtype = CMDBUILTIN;
++                      entry->u.index = i;
++                      return;
++              }
+               INTOFF;
+               cmdp = cmdlookup(name, 1);
+               cmdp->cmdtype = CMDBUILTIN;
+@@ -475,7 +531,7 @@
+       /* We have to search path. */
+       prev = -1;              /* where to start */
+-      if (cmdp) {             /* doing a rehash */
++      if (cmdp && cmdp->rehash) {     /* doing a rehash */
+               if (cmdp->cmdtype == CMDBUILTIN)
+                       prev = builtinloc;
+               else
+@@ -488,26 +544,38 @@
+       while ((fullname = padvance(&path, name)) != NULL) {
+               stunalloc(fullname);
+               idx++;
++              if (idx >= firstchange) {
++                      updatetbl = 0;
++              }
+               if (pathopt) {
+                       if (prefix("builtin", pathopt)) {
+-                              if ((i = find_builtin(name)) < 0)
+-                                      goto loop;
+-                              INTOFF;
+-                              cmdp = cmdlookup(name, 1);
+-                              cmdp->cmdtype = CMDBUILTIN;
+-                              cmdp->param.index = i;
+-                              INTON;
+-                              goto success;
+-                      } else if (prefix("func", pathopt)) {
++                              if ((i = find_builtin(name)) >= 0) {
++                                      if (!updatetbl) {
++                                              entry->cmdtype = CMDBUILTIN;
++                                              entry->u.index = i;
++                                              return;
++                                      }
++                                      INTOFF;
++                                      cmdp = cmdlookup(name, 1);
++                                      cmdp->cmdtype = CMDBUILTIN;
++                                      cmdp->param.index = i;
++                                      INTON;
++                                      goto success;
++                              } else {
++                                      continue;
++                              }
++                      } else if (!(act & DO_NOFUN) &&
++                                 prefix("func", pathopt)) {
+                               /* handled below */
+                       } else {
+-                              goto loop;      /* ignore unimplemented options */
++                              continue;       /* ignore unimplemented options */
+                       }
+               }
+               /* if rehash, don't redo absolute path names */
+-              if (fullname[0] == '/' && idx <= prev) {
++              if (fullname[0] == '/' && idx <= prev &&
++                  idx < firstchange) {
+                       if (idx < prev)
+-                              goto loop;
++                              continue;
+                       TRACE(("searchexec \"%s\": no change\n", name));
+                       goto success;
+               }
+@@ -522,7 +590,7 @@
+               }
+               e = EACCES;     /* if we fail, this will be the error */
+               if (!S_ISREG(statb.st_mode))
+-                      goto loop;
++                      continue;
+               if (pathopt) {          /* this is a %func directory */
+                       stalloc(strlen(fullname) + 1);
+                       readcmdfile(fullname);
+@@ -544,6 +612,13 @@
+               }
+ #endif
+               TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
++              /* If we aren't called with DO_BRUTE and cmdp is set, it must
++                 be a function and we're being called with DO_NOFUN */
++              if (!updatetbl) {
++                      entry->cmdtype = CMDNORMAL;
++                      entry->u.index = idx;
++                      return;
++              }
+               INTOFF;
+               cmdp = cmdlookup(name, 1);
+               cmdp->cmdtype = CMDNORMAL;
+@@ -553,7 +628,7 @@
+       }
+       /* We failed.  If there was an entry for this command, delete it */
+-      if (cmdp)
++      if (cmdp && updatetbl)
+               delete_cmd_entry();
+       if (act & DO_ERR)
+               outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
+@@ -618,37 +693,12 @@
+ changepath(newval)
+       const char *newval;
+ {
+-      const char *old, *new;
+-      int idx;
+       int firstchange;
+       int bltin;
+-      old = pathval();
+-      new = newval;
+-      firstchange = 9999;     /* assume no change */
+-      idx = 0;
+-      bltin = -1;
+-      for (;;) {
+-              if (*old != *new) {
+-                      firstchange = idx;
+-                      if ((*old == '\0' && *new == ':')
+-                       || (*old == ':' && *new == '\0'))
+-                              firstchange++;
+-                      old = new;      /* ignore subsequent differences */
+-              }
+-              if (*new == '\0')
+-                      break;
+-              if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
+-                      bltin = idx;
+-              if (*new == ':') {
+-                      idx++;
+-              }
+-              new++, old++;
+-      }
++      firstchange = path_change(newval, &bltin);
+       if (builtinloc < 0 && bltin >= 0)
+               builtinloc = bltin;             /* zap builtins */
+-      if (builtinloc >= 0 && bltin < 0)
+-              firstchange = 0;
+       clearcmdentry(firstchange);
+       builtinloc = bltin;
+ }
+@@ -838,11 +888,9 @@
+       {
+       struct cmdentry entry;
+-      INTOFF;
+       entry.cmdtype = CMDFUNCTION;
+       entry.u.func = copyfunc(func);
+       addcmdentry(name, &entry);
+-      INTON;
+ }
+@@ -944,4 +992,190 @@
+               }
+       }
+       return err;
++}
++
++STATIC int
++describe_command(command, verbose)
++      char *command;
++      int verbose;
++{
++      struct cmdentry entry;
++      struct tblentry *cmdp;
++      char **pp;
++      struct alias *ap;
++      extern char *const parsekwd[];
++
++      for (pp = (char **)parsekwd; *pp; pp++)
++              if (**pp == *command && equal(*pp, command))
++                      break;
++
++      if (*pp) {
++              if (verbose) {
++                      out1fmt("%s is a reserved word\n", command);
++              } else {
++                      out1fmt("%s\n", command);
++              }
++              return 0;
++      }
++
++      /* Then look at the aliases */
++      if ((ap = lookupalias(command, 1)) != NULL) {
++              if (verbose) {
++                      out1fmt("%s is aliased to `%s'\n", command, ap->val);
++              } else {
++                      out1fmt("alias %s='%s'\n", command, ap->val);
++              }
++              return 0;
++      }
++
++      /* Then check if it is a tracked alias */
++      if ((cmdp = cmdlookup(command, 0)) != NULL) {
++              entry.cmdtype = cmdp->cmdtype;
++              entry.u = cmdp->param;
++      }
++      else {
++              /* Finally use brute force */
++              find_command(command, &entry, DO_ABS, pathval());
++      }
++
++      switch (entry.cmdtype) {
++      case CMDNORMAL: {
++              int j = entry.u.index;
++              const char *path = pathval();
++              char *name;
++              if (j == -1) 
++                      name = command;
++              else {
++                      do { 
++                              name = padvance(&path, command);
++                              stunalloc(name);
++                      } while (--j >= 0);
++              }
++              if (verbose) {
++                      out1fmt("%s is %s\n", command, name);
++              } else {
++                      out1fmt("%s\n", name);
++              }
++              break;
++      }
++      case CMDFUNCTION:
++              if (verbose) {
++                      out1fmt("%s is a function\n", command);
++              } else {
++                      out1fmt("%s\n", command);
++              }
++              break;
++      case CMDBUILTIN:
++              if (verbose) {
++                      if (is_special_builtin(command)) {
++                              out1fmt("%s is a special built-in utility\n", command);
++                      } else {
++                              out1fmt("%s is a built-in utility\n", command);
++                      }
++              } else {
++                      out1fmt("%s\n", command);
++              }
++              break;
++      default:
++              outfmt(out2, "%s not found\n", command);
++              return 127;
++      }
++
++      return 0;
++}
++
++int
++commandcmd(argc, argv)
++      int argc;
++      char **argv;
++{
++      int c;
++      int default_path = 0;
++      int verify_only = 0;
++      int verbose_verify_only = 0;
++
++      while ((c = nextopt("pvV")) != '\0')
++              switch (c) {
++              case 'p':
++                      default_path = 1;
++                      break;
++              case 'v':
++                      verify_only = 1;
++                      break;
++              case 'V':
++                      verbose_verify_only = 1;
++                      break;
++              default:
++                      outfmt(out2,
++"command: nextopt returned character code 0%o\n", c);
++                      return EX_SOFTWARE;
++              }
++
++      if (default_path + verify_only + verbose_verify_only > 1 ||
++          !*argptr) {
++                      outfmt(out2,
++"command [-p] command [arg ...]\n");
++                      outfmt(out2,
++"command {-v|-V} command\n");
++                      return EX_USAGE;
++      }
++
++      if (verify_only || verbose_verify_only) {
++              return describe_command(*argptr, verbose_verify_only);
++      }
++
++      return 0;
++}
++
++STATIC int
++path_change(newval, bltin)
++      const char *newval;
++      int *bltin;
++{
++      const char *old, *new;
++      int idx;
++      int firstchange;
++
++      old = pathval();
++      new = newval;
++      firstchange = 9999;     /* assume no change */
++      idx = 0;
++      *bltin = -1;
++      for (;;) {
++              if (*old != *new) {
++                      firstchange = idx;
++                      if ((*old == '\0' && *new == ':')
++                       || (*old == ':' && *new == '\0'))
++                              firstchange++;
++                      old = new;      /* ignore subsequent differences */
++              }
++              if (*new == '\0')
++                      break;
++              if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
++                      *bltin = idx;
++              if (*new == ':') {
++                      idx++;
++              }
++              new++, old++;
++      }
++      if (builtinloc >= 0 && *bltin < 0)
++              firstchange = 0;
++      return firstchange;
++}
++
++STATIC int
++is_regular_builtin(name)
++        const char *name;
++{
++        static const char *regular_builtins[] = {
++              "alias", "bg", "cd", "command", "false", "fc", "fg",
++              "getopts", "jobs", "kill", "newgrp", "read", "true",
++              "umask", "unalias", "wait", (char *)NULL
++        };
++        int i;
++
++        if (!name) return 0;
++        for (i = 0; regular_builtins[i]; i++)
++                if (equal(name, regular_builtins[i])) return 1;
++        return 0;
+ }
+diff -urN netbsd-sh/exec.h ash-0.3.7.orig/exec.h
+--- netbsd-sh/exec.h   Tue May 23 12:03:19 2000
++++ ash-0.3.7.orig/exec.h      Mon Apr 23 22:16:46 2001
+@@ -56,6 +56,8 @@
+ #define DO_ERR        1               /* find_command prints errors */
+ #define DO_ABS        2               /* find_command checks absolute paths */
++#define DO_NOFUN      4       /* find_command ignores functions */
++#define DO_BRUTE      8       /* find_command ignores hash table */
+ extern const char *pathopt;   /* set by padvance */
+ extern int exerrno;           /* last exec error */
+@@ -74,3 +76,4 @@
+ void defun __P((char *, union node *));
+ int unsetfunc __P((char *));
+ int typecmd __P((int, char **));
++int commandcmd __P((int, char **));
+
diff --git a/ash-debian.patch b/ash-debian.patch
new file mode 100644 (file)
index 0000000..7a0584d
--- /dev/null
@@ -0,0 +1,702 @@
+diff -urN netbsd-sh/debian/README.debian ash-0.3.7.orig/debian/README.debian
+--- netbsd-sh/debian/README.debian     Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/README.debian        Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,14 @@
++ash for DEBIAN
++----------------------
++
++This is a very simple port of ash taken from NetBSD-current on 1997/06/18.  The
++file setmode.c was taken from src/libc/gen and is needed since the Linux libc
++does provide getmode(3) or setmode(3).  History editing is disabled to avoid
++code bloat.  This also means that building the package is possible without the
++BSD libedit.
++
++This port is preriodically revised to keep up to date with NetBSD's current
++release.
++
++Herbert Xu <herbert@debian.org>
++$Id$
+diff -urN netbsd-sh/debian/ash-medium.README.Debian ash-0.3.7.orig/debian/ash-medium.README.Debian
+--- netbsd-sh/debian/ash-medium.README.Debian  Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/ash-medium.README.Debian     Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,14 @@
++ash for DEBIAN
++----------------------
++
++This is a very simple port of ash taken from NetBSD-current on 1997/06/18.  The
++file setmode.c was taken from src/libc/gen and is needed since the Linux libc
++does provide getmode(3) or setmode(3).  History editing is disabled to avoid
++code bloat.  This also means that building the package is possible without the
++BSD libedit.
++
++This port is preriodically revised to keep up to date with NetBSD's current
++release.
++
++Herbert Xu <herbert@debian.org>
++$Id$
+diff -urN netbsd-sh/debian/ash-medium.dirs ash-0.3.7.orig/debian/ash-medium.dirs
+--- netbsd-sh/debian/ash-medium.dirs   Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/ash-medium.dirs      Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,2 @@
++usr/bin
++usr/share/man/man1
+diff -urN netbsd-sh/debian/ash-udeb.dirs ash-0.3.7.orig/debian/ash-udeb.dirs
+--- netbsd-sh/debian/ash-udeb.dirs     Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/ash-udeb.dirs        Mon Apr 23 22:16:46 2001
+@@ -0,0 +1 @@
++bin
+diff -urN netbsd-sh/debian/bsdyacc ash-0.3.7.orig/debian/bsdyacc
+--- netbsd-sh/debian/bsdyacc   Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/bsdyacc      Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,20 @@
++#!/bin/sh -e
++
++if echo "$@" | grep -q -- -o; then
++      OUTPUT=$(echo "$@" |
++               sed 's/.*-o[[:blank:]]\+\([^[:blank:]]\+\)\.c.*/\1/')
++      OPTIONS=$(echo "$@" |
++               sed 's/\(.*\)-o[[:blank:]]\+[^[:blank:]]\+\(.*\)/\1\2/')
++      NEW=1
++else
++      OUTPUT=$(echo "$@" |
++               sed -e 's/.*[[:blank:]]\+\([^[:blank:]]\+\)\.y.*/\1/')
++      OPTIONS="$@"
++      NEW=0
++fi
++
++byacc $OPTIONS
++if [ $NEW = 1 ]; then
++      mv y.tab.c $OUTPUT.c
++fi
++mv y.tab.h $OUTPUT.h
+diff -urN netbsd-sh/debian/changelog ash-0.3.7.orig/debian/changelog
+--- netbsd-sh/debian/changelog Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/changelog    Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,429 @@
++ash (0.3.7-14) unstable; urgency=low
++
++  * Removed predependency from udeb (closes: #81995).
++  * Added /bin/sh symlink to udeb (closes: #81967).
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 13 Jan 2001 15:23:21 +1100
++
++ash (0.3.7-13) unstable; urgency=low
++
++  * Renamed the udeb to ash-udeb.
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 20 Dec 2000 19:32:34 +1100
++
++ash (0.3.7-12) unstable; urgency=low
++
++  * Added support for udebs (Randolph Chung, closes: #79237).
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 16 Dec 2000 13:53:28 +1100
++
++ash (0.3.7-11) unstable; urgency=low
++
++  * Preserve the previous exit status upon entering a function
++    (closes: #78374).
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  3 Dec 2000 13:34:27 +1100
++
++ash (0.3.7-10) unstable; urgency=low
++
++  * Merged changes for GNU from Igor Khavkine.
++  * Minimise the number of sigactions.
++
++ -- Herbert Xu <herbert@debian.org>  Fri,  3 Nov 2000 20:31:52 +1100
++
++ash (0.3.7-9) unstable; urgency=low
++
++  * Predepend on the libraries.
++  * Always save fd 2 when it is redirected (closes: #75302).
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 22 Oct 2000 08:40:40 +1100
++
++ash (0.3.7-8) unstable; urgency=high
++
++  * More redirection fixes (closes: #73613).
++
++ -- Herbert Xu <herbert@debian.org>  Thu,  5 Oct 2000 18:22:17 +1100
++
++ash (0.3.7-7) unstable; urgency=high
++
++  * Added missing break in redirection code (closes: #72956).
++
++ -- Herbert Xu <herbert@debian.org>  Tue,  3 Oct 2000 07:58:04 +1100
++
++ash (0.3.7-6) unstable; urgency=low
++
++  * command -[vV] no longer displays an error message on stdout.
++  * Redirecting to /proc/self/fd/* now works (closes: #72852).
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  1 Oct 2000 12:56:39 +1100
++
++ash (0.3.7-5) unstable; urgency=low
++
++  * Implemented set -a.
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 30 Sep 2000 16:00:33 +1100
++
++ash (0.3.7-4) unstable; urgency=low
++
++  * Added build-time dependency on debhelper (closes: #69920).
++  * Extended maximum length of arithmetic expansions to match 32-bit integers.
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 20 Sep 2000 14:28:16 +1100
++
++ash (0.3.7-3) unstable; urgency=low
++
++  * Switch to the old globbing code since glob(3) is hopelessly broken
++    (closes: #69455).
++
++ -- Herbert Xu <herbert@debian.org>  Mon, 21 Aug 2000 20:37:15 +1000
++
++ash (0.3.7-2) unstable; urgency=low
++
++  * Call glob(3) with GLOB_NOMAGIC (ouch).
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  6 Aug 2000 17:47:08 +1000
++
++ash (0.3.7-1) unstable; urgency=low
++
++  * NetBSD-current version as of 20000729.
++  * Use fnmatch(3) and glob(3).
++  * Fixed the use of backslashes in the pattern in parameter substitutions,
++    hopefully for the last time.
++  * Applied HETIO patch and built ash.medium (closes: #50788).  Will do ash.big
++    when readline is fixed so that it doesn't leak anymore.
++
++ -- Herbert Xu <herbert@debian.org>  Fri,  4 Aug 2000 21:36:44 +1000
++
++ash (0.3.6-5) unstable; urgency=low
++
++  * Fixed manpage entry for read with patch from Kevin Ryde (closes: #62500).
++  * Fixed a file descriptor leak for pipelines.
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 19 Apr 2000 18:56:20 +1000
++
++ash (0.3.6-4) unstable; urgency=low
++
++  * Fixed the case of an empty command with redirections.
++
++ -- Herbert Xu <herbert@debian.org>  Fri,  7 Apr 2000 12:07:18 +1000
++
++ash (0.3.6-3) unstable; urgency=low
++
++  * ! is now recognised correctly.
++  * Ash is now more strict on the syntax, e.g., a lone ! is no longer accepted
++    as an alternative to ! true.
++
++ -- Herbert Xu <herbert@debian.org>  Fri,  7 Apr 2000 10:46:06 +1000
++
++ash (0.3.6-2) unstable; urgency=low
++
++  * Fixed a problem with fmtstr() which broke getopts.
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  2 Apr 2000 10:49:26 +1000
++
++ash (0.3.6-1) unstable; urgency=low
++
++  * NetBSD-current version as of 20000326.
++  * Added a Build-Depends on groff (closes: #61041).
++  * Implemented noclobber (closes: #59028).
++  * Rewrote output.c to use stream IO.
++
++ -- Herbert Xu <herbert@debian.org>  Sat,  1 Apr 2000 19:24:31 +1000
++
++ash (0.3.5-10) frozen unstable; urgency=low
++
++  * Don't stat mail boxes in non-interactive mode (closes: #59213).
++  * Added an fflush(stdout) to the times builtin (closes: #59027).
++  * Documented the times builtin.
++  * Added source depends.
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 18 Mar 2000 18:58:44 +1100
++
++ash (0.3.5-9) unstable; urgency=low
++
++  * Double quotes inside paramater substitutions inside double quotes are now
++    ignored as in bash (the originial behaviour was POSIX compliant too but
++    IMHO this one makes a little bit more sense).
++    This one broke mwm (but it was actually mwm's fault).
++  * Corrected backslash/CTLESC treatment for patterns in parameter
++    substitutions.
++
++ -- Herbert Xu <herbert@debian.org>  Sat,  6 Nov 1999 18:13:19 +1100
++
++ash (0.3.5-8) unstable; urgency=low
++
++  * Replaced use of echo -n in manual page with escape codes.
++  * Made FHS compliant (closes: #47978).
++  * Restored echo's option processing ability.
++
++ -- Herbert Xu <herbert@debian.org>  Fri, 22 Oct 1999 10:20:58 +1000
++
++ash (0.3.5-7) unstable; urgency=low
++
++  * echo no longer supports options.
++  * Don't quote patterns inside parameter substitutions enclosed by double
++    quotes (closes: #47842).
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 20 Oct 1999 20:28:14 +1000
++
++ash (0.3.5-6) unstable; urgency=low
++
++  * Use getcwd() instead of /bin/pwd -- Zack Weinberg (closes: #46981).
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 10 Oct 1999 16:31:49 +1000
++
++ash (0.3.5-5) unstable; urgency=low
++
++  * Only test for -e on simple commands (fixes #44559).
++
++ -- Herbert Xu <herbert@debian.org>  Wed,  8 Sep 1999 22:18:27 +1000
++
++ash (0.3.5-4) unstable; urgency=low
++
++  * Don't wait for stopped children if job control is disabled (fixes #42814).
++  * Allow an option '(' in a case statement (fixes #42364).
++
++ -- Herbert Xu <herbert@debian.org>  Thu, 12 Aug 1999 23:30:30 +1000
++
++ash (0.3.5-3) unstable; urgency=low
++
++  * OK, the fix to the esoteric problem in 0.3.5-1 actually breaks VSASSIGN
++    and VSQUESTION, they should work properly now (fixes #41327).
++
++ -- Herbert Xu <herbert@debian.org>  Thu, 15 Jul 1999 22:47:13 +1000
++
++ash (0.3.5-2) unstable; urgency=low
++
++  * PATH search and execution is now correct.
++  * hash no longer shows builtins.
++  * Added kill builtin.
++  * New description from James R. van Zandt reformatted by Josip Rodin.
++
++ -- Herbert Xu <herbert@debian.org>  Mon, 12 Jul 1999 18:51:42 +1000
++
++ash (0.3.5-1) unstable; urgency=low
++
++  * New upstream release.
++  * Adapted to new pmake (fixes #38737).
++  * Fixed behvaiour of backslashes preceding a closing brace for a parameter
++    substituion inside double quotes (even bash messes this one up :).
++  * Fixed command (fixes #34639).
++  * Fixed a pipe bug where stdin may be wrongly closed (fixes #35452).
++  * Revamped getopts (fixes #39694).
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  4 Jul 1999 12:19:01 +1000
++
++ash (0.3.4-7) unstable; urgency=low
++
++  * Fixed a glibc 2.1 compatitibility problem.
++  * Fixed a PWD inconsistency that stuffed up the kernel compilation.
++
++ -- Herbert Xu <herbert@debian.org>  Mon, 17 May 1999 23:14:57 +1000
++
++ash (0.3.4-6) unstable; urgency=low
++
++  * Fixed incorrect -e test due to the last bug fix (fixes #26509).
++
++ -- Herbert Xu <herbert@debian.org>  Tue,  8 Sep 1998 10:02:46 +1000
++
++ash (0.3.4-5) unstable; urgency=low
++
++  * Use test_eaccess from bash instead of access(2) (fixes #26110).
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 26 Aug 1998 21:22:49 +1000
++
++ash (0.3.4-4) unstable; urgency=low
++
++  * Only upload to unstable.
++
++ -- Herbert Xu <herbert@debian.org>  Tue,  5 May 1998 18:01:02 +1000
++
++ash (0.3.4-3) frozen unstable; urgency=low
++
++  * Applied sparc patch (fixes #21562).
++
++ -- Herbert Xu <herbert@debian.org>  Fri,  1 May 1998 19:48:13 +1000
++
++ash (0.3.4-2) frozen unstable; urgency=low
++
++  * Fixed the incorrect trap fixes (fixes #20363).
++
++ -- Herbert Xu <herbert@debian.org>  Thu, 16 Apr 1998 21:07:10 +1000
++
++ash (0.3.4-1) unstable; urgency=low
++
++  * New upstream release.
++  * Reverted word splitting change in 0.3.2-1 since the fix was broken and
++    major work (the quote removal is done too quickly at the moment) is needed
++    to fix it properly.
++  * Fixed more trap noncompliance.
++
++ -- Herbert Xu <herbert@debian.org>  Thu, 19 Mar 1998 22:59:12 +1100
++
++ash (0.3.2-5) unstable; urgency=low
++
++  * Fixed a bug when doing pattern matching in parameter expansions.
++
++ -- Herbert Xu <herbert@debian.org>  Tue, 10 Mar 1998 21:25:40 +1100
++
++ash (0.3.2-4) unstable; urgency=low
++
++  * Allow ] to be quoted in bracket expressions (fixes #17533).
++  * Move dh_fixperms to second last spot (fixes #18267).
++  * Don't do field splitting in evalfor.
++
++ -- Herbert Xu <herbert@debian.org>  Tue, 17 Feb 1998 13:32:09 +1100
++
++ash (0.3.2-3) unstable; urgency=low
++
++  * Fixed stupid core dump.
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 11 Feb 1998 21:33:55 +1100
++
++ash (0.3.2-2) unstable; urgency=low
++
++  * Hack for special builtins (fixes #18055).
++  * Hack for command.
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 11 Feb 1998 21:19:46 +1100
++
++ash (0.3.2-1) unstable; urgency=low
++
++  * NetBSD-current version as of 19980209.
++  * Fixed a word splitting problem after parameter expansion thanks to Alexey
++    Marinichev.
++  * Converted to debhelper (fixes #14612, #15005).
++
++ -- Herbert Xu <herbert@debian.org>  Mon,  9 Feb 1998 16:53:48 +1100
++
++ash (0.3.1-20) unstable; urgency=low
++
++  * Fixed -e problem with eval.
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  7 Dec 1997 20:19:00 +1100
++
++ash (0.3.1-19) unstable; urgency=low
++
++  * Fixed -e problem with command substitution.
++
++ -- Herbert Xu <herbert@debian.org>  Sun,  7 Dec 1997 19:44:49 +1100
++
++ash (0.3.1-18) unstable; urgency=low
++
++  * Do not link with ncurses (#15485).
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 30 Nov 1997 12:00:11 +1100
++
++ash (0.3.1-17) unstable; urgency=low
++
++  * Set PATH like bash (#15238).
++
++ -- Herbert Xu <herbert@debian.org>  Wed, 26 Nov 1997 16:17:27 +1100
++
++ash (0.3.1-16) unstable; urgency=low
++
++  * Fixed incorrect assignment builtin code.
++
++ -- Herbert Xu <herbert@debian.org>  Mon, 24 Nov 1997 16:19:10 +1100
++
++ash (0.3.1-15) unstable; urgency=low
++
++  * hash now returns error codes (needed by the Linux kernel).
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 23 Nov 1997 21:37:08 +1100
++
++ash (0.3.1-14) unstable; urgency=low
++
++  * Disabled word-splitting for assignment builtins.
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 23 Nov 1997 12:45:15 +1100
++
++ash (0.3.1-13) unstable; urgency=low
++
++  * ! is now recognised even after &&/||.
++
++ -- Herbert Xu <herbert@debian.org>  Fri, 21 Nov 1997 22:09:05 +1100
++
++ash (0.3.1-12) unstable; urgency=low
++
++  * More fixes to the handling of SIGINT when forking.
++
++ -- Herbert Xu <herbert@debian.org>  Fri, 14 Nov 1997 15:14:32 +1100
++
++ash (0.3.1-11) unstable; urgency=low
++
++  * Ignore SIGINT when forking non-interactively.
++
++ -- Herbert Xu <herbert@debian.org>  Mon,  3 Nov 1997 12:00:02 +1100
++
++ash (0.3.1-10) unstable; urgency=low
++
++  * echo now handles options correctly.
++  * echo nolonger returns 0 if erorrs occured while writing to stdout.
++  * New code from GNU echo merged.
++  * Error messages from test now work.
++
++ -- Herbert Xu <herbert@debian.org>  Wed,  8 Oct 1997 21:47:13 +1000
++
++ash (0.3.1-9) unstable; urgency=low
++
++  * ! is recognised at pipeline level like bash.
++
++ -- Herbert Xu <herbert@debian.org>  Mon, 15 Sep 1997 23:13:45 +1000
++
++ash (0.3.1-8) unstable; urgency=medium
++
++  * Old patch regarding SIGCHLD in again.
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 31 Aug 1997 11:20:27 +1000
++
++ash (0.3.1-7) unstable; urgency=low
++
++  * /bin/sh -e is behaving even better now (for loops within conditionals).
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 23 Aug 1997 22:08:19 +1000
++
++ash (0.3.1-6) unstable; urgency=low
++
++  * /bin/sh -e is behaving better now.
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 23 Aug 1997 13:16:26 +1000
++
++ash (0.3.1-5) unstable; urgency=low
++
++  * hash -v /dir/command doesn't coredump anymore.
++  * type /dir/command now works correctly.
++
++ -- Herbert Xu <herbert@debian.org>  Fri,  1 Aug 1997 20:48:19 +1000
++
++ash (0.3.1-4) unstable; urgency=low
++
++  * trap now understands symbolic signal names.
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 26 Jul 1997 14:04:46 +1000
++
++ash (0.3.1-3) unstable; urgency=low
++
++  * Added the builtin test command.
++
++ -- Herbert Xu <herbert@debian.org>  Sun, 20 Jul 1997 15:00:14 +1000
++
++ash (0.3.1-2) unstable; urgency=medium
++
++  * Fixed a coredump involving $*.
++
++ -- Herbert Xu <herbert@debian.org>  Sat, 19 Jul 1997 12:03:02 +1000
++
++ash (0.3.1-1) unstable; urgency=medium
++
++  * NetBSD-current version as of 19970715.
++  * Fixed a "use after free" bug (#11294).
++
++ -- Herbert Xu <herbert@debian.org>  Fri, 18 Jul 1997 13:48:09 +1000
++
++ash (0.3-1) unstable; urgency=low
++
++  * Initial Release.
++
++ -- Herbert Xu <herbert@debian.org>  Thu, 19 Jun 1997 19:29:16 +1000
++
+diff -urN netbsd-sh/debian/control ash-0.3.7.orig/debian/control
+--- netbsd-sh/debian/control   Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/control      Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,69 @@
++Source: ash
++Section: shells
++Priority: optional
++Maintainer: Herbert Xu <herbert@debian.org>
++Build-Depends: byacc, debhelper, flex, pmake, groff
++Standards-Version: 3.2.1
++
++Package: ash
++Architecture: any
++Pre-Depends: ${shlibs:Depends}
++Description: NetBSD /bin/sh
++ "ash" is a POSIX compliant shell that is much smaller than "bash".
++ We take advantage of that by making it the shell on the installation
++ root floppy, where space is at a premium.
++ .
++ It can be usefully installed as /bin/sh (because it executes scripts
++ somewhat faster than "bash"), or as the default shell either of root
++ or of a second user with a userid of 0 (because it depends on fewer
++ libraries, and is therefore less likely to be affected by an upgrade
++ problem or a disk failure).  It is also useful for checking that a
++ script uses only POSIX syntax.
++ .
++ "bash" is a better shell for most users, since it has some nice
++ features absent from "ash", and is a required part of the system.
++
++Package: ash-medium
++Architecture: any
++Pre-Depends: ${shlibs:Depends}
++Priority: extra
++Description: NetBSD /bin/sh with HETIO
++ This is a slightly bigger version of the standard ash package with a
++ hack that provides primitive history support.  It may be useful on
++ boot floppies where space is at a premium, yet users still need the
++ ability to access previous commands in the same session.  If you're
++ not a boot floppies maintainer, you should probably go for ash,
++ ash.big (not yet available), or bash.
++ .
++ "ash" is a POSIX compliant shell that is much smaller than "bash".
++ We take advantage of that by making it the shell on the installation
++ root floppy, where space is at a premium.
++ .
++ It can be usefully installed as /bin/sh (because it executes scripts
++ somewhat faster than "bash"), or as the default shell either of root
++ or of a second user with a userid of 0 (because it depends on fewer
++ libraries, and is therefore less likely to be affected by an upgrade
++ problem or a disk failure).  It is also useful for checking that a
++ script uses only POSIX syntax.
++ .
++ "bash" is a better shell for most users, since it has some nice
++ features absent from "ash", and is a required part of the system.
++
++Package: ash-udeb
++Architecture: any
++Section: debian-installer
++Description: NetBSD /bin/sh for boot floppies
++ "ash" is a POSIX compliant shell that is much smaller than "bash".
++ We take advantage of that by making it the shell on the installation
++ root floppy, where space is at a premium.
++ .
++ It can be usefully installed as /bin/sh (because it executes scripts
++ somewhat faster than "bash"), or as the default shell either of root
++ or of a second user with a userid of 0 (because it depends on fewer
++ libraries, and is therefore less likely to be affected by an upgrade
++ problem or a disk failure).  It is also useful for checking that a
++ script uses only POSIX syntax.
++ .
++ "bash" is a better shell for most users, since it has some nice
++ features absent from "ash", and is a required part of the system.
++
+diff -urN netbsd-sh/debian/copyright ash-0.3.7.orig/debian/copyright
+--- netbsd-sh/debian/copyright Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/copyright    Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,18 @@
++This package was debianized by Mark W. Eichin eichin@kitten.gen.ma.us on
++Mon, 24 Feb 1997 16:00:16 -0500.
++
++This package was re-ported from NetBSD and debianized by
++Herbert Xu herbert@debian.org on Thu, 19 Jun 1997 19:29:16 +1000.
++
++It was downloaded from ftp.netbsd.org.
++
++Copyright:
++
++Copyright (c) 1991, 1993
++      The Regents of the University of California.  All rights reserved.
++
++This code is derived from software contributed to Berkeley by Kenneth Almquist.
++
++Please refer to /usr/share/common-licenses/BSD for details.
++
++$Id$
+diff -urN netbsd-sh/debian/dirs ash-0.3.7.orig/debian/dirs
+--- netbsd-sh/debian/dirs      Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/dirs Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,2 @@
++bin
++usr/share/man/man1
+diff -urN netbsd-sh/debian/rules ash-0.3.7.orig/debian/rules
+--- netbsd-sh/debian/rules     Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/debian/rules        Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,92 @@
++#!/usr/bin/make -f
++# $Id$
++
++# Uncomment this to turn on verbose mode.
++#export DH_VERBOSE=1
++CDEF = -g -O2 -Wall -DBSD=1 -DSMALL -D_GNU_SOURCE \
++       -DGLOB_BROKEN \
++       -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)=
++CDEFSM = -Os -fomit-frame-pointer -Wall -DBSD=1 -DSMALL -D_GNU_SOURCE \
++       -DGLOB_BROKEN \
++       -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)=
++
++sh.hetio:
++      chmod u+x debian/bsdyacc
++      rm -f *.o
++      pmake CFLAGS='$(CDEF)' HETIO= YACC=`pwd`/debian/bsdyacc
++      mv sh sh.hetio
++
++sh:
++      chmod u+x debian/bsdyacc
++      rm -f *.o
++      pmake CFLAGS='$(CDEF)' YACC=`pwd`/debian/bsdyacc
++
++sh.udeb:
++      chmod u+x debian/bsdyacc
++      rm -f *.o
++      pmake CFLAGS='$(CDEFSM)' YACC=`pwd`/debian/bsdyacc
++      mv sh sh.udeb
++
++build: build-stamp
++build-stamp: sh.hetio sh.udeb sh
++      dh_testdir
++
++      touch build-stamp
++
++clean:
++      dh_testdir
++      dh_testroot
++      rm -f build-stamp
++
++      pmake clean HETIO=
++      rm -f sh.cat1 mksignames signames.h sh.hetio sh.udeb
++
++      dh_clean
++
++# Build architecture-independent files here.
++binary-indep: build
++# We have nothing to do by default.
++
++# Build architecture-dependent files here.
++binary-arch: build
++#     dh_testversion
++      dh_testdir
++      dh_testroot
++      dh_clean -k
++      dh_installdirs
++
++      install sh debian/tmp/bin/ash
++      install -m 644 sh.1 debian/tmp/usr/share/man/man1/ash.1
++      install sh.hetio debian/ash-medium/usr/bin/ash.medium
++      install -m 644 sh.1 debian/ash-medium/usr/share/man/man1/ash.medium.1
++      install sh.udeb debian/ash-udeb/bin/ash
++      ln -s ash debian/ash-udeb/bin/sh
++
++      dh_installdocs -Nash-udeb
++      dh_installexamples
++      dh_installmenu
++#     dh_installinit
++      dh_installcron
++#     dh_installmanpages
++#     dh_undocumented
++      dh_installchangelogs -Nash-udeb
++      dh_strip
++      dh_compress
++      dh_fixperms
++      dh_suidregister
++      dh_installdeb -Nash-udeb
++      dh_shlibdeps
++      dh_gencontrol
++#     dh_makeshlibs
++      dh_md5sums
++      dh_builddeb
++      for i in ../ash-udeb_*.deb; do mv $$i $${i%deb}udeb; done
++      sed '/^[^ ]*\.udeb/d; s/^\(ash-udeb_[^ ]*\.\)deb/\1udeb/' \
++              debian/files > debian/files.new
++      mv debian/files.new debian/files
++
++source diff:                                                                  
++      @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
++
++binary: binary-indep binary-arch
++.PHONY: build clean binary-indep binary-arch binary
+
diff --git a/ash-echo.patch b/ash-echo.patch
new file mode 100644 (file)
index 0000000..89d9347
--- /dev/null
@@ -0,0 +1,91 @@
+diff -urN netbsd-sh/bltin/echo.c ash-0.3.7.orig/bltin/echo.c
+--- netbsd-sh/bltin/echo.c     Sun Nov  3 13:06:22 1996
++++ ash-0.3.7.orig/bltin/echo.c        Mon Apr 23 22:16:46 2001
+@@ -44,7 +44,13 @@
+ #define main echocmd
++#ifdef _GNU_SOURCE
++#include <stdio.h>
++
++#include "../mystring.h"
++#else
+ #include "bltin.h"
++#endif
+ /* #define eflag 1 */
+@@ -53,7 +59,6 @@
+       register char **ap;
+       register char *p;
+       register char c;
+-      int count;
+       int nflag = 0;
+ #ifndef eflag
+       int eflag = 0;
+@@ -62,21 +67,26 @@
+       ap = argv;
+       if (argc)
+               ap++;
+-      if ((p = *ap) != NULL) {
++      while ((p = *ap) != NULL && *p == '-') {
+               if (equal(p, "-n")) {
+-                      nflag++;
+-                      ap++;
++                      nflag = 1;
+               } else if (equal(p, "-e")) {
+ #ifndef eflag
+-                      eflag++;
++                      eflag = 1;
++#endif
++              } else if (equal(p, "-E")) {
++#ifndef eflag
++                      eflag = 0;
+ #endif
+-                      ap++;
+               }
++              else break;
++              ap++;
+       }
+       while ((p = *ap++) != NULL) {
+               while ((c = *p++) != '\0') {
+                       if (c == '\\' && eflag) {
+-                              switch (*p++) {
++                              switch (c = *p++) {
++                              case 'a':  c = '\007'; break;
+                               case 'b':  c = '\b';  break;
+                               case 'c':  return 0;            /* exit */
+                               case 'f':  c = '\f';  break;
+@@ -85,11 +95,13 @@
+                               case 't':  c = '\t';  break;
+                               case 'v':  c = '\v';  break;
+                               case '\\':  break;              /* c = '\\' */
+-                              case '0':
+-                                      c = 0;
+-                                      count = 3;
+-                                      while (--count >= 0 && (unsigned)(*p - '0') < 8)
+-                                              c = (c << 3) + (*p++ - '0');
++                              case '0': case '1': case '2': case '3':
++                              case '4': case '5': case '6': case '7':
++                                      c -= '0';
++                                      if (*p >= '0' && *p <= '7')
++                                              c = c * 8 + (*p++ - '0');
++                                      if (*p >= '0' && *p <= '7')
++                                      c = c * 8 + (*p++ - '0');
+                                       break;
+                               default:
+                                       p--;
+@@ -103,5 +115,12 @@
+       }
+       if (! nflag)
+               putchar('\n');
++#ifdef _GNU_SOURCE
++      fflush(stdout);
++      if (ferror(stdout)) {
++              clearerr(stdout);
++              return 1;
++      }
++#endif
+       return 0;
+ }
+
diff --git a/ash-freebsd.patch b/ash-freebsd.patch
new file mode 100644 (file)
index 0000000..b0b1144
--- /dev/null
@@ -0,0 +1,60 @@
+diff -ur ash-0.4.0/bltin/echo.c ash-0.4.0+free/bltin/echo.c
+--- ash-0.4.0/bltin/echo.c     Tue Apr 24 02:03:56 2001
++++ ash-0.4.0+free/bltin/echo.c        Tue Apr 24 01:43:15 2001
+@@ -89,6 +89,7 @@
+                               case 'a':  c = '\007'; break;
+                               case 'b':  c = '\b';  break;
+                               case 'c':  return 0;            /* exit */
++                              case 'e':  c = '\033';  break;
+                               case 'f':  c = '\f';  break;
+                               case 'n':  c = '\n';  break;
+                               case 'r':  c = '\r';  break;
+diff -ur ash-0.4.0/cd.c ash-0.4.0+free/cd.c
+--- ash-0.4.0/cd.c     Tue Apr 24 02:03:56 2001
++++ ash-0.4.0+free/cd.c        Tue Apr 24 01:43:57 2001
+@@ -244,6 +244,7 @@
+               curdir = NULL;
+               getpwd();
+               setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
++              setvar("OLDPWD", prevdir, VEXPORT|VTEXTFIXED);
+               INTON;
+               return;
+       }
+@@ -275,6 +276,7 @@
+       prevdir = curdir;
+       curdir = savestr(stackblock());
+       setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
++      setvar("OLDPWD", prevdir, VEXPORT|VTEXTFIXED);
+       INTON;
+ }
+diff -ur ash-0.4.0/main.c ash-0.4.0+free/main.c
+--- ash-0.4.0/main.c   Tue Apr 24 02:03:57 2001
++++ ash-0.4.0+free/main.c      Tue Apr 24 02:03:26 2001
+@@ -115,6 +115,9 @@
+       struct stackmark smark;
+       volatile int state;
+       char *shinit;
++      int priviliged;
++
++      priviliged = getuid() != geteuid() || getgid() != getegid();
+ #if PROFILE
+       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+@@ -188,11 +191,14 @@
+               read_profile("/etc/profile");
+ state1:
+               state = 2;
+-              read_profile(".profile");
++              if (priviliged == 0)
++                      read_profile(".profile");
++              else
++                      read_profile("/etc/suid_profile");
+       }
+ state2:
+       state = 3;
+-      if (getuid() == geteuid() && getgid() == getegid()) {
++      if (iflag && !priviliged) {
+               if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+                       state = 3;
+                       read_profile(shinit);
diff --git a/ash-getcwd.patch b/ash-getcwd.patch
new file mode 100644 (file)
index 0000000..f98f487
--- /dev/null
@@ -0,0 +1,13 @@
+diff -urN netbsd-sh/cd.c ash-0.3.7.orig/cd.c
+--- netbsd-sh/cd.c     Fri Jul  9 13:02:05 1999
++++ ash-0.3.7.orig/cd.c        Mon Apr 23 22:16:46 2001
+@@ -319,7 +319,7 @@
+        * c implementation of getcwd, that does not open a pipe to
+        * /bin/pwd.
+        */
+-#if defined(__NetBSD__) || defined(__SVR4)
++#if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__)
+               
+       if (getcwd(buf, sizeof(buf)) == NULL) {
+               char *pwd = getenv("PWD");
+
diff --git a/ash-getopt.patch b/ash-getopt.patch
new file mode 100644 (file)
index 0000000..df88ba0
--- /dev/null
@@ -0,0 +1,198 @@
+diff -urN netbsd-sh/options.c ash-0.3.7.orig/options.c
+--- netbsd-sh/options.c        Fri Jul  9 13:02:07 1999
++++ ash-0.3.7.orig/options.c   Mon Apr 23 22:16:46 2001
+@@ -79,7 +79,7 @@
+ STATIC void options __P((int));
+ STATIC void minus_o __P((char *, int));
+ STATIC void setoption __P((int, int));
+-STATIC int getopts __P((char *, char *, char **, char ***, char **));
++STATIC int getopts __P((char *, char *, char **, int *, int *));
+ /*
+@@ -118,7 +118,8 @@
+               arg0 = *argptr++;
+       shellparam.p = argptr;
+-      shellparam.reset = 1;
++      shellparam.optind = 1;
++      shellparam.optoff = -1;
+       /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+       while (*argptr) {
+               shellparam.nparam++;
+@@ -282,7 +283,8 @@
+       shellparam.malloc = 1;
+       shellparam.nparam = nparam;
+       shellparam.p = newparam;
+-      shellparam.optnext = NULL;
++      shellparam.optind = 1;
++      shellparam.optoff = -1;
+ }
+@@ -330,7 +332,8 @@
+       }
+       ap2 = shellparam.p;
+       while ((*ap2++ = *ap1++) != NULL);
+-      shellparam.optnext = NULL;
++      shellparam.optind = 1;
++      shellparam.optoff = -1;
+       INTON;
+       return 0;
+ }
+@@ -363,10 +366,8 @@
+ getoptsreset(value)
+       const char *value;
+ {
+-      if (number(value) == 1) {
+-              shellparam.optnext = NULL;
+-              shellparam.reset = 1;
+-      }
++      shellparam.optind = number(value);
++      shellparam.optoff = -1;
+ }
+ /*
+@@ -385,50 +386,58 @@
+       if (argc < 3)
+               error("Usage: getopts optstring var [arg]");
+-      else if (argc == 3)
++      else if (argc == 3) {
+               optbase = shellparam.p;
+-      else
++              if (shellparam.optind > shellparam.nparam + 1) {
++                      shellparam.optind = 1;
++                      shellparam.optoff = -1;
++              }
++      }
++      else {
+               optbase = &argv[3];
+-
+-      if (shellparam.reset == 1) {
+-              shellparam.optnext = optbase;
+-              shellparam.optptr = NULL;
+-              shellparam.reset = 0;
++              if (shellparam.optind > argc - 2) {
++                      shellparam.optind = 1;
++                      shellparam.optoff = -1;
++              }
+       }
+-      return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
+-                     &shellparam.optptr);
++      return getopts(argv[1], argv[2], optbase, &shellparam.optind,
++                     &shellparam.optoff);
+ }
+ STATIC int
+-getopts(optstr, optvar, optfirst, optnext, optpptr)
++getopts(optstr, optvar, optfirst, optind, optoff)
+       char *optstr;
+       char *optvar;
+       char **optfirst;
+-      char ***optnext;
+-      char **optpptr;
++      int *optind;
++      int *optoff;
+ {
+       char *p, *q;
+       char c = '?';
+       int done = 0;
+-      int ind = 0;
+       int err = 0;
+       char s[10];
++      char **optnext = optfirst + *optind - 1;
+-      if ((p = *optpptr) == NULL || *p == '\0') {
++      if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
++          strlen(*(optnext - 1)) < *optoff)
++              p = NULL;
++      else
++              p = *(optnext - 1) + *optoff;
++      if (p == NULL || *p == '\0') {
+               /* Current word is done, advance */
+-              if (*optnext == NULL)
++              if (optnext == NULL)
+                       return 1;
+-              p = **optnext;
++              p = *optnext;
+               if (p == NULL || *p != '-' || *++p == '\0') {
+ atend:
+-                      ind = *optnext - optfirst + 1;
+-                      *optnext = NULL;
++                      *optind = optnext - optfirst + 1;
+                       p = NULL;
+                       done = 1;
+                       goto out;
+               }
+-              (*optnext)++;
++              optnext++;
+               if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
+                       goto atend;
+       }
+@@ -453,7 +462,7 @@
+       }
+       if (*++q == ':') {
+-              if (*p == '\0' && (p = **optnext) == NULL) {
++              if (*p == '\0' && (p = *optnext) == NULL) {
+                       if (optstr[0] == ':') {
+                               s[0] = c;
+                               s[1] = '\0';
+@@ -468,30 +477,29 @@
+                       goto bad;
+               }
+-              if (p == **optnext)
+-                      (*optnext)++;
++              if (p == *optnext)
++                      optnext++;
+               setvarsafe("OPTARG", p, 0);
+               p = NULL;
+       }
+       else
+               setvarsafe("OPTARG", "", 0);
+-      ind = *optnext - optfirst + 1;
++      *optind = optnext - optfirst + 1;
+       goto out;
+ bad:
+-      ind = 1;
+-      *optnext = NULL;
++      *optind = 1;
+       p = NULL;
+ out:
+-      *optpptr = p;
+-      fmtstr(s, sizeof(s), "%d", ind);
++      *optoff = p ? p - *(optnext - 1) : -1;
++      fmtstr(s, sizeof(s), "%d", *optind);
+       err |= setvarsafe("OPTIND", s, VNOFUNC);
+       s[0] = c;
+       s[1] = '\0';
+       err |= setvarsafe(optvar, s, 0);
+       if (err) {
+-              *optnext = NULL;
+-              *optpptr = NULL;
++              *optind = 1;
++              *optoff = -1;
+               flushall();
+               exraise(EXERROR);
+       }
+diff -urN netbsd-sh/options.h ash-0.3.7.orig/options.h
+--- netbsd-sh/options.h        Fri Jul  9 13:02:07 1999
++++ ash-0.3.7.orig/options.h   Mon Apr 23 22:16:46 2001
+@@ -41,10 +41,9 @@
+ struct shparam {
+       int nparam;             /* # of positional parameters (without $0) */
+       unsigned char malloc;   /* if parameter list dynamically allocated */
+-      unsigned char reset;    /* if getopts has been reset */
+       char **p;               /* parameter list */
+-      char **optnext;         /* next parameter to be processed by getopts */
+-      char *optptr;           /* used by getopts */
++      int optind;             /* next parameter to be processed by getopts */
++      int optoff;             /* used by getopts */
+ };
+
diff --git a/ash-glob.patch b/ash-glob.patch
new file mode 100644 (file)
index 0000000..7001353
--- /dev/null
@@ -0,0 +1,445 @@
+diff -urN netbsd-sh/expand.c ash-0.3.7.orig/expand.c
+--- netbsd-sh/expand.c Tue Mar 14 13:03:45 2000
++++ ash-0.3.7.orig/expand.c    Mon Apr 23 22:16:46 2001
+@@ -54,6 +54,10 @@
+ #include <pwd.h>
+ #include <stdlib.h>
+ #include <stdio.h>
++#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
++#include <fnmatch.h>
++#include <glob.h>
++#endif
+ /*
+  * Routines to expand arguments to commands.  We have to deal with
+@@ -102,17 +106,30 @@
+ STATIC int subevalvar __P((char *, char *, int, int, int, int));
+ STATIC char *evalvar __P((char *, int));
+ STATIC int varisset __P((char *, int));
++STATIC char *strtodest __P((char *, int, int));
+ STATIC void varvalue __P((char *, int, int));
+ STATIC void recordregion __P((int, int, int));
+ STATIC void removerecordregions __P((int)); 
+ STATIC void ifsbreakup __P((char *, struct arglist *));
+ STATIC void ifsfree __P((void));
+ STATIC void expandmeta __P((struct strlist *, int));
++#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
++STATIC const char *preglob __P((const char *));
++STATIC void addglob __P((const glob_t *));
++#else
+ STATIC void expmeta __P((char *, char *));
++#endif
+ STATIC void addfname __P((char *));
++#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
++STATIC int patmatch __P((char *, char *, int));
++STATIC int patmatch2 __P((char *, char *, int));
++STATIC char * _rmescapes __P((char *, int));
++#else
+ STATIC struct strlist *expsort __P((struct strlist *));
+ STATIC struct strlist *msort __P((struct strlist *, int));
+ STATIC int pmatch __P((char *, char *, int));
++#define patmatch2 patmatch
++#endif
+ STATIC char *cvtnum __P((int, char *));
+ /*
+@@ -371,7 +388,7 @@
+        * have to rescan starting from the beginning since CTLESC
+        * characters have to be processed left to right.
+        */
+-      CHECKSTRSPACE(8, expdest);
++      CHECKSTRSPACE(10, expdest);
+       USTPUTC('\0', expdest);
+       start = stackblock();
+       p = expdest - 1;
+@@ -393,7 +410,7 @@
+       if (quotes)
+               rmescapes(p+2);
+       result = arith(p+2);
+-      fmtstr(p, 10, "%d", result);
++      fmtstr(p, 12, "%d", result);
+       while (*p++)
+               ;
+@@ -503,7 +520,7 @@
+       int amount;
+       herefd = -1;
+-      argstr(p, 0);
++      argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
+       STACKSTRNUL(expdest);
+       herefd = saveherefd;
+       argbackq = saveargbackq;
+@@ -535,7 +552,7 @@
+               for (loc = startp; loc < str; loc++) {
+                       c = *loc;
+                       *loc = '\0';
+-                      if (patmatch(str, startp, varflags & VSQUOTE))
++                      if (patmatch2(str, startp, varflags & VSQUOTE))
+                               goto recordleft;
+                       *loc = c;
+                       if ((varflags & VSQUOTE) && *loc == CTLESC)
+@@ -547,7 +564,7 @@
+               for (loc = str - 1; loc >= startp;) {
+                       c = *loc;
+                       *loc = '\0';
+-                      if (patmatch(str, startp, varflags & VSQUOTE))
++                      if (patmatch2(str, startp, varflags & VSQUOTE))
+                               goto recordleft;
+                       *loc = c;
+                       loc--;
+@@ -564,7 +581,7 @@
+       case VSTRIMRIGHT:
+               for (loc = str - 1; loc >= startp;) {
+-                      if (patmatch(str, loc, varflags & VSQUOTE))
++                      if (patmatch2(str, loc, varflags & VSQUOTE))
+                               goto recordright;
+                       loc--;
+                       if ((varflags & VSQUOTE) && loc > startp &&
+@@ -580,7 +597,7 @@
+       case VSTRIMRIGHTMAX:
+               for (loc = startp; loc < str - 1; loc++) {
+-                      if (patmatch(str, loc, varflags & VSQUOTE))
++                      if (patmatch2(str, loc, varflags & VSQUOTE))
+                               goto recordright;
+                       if ((varflags & VSQUOTE) && *loc == CTLESC)
+                               loc++;
+@@ -819,6 +836,34 @@
+ /*
++ * Put a string on the stack.
++ */
++
++STATIC char *
++strtodest(p, quoted, allow_split)
++      char *p;
++      int quoted;
++      int allow_split;
++{
++      char const *syntax;
++
++      if (allow_split) {
++              syntax = quoted ? DQSYNTAX : BASESYNTAX;
++              while (*p) {
++                      if (syntax[(int) *p] == CCTL)
++                              STPUTC(CTLESC, expdest);
++                      STPUTC(*p++, expdest);
++              }
++      } else
++              while (*p)
++                      STPUTC(*p++, expdest);
++
++      return p;
++}
++
++
++
++/*
+  * Add the value of a specialized variable to the stack string.
+  */
+@@ -834,22 +879,6 @@
+       extern int oexitstatus;
+       char sep;
+       char **ap;
+-      char const *syntax;
+-
+-#define STRTODEST(p) \
+-      do {\
+-      if (allow_split) { \
+-              syntax = quoted? DQSYNTAX : BASESYNTAX; \
+-              while (*p) { \
+-                      if (syntax[(int)*p] == CCTL) \
+-                              STPUTC(CTLESC, expdest); \
+-                      STPUTC(*p++, expdest); \
+-              } \
+-      } else \
+-              while (*p) \
+-                      STPUTC(*p++, expdest); \
+-      } while (0)
+-
+       switch (*name) {
+       case '$':
+@@ -875,7 +904,7 @@
+       case '@':
+               if (allow_split && quoted) {
+                       for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+-                              STRTODEST(p);
++                              p = strtodest(p, quoted, allow_split);
+                               if (*ap)
+                                       STPUTC('\0', expdest);
+                       }
+@@ -888,21 +917,20 @@
+               else
+                       sep = ' ';
+               for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+-                      STRTODEST(p);
++                      p = strtodest(p, quoted, allow_split);
+                       if (*ap && sep)
+                               STPUTC(sep, expdest);
+               }
+               break;
+       case '0':
+-              p = arg0;
+-              STRTODEST(p);
++              p = strtodest(arg0, quoted, allow_split);
+               break;
+       default:
+               if (is_digit(*name)) {
+                       num = atoi(name);
+                       if (num > 0 && num <= shellparam.nparam) {
+-                              p = shellparam.p[num - 1];
+-                              STRTODEST(p);
++                              p = strtodest(shellparam.p[num - 1], quoted,
++                                            allow_split);
+                       }
+               }
+               break;
+@@ -1054,6 +1082,98 @@
+  * should be escapes.  The results are stored in the list exparg.
+  */
++#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
++STATIC void
++expandmeta(str, flag)
++      struct strlist *str;
++      int flag;
++{
++      const char *p;
++      glob_t pglob;
++      /* TODO - EXP_REDIR */
++
++      while (str) {
++              if (fflag)
++                      goto nometa;
++              p = preglob(str->text);
++              INTOFF;
++              switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
++              case 0:
++                      if (!(pglob.gl_flags & GLOB_MAGCHAR))
++                              goto nometa2;
++                      addglob(&pglob);
++                      globfree(&pglob);
++                      INTON;
++                      break;
++              case GLOB_NOMATCH:
++nometa2:
++                      globfree(&pglob);
++                      INTON;
++nometa:
++                      *exparg.lastp = str;
++                      rmescapes(str->text);
++                      exparg.lastp = &str->next;
++                      break;
++              default:        /* GLOB_NOSPACE */
++                      error("Out of space");
++              }
++              str = str->next;
++      }
++}
++
++
++/*
++ * Prepare the string for glob(3).
++ */
++
++STATIC const char *
++preglob(str)
++      const char *str;
++{
++      const char *p;
++      char *q, *r;
++      size_t len;
++
++      p = str;
++      while (*p != CTLQUOTEMARK && *p != CTLESC) {
++              if (*p++ == '\0')
++                      return str;
++      }
++      len = p - str;
++      q = r = stalloc(strlen(str) + 1);
++      if (len > 0) {
++              memcpy(q, str, len);
++              q += len;
++      }
++      do {
++              if (*p == CTLQUOTEMARK)
++                      continue;
++              if (*p == CTLESC) {
++                      if (*++p != '/')
++                              *q++ = '\\';
++              }
++              *q++ = *p;
++      } while (*++p);
++      *q = '\0';
++      return r;
++}
++
++
++/*
++ * Add the result of glob(3) to the list.
++ */
++
++STATIC void
++addglob(pglob)
++      const glob_t *pglob;
++{
++      char **p = pglob->gl_pathv;
++
++      do {
++              addfname(*p);
++      } while (*++p);
++}
++#else
+ char *expdir;
+@@ -1238,6 +1358,7 @@
+       if (! atend)
+               endname[-1] = '/';
+ }
++#endif
+ /*
+@@ -1260,6 +1381,7 @@
+ }
++#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN))
+ /*
+  * Sort the results of file name expansion.  It calculates the number of
+  * strings to sort and then calls msort (short for merge sort) to do the
+@@ -1321,6 +1443,7 @@
+       }
+       return list;
+ }
++#endif
+@@ -1328,6 +1451,39 @@
+  * Returns true if the pattern matches the string.
+  */
++#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
++STATIC int
++patmatch(pattern, string, squoted)
++      char *pattern;
++      char *string;
++      int squoted;    /* string might have quote chars */
++      {
++      const char *p;
++      char *q;
++
++      p = preglob(pattern);
++      q = squoted ? _rmescapes(string, 1) : string;
++
++      return !fnmatch(p, q, 0);
++}
++
++
++STATIC int
++patmatch2(pattern, string, squoted)
++      char *pattern;
++      char *string;
++      int squoted;    /* string might have quote chars */
++      {
++      char *p;
++      int res;
++
++      sstrnleft--;
++      p = grabstackstr(expdest);
++      res = patmatch(pattern, string, squoted);
++      ungrabstackstr(p, expdest);
++      return res;
++}
++#else
+ int
+ patmatch(pattern, string, squoted)
+       char *pattern;
+@@ -1462,6 +1618,7 @@
+               return 0;
+       return 1;
+ }
++#endif
+@@ -1469,6 +1626,50 @@
+  * Remove any CTLESC characters from a string.
+  */
++#if defined(__GLIBC__) && !defined(GLOB_BROKEN)
++void
++rmescapes(str)
++      char *str;
++{
++      _rmescapes(str, 0);
++}
++
++
++STATIC char *
++_rmescapes(str, flag)
++      char *str;
++      int flag;
++{
++      char *p, *q, *r;
++
++      p = str;
++      while (*p != CTLESC && *p != CTLQUOTEMARK) {
++              if (*p++ == '\0')
++                      return str;
++      }
++      q = p;
++      r = str;
++      if (flag) {
++              size_t len = p - str;
++              q = r = stalloc(strlen(p) + len + 1);
++              if (len > 0) {
++                      memcpy(q, str, len);
++                      q += len;
++              }
++      }
++      while (*p) {
++              if (*p == CTLQUOTEMARK) {
++                      p++;
++                      continue;
++              }
++              if (*p == CTLESC)
++                      p++;
++              *q++ = *p++;
++      }
++      *q = '\0';
++      return r;
++}
++#else
+ void
+ rmescapes(str)
+       char *str;
+@@ -1492,6 +1693,7 @@
+       }
+       *q = '\0';
+ }
++#endif
+
+diff -urN netbsd-sh/expand.h ash-0.3.7.orig/expand.h
+--- netbsd-sh/expand.h Fri Jul  9 13:02:06 1999
++++ ash-0.3.7.orig/expand.h    Mon Apr 23 22:16:46 2001
+@@ -64,7 +64,9 @@
+ void expandhere __P((union node *, int));
+ void expandarg __P((union node *, struct arglist *, int));
+ void expari __P((int));
++#if !(defined(__GLIBC__) && !defined(GLOB_BROKEN))
+ int patmatch __P((char *, char *, int));
++#endif
+ void rmescapes __P((char *));
+ int casematch __P((union node *, char *));
diff --git a/ash-hetio.patch b/ash-hetio.patch
new file mode 100644 (file)
index 0000000..c416cde
--- /dev/null
@@ -0,0 +1,559 @@
+diff -urN ash-0.4.0/Makefile ash-0.4.0-/Makefile
+--- ash-0.4.0/Makefile Tue Apr 24 00:57:33 2001
++++ ash-0.4.0-/Makefile        Tue Apr 24 00:59:53 2001
+@@ -7,7 +7,7 @@
+ SHSRCS=       alias.c cd.c echo.c error.c eval.c exec.c expand.c \
+       histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
+       mystring.c options.c parser.c redir.c show.c trap.c output.c var.c \
+-      test.c setmode.c test.c
++      test.c setmode.c test.c hetio.c
+ GENSRCS=builtins.c builtins.h init.c nodes.c arith.c arith.h lex.yy.c \
+       nodes.h syntax.c syntax.h token.h signames.c
+ SRCS= ${SHSRCS} ${GENSRCS}
+@@ -17,12 +17,13 @@
+       mystring.o options.o output.o parser.o redir.o show.o \
+       trap.o var.o bltin/test.o signames.o \
+       builtins.o init.o nodes.o syntax.o arith.o lex.yy.o \
+-      setmode.o bltin/times.o
++      setmode.o bltin/times.o hetio.o
+ OPT_FLAGS=-O2 -g
+ LDFLAGS=-g
+ CFLAGS=$(OPT_FLAGS) -DSHELL -I. -DNO_HISTORY -DBSD=1 -DSMALL -D_GNU_SOURCE \
+-      -DGLOB_BROKEN -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)=
++      -DGLOB_BROKEN -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= \
++      -DHETIO
+ all: $(PROG)
+diff -urN ash-0.4.0/hetio.c ash-0.4.0-/hetio.c
+--- ash-0.4.0/hetio.c  Thu Jan  1 01:00:00 1970
++++ ash-0.4.0-/hetio.c Tue Apr 24 01:06:59 2001
+@@ -0,0 +1,377 @@
++/*
++ * Termios command line History and Editting for NetBSD sh (ash)
++ * Copyright (c) 1999
++ *    Main code:      Adam Rogoyski <rogoyski@cs.utexas.edu> 
++ *    Etc:            Dave Cinege <dcinege@psychosis.com>
++ *
++ * You may use this code as you wish, so long as the original author(s)
++ * are attributed in any redistributions of the source code.
++ * This code is 'as is' with no warranty.
++ * This code may safely be consumed by a BSD or GPL license.
++ *
++ * v 0.5  19990328    Initial release 
++ *
++ * Future plans: Simple file and path name completion. (like BASH)
++ *
++ */
++
++/*
++Usage and Known bugs:
++      Terminal key codes are not extensive, and more will probably
++      need to be added. This version was created on Debian GNU/Linux 2.x.
++      Delete, Backspace, Home, End, and the arrow keys were tested
++      to work in an Xterm and console. Ctrl-A also works as Home.
++      Ctrl-E also works as End. The binary size increase is <3K.
++      
++      Editting will not display correctly for lines greater then the 
++      terminal width. (more then one line.) However, history will.
++*/
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <termios.h>
++#include <ctype.h>
++#include <sys/ioctl.h>
++
++#include "input.h"
++#include "output.h"
++
++#ifdef HETIO
++
++#include "hetio.h"
++
++   
++#define  MAX_HISTORY   15                     /* Maximum length of the linked list for the command line history */
++
++#define ESC   27
++#define DEL   127
++
++static struct history *his_front = NULL;      /* First element in command line list */
++static struct history *his_end = NULL;                /* Last element in command line list */
++static struct termios old_term, new_term;     /* Current termio and the previous termio before starting ash */
++
++static int history_counter = 0;                       /* Number of commands in history list */
++static int reset_term = 0;                    /* Set to true if the terminal needs to be reset upon exit */
++static int hetio_inter = 0;
++
++struct history
++{
++   char *s;
++   struct history *p;
++   struct history *n;
++};
++
++
++void input_delete    (int);
++void input_home      (int *);
++void input_end       (int *, int);
++void input_backspace (int *, int *);
++
++
++
++void hetio_init(void)
++{
++      hetio_inter = 1;
++}
++
++
++void hetio_reset_term(void)
++{
++      if (reset_term)
++              tcsetattr(1, TCSANOW, &old_term);
++}
++
++
++void setIO(struct termios *new, struct termios *old)  /* Set terminal IO to canonical mode, and save old term settings. */
++{
++      tcgetattr(0, old);
++      memcpy(new, old, sizeof(*new));
++      new->c_cc[VMIN] = 1;
++      new->c_cc[VTIME] = 0;
++      new->c_lflag &= ~ICANON; /* unbuffered input */
++      new->c_lflag &= ~ECHO;
++      tcsetattr(0, TCSANOW, new);
++}
++
++void input_home(int *cursor)                          /* Command line input routines */
++{
++      while (*cursor > 0) {
++              out1c('\b');
++              --*cursor;
++      }
++      flushout(&output);
++}
++
++
++void input_delete(int cursor)
++{
++      int j = 0;
++
++      memmove(parsenextc + cursor, parsenextc + cursor + 1,
++              BUFSIZ - cursor - 1);
++      for (j = cursor; j < (BUFSIZ - 1); j++) {
++              if (!*(parsenextc + j))
++                      break;
++              else
++                      out1c(*(parsenextc + j));
++      }
++
++      out1str(" \b");
++      
++      while (j-- > cursor)
++              out1c('\b');
++      flushout(&output);
++}
++
++
++void input_end(int *cursor, int len)
++{
++      while (*cursor < len) {
++              out1str("\033[C");
++              ++*cursor;
++      }
++      flushout(&output);
++}
++
++
++void
++input_backspace(int *cursor, int *len)
++{
++      int j = 0;
++
++      if (*cursor > 0) {
++              out1str("\b \b");
++              --*cursor;
++              memmove(parsenextc + *cursor, parsenextc + *cursor + 1, 
++                      BUFSIZ - *cursor + 1);
++              
++              for (j = *cursor; j < (BUFSIZ - 1); j++) {
++                      if (!*(parsenextc + j))
++                              break;
++                      else
++                              out1c(*(parsenextc + j));
++              }
++              
++              out1str(" \b");
++              
++              while (j-- > *cursor)
++                      out1c('\b');
++              
++              --*len;
++              flushout(&output);
++      }
++}
++
++int hetio_read_input(int fd)
++{
++      int nr = 0;
++
++      if (!hetio_inter) {             /* Are we an interactive shell? */
++              return -255;            
++      } else {
++              int len = 0;
++              int j = 0;
++              int cursor = 0;
++              int break_out = 0;
++              int ret = 0;
++              char c = 0;
++              struct history *hp = his_end;
++
++              if (!reset_term) {
++                      setIO(&new_term, &old_term);
++                      reset_term = 1;
++              } else {
++                      tcsetattr(0, TCSANOW, &new_term);
++              }
++              
++              memset(parsenextc, 0, BUFSIZ);
++              
++              while (1) {
++                      if ((ret = read(fd, &c, 1)) < 1)
++                              return ret;
++                      
++                      switch (c) {
++                              case 1:         /* Control-A Beginning of line */
++                                      input_home(&cursor);
++                                      break;
++                              case 5:         /* Control-E EOL */
++                                      input_end(&cursor, len);
++                                      break;
++                              case 4:         /* Control-D */
++#ifndef CTRL_D_DELETE
++                                      return 0;
++#else
++                                      if (cursor != len) {
++                                              input_delete(cursor);
++                                              len--;
++                                      }
++                                      break;
++#endif
++                              case '\b':      /* Backspace */
++                              case DEL:
++                                      input_backspace(&cursor, &len);
++                                      break;
++                              case '\n':      /* Enter */
++                                      *(parsenextc + len++ + 1) = c;
++                                      out1c(c);
++                                      flushout(&output);
++                                      break_out = 1;
++                                      break;
++                              case ESC:       /* escape sequence follows */
++                                      if ((ret = read(fd, &c, 1)) < 1)
++                                              return ret;
++                                                                              
++                                      if (c == '[' || c == 'O' ) {    /* 91 */
++                                              if ((ret = read(fd, &c, 1)) < 1)
++                                                      return ret;
++                                              
++                                              switch (c) {
++                                                      case 'A':
++                                                              if (hp && hp->p) {              /* Up */
++                                                                      hp = hp->p;
++                                                                      goto hop;
++                                                              }
++                                                              break;
++                                                      case 'B':
++                                                              if (hp && hp->n && hp->n->s) {  /* Down */
++                                                                      hp = hp->n;
++                                                                      goto hop;
++                                                              }
++                                                              break;
++
++hop:                                          /* hop */                                                       
++                                                              len = strlen(parsenextc);
++
++                                                              for (; cursor > 0; cursor--)            /* return to begining of line */
++                                                                      out1c('\b');
++
++                                                              for (j = 0; j < len; j++)               /* erase old command */
++                                                                      out1c(' ');
++
++                                                              for (j = len; j > 0; j--)               /* return to begining of line */
++                                                                      out1c('\b');
++
++                                                              strcpy (parsenextc, hp->s);             /* write new command */
++                                                              len = strlen (hp->s);
++                                                              out1str(parsenextc);
++                                                              flushout(&output);
++                                                              cursor = len;
++                                                              break;
++                                                      case 'C':               /* Right */
++                                                                      if (cursor < len) {
++                                                                      out1str("\033[C");
++                                                                      cursor++;
++                                                                      flushout(&output);
++                                                              }
++                                                              break;
++                                                      case 'D':               /* Left */
++                                                              if (cursor > 0) {
++                                                                      out1str("\033[D");
++                                                                      cursor--;
++                                                                      flushout(&output);
++                                                              }
++                                                              break;
++                                                      case '3':               /* Delete */
++                                                              if (cursor != len) {
++                                                                      input_delete(cursor);
++                                                                      len--;
++                                                              }
++                                                              break;                                                          
++                                                      case 'H':               /* Home (xterm) */
++                                                      case '1':               /* Home (Ctrl-A) */
++                                                                      input_home(&cursor);
++                                                              break;
++                                                      case 'F':               /* End (xterm_ */
++                                                      case '4':               /* End (Ctrl-E) */
++                                                              input_end(&cursor, len);
++                                                              break;
++                                              }
++                                              if (c == '1' || c == '3' || c == '4')
++                                                      if ((ret = read(fd, &c, 1)) < 1)
++                                                              return ret;  /* read 126 (~) */
++                                      }
++                      
++                                      c = 0;
++                                      break;
++              
++                              default:                                /* If it's regular input, do the normal thing */
++             
++                                      if (!isprint(c))                /* Skip non-printable characters */
++                                              break;
++                                                             
++                                      if (len >= (BUFSIZ - 2))        /* Need to leave space for enter */
++                                              break;
++                      
++                                      len++;
++                      
++                                      if (cursor == (len - 1)) {      /* Append if at the end of the line */
++                                              *(parsenextc + cursor) = c;
++                                      } else {                        /* Insert otherwise */
++                                              memmove(parsenextc + cursor + 1, parsenextc + cursor,
++                                                      len - cursor - 1);
++                                      
++                                              *(parsenextc + cursor) = c;
++                      
++                                              for (j = cursor; j < len; j++)
++                                                      out1c(*(parsenextc + j));
++                                              for (; j > cursor; j--)
++                                                      out1str("\033[D");
++                                      }
++              
++                                      cursor++;
++                                      out1c(c);
++                                      flushout(&output);
++                                      break;
++                      }
++                      
++                      if (break_out)          /* Enter is the command terminator, no more input. */
++                              break;
++              }
++      
++              nr = len + 1;
++              tcsetattr(0, TCSANOW, &old_term);
++              
++              
++              if (*(parsenextc)) {            /* Handle command history log */
++                      struct history *h = his_end;
++  
++                      if (!h) {       /* No previous history */
++                              h = his_front = malloc(sizeof (struct history));
++                              h->n = malloc(sizeof (struct history));
++                              h->p = NULL;
++                              h->s = strdup(parsenextc);
++
++                              h->n->p = h;
++                              h->n->n = NULL;
++                              h->n->s = NULL;
++                              his_end = h->n;
++                              history_counter++;
++                      } else {        /* Add a new history command */
++  
++                              h->n = malloc(sizeof (struct history)); 
++
++                              h->n->p = h;
++                              h->n->n = NULL;
++                              h->n->s = NULL;
++                              h->s = strdup(parsenextc);
++                              his_end = h->n;
++
++                              if (history_counter >= MAX_HISTORY) {   /* After max history, remove the last known command */
++                                      struct history *p = his_front->n;
++                                      
++                                      p->p = NULL;
++                                      free(his_front->s);
++                                      free(his_front);
++                                      his_front = p;
++                              } else {
++                                      history_counter++;
++                              }
++                      }
++              }
++      } 
++
++      return nr;
++}
++#endif
+diff -urN ash-0.4.0/hetio.h ash-0.4.0-/hetio.h
+--- ash-0.4.0/hetio.h  Thu Jan  1 01:00:00 1970
++++ ash-0.4.0-/hetio.h Tue Apr 24 00:13:57 2001
+@@ -0,0 +1,22 @@
++/*
++ * Termios command line History and Editting for NetBSD sh (ash)
++ * Copyright (c) 1999
++ *    Main code:      Adam Rogoyski <rogoyski@cs.utexas.edu> 
++ *    Etc:            Dave Cinege <dcinege@psychosis.com>
++ *
++ * You may use this code as you wish, so long as the original author(s)
++ * are attributed in any redistributions of the source code.
++ * This code is 'as is' with no warranty.
++ * This code may safely be consumed by a BSD or GPL license.
++ *
++ * v 0.5  19990328    Initial release 
++ *
++ * Future plans: Simple file and path name completion. (like BASH)
++ *
++ */
++
++void hetio_init(void);
++int hetio_read_input(int fd);
++void hetio_reset_term(void);
++
++extern int hetio_inter;
+diff -urN ash-0.4.0/histedit.c ash-0.4.0-/histedit.c
+--- ash-0.4.0/histedit.c       Fri Jan 12 17:50:35 2001
++++ ash-0.4.0-/histedit.c      Tue Apr 24 00:13:57 2001
+@@ -60,9 +60,9 @@
+ #include "main.h"
+ #include "output.h"
+ #include "mystring.h"
+-#include "myhistedit.h"
+ #include "error.h"
+ #ifndef SMALL
++#include "myhistedit.h"
+ #include "eval.h"
+ #include "memalloc.h"
+@@ -219,7 +219,11 @@
+       if (argc == 1)
+               error("missing history argument");
++#ifdef __GLIBC__
++      optind = 1;
++#else
+       optreset = 1; optind = 1; /* initialize getopt */
++#endif
+       while (not_fcnumber(argv[optind]) &&
+             (ch = getopt(argc, argv, ":e:lnrs")) != -1)
+               switch ((char)ch) {
+diff -urN ash-0.4.0/input.c ash-0.4.0-/input.c
+--- ash-0.4.0/input.c  Tue May 23 12:03:19 2000
++++ ash-0.4.0-/input.c Tue Apr 24 00:13:57 2001
+@@ -66,7 +66,13 @@
+ #include "error.h"
+ #include "alias.h"
+ #include "parser.h"
++#ifndef SMALL
+ #include "myhistedit.h"
++#endif
++
++#ifdef HETIO
++#include "hetio.h"
++#endif
+ #define EOF_NLEFT -99         /* value of parsenleft when EOF pushed back */
+@@ -108,7 +114,9 @@
+ int init_editline = 0;                /* editline library initialized? */
+ int whichprompt;              /* 1 == PS1, 2 == PS2 */
++#ifndef SMALL
+ EditLine *el;                 /* cookie for editline package */
++#endif
+ STATIC void pushfile __P((void));
+ static int preadfd __P((void));
+@@ -197,6 +205,11 @@
+                       (void) strcpy(buf, rl_cp);
+               }
+       } else
++#endif
++
++#ifdef HETIO
++              nr = hetio_read_input(parsefile->fd);
++              if (nr == -255)
+ #endif
+               nr = read(parsefile->fd, buf, BUFSIZ - 1);
+diff -urN ash-0.4.0/main.c ash-0.4.0-/main.c
+--- ash-0.4.0/main.c   Tue Apr 24 00:57:33 2001
++++ ash-0.4.0-/main.c  Tue Apr 24 00:13:57 2001
+@@ -79,6 +79,10 @@
+ #include "exec.h"
+ #include "cd.h"
++#ifdef HETIO
++#include "hetio.h"
++#endif
++
+ #define PROFILE 0
+ int rootpid;
+@@ -242,6 +246,10 @@
+       TRACE(("cmdloop(%d) called\n", top));
+       setstackmark(&smark);
++#ifdef HETIO
++      if(iflag && top)
++              hetio_init();
++#endif
+       for (;;) {
+               if (pendingsigs)
+                       dotrap();
+Binary files ash-0.4.0/mksignames and ash-0.4.0-/mksignames differ
+diff -urN ash-0.4.0/trap.c ash-0.4.0-/trap.c
+--- ash-0.4.0/trap.c   Tue Apr 24 00:57:33 2001
++++ ash-0.4.0-/trap.c  Tue Apr 24 00:13:57 2001
+@@ -62,7 +62,11 @@
+ #include "error.h"
+ #include "trap.h"
+ #include "mystring.h"
++#include "mail.h"
++#ifdef HETIO
++#include "hetio.h"
++#endif
+ /*
+  * Sigmode records the current value of the signal handlers for the various
+@@ -341,6 +345,7 @@
+       setsignal(SIGINT);
+       setsignal(SIGQUIT);
+       setsignal(SIGTERM);
++      chkmail(1);
+       is_interactive = on;
+ }
+@@ -358,6 +363,9 @@
+       char *p;
+       TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
++#ifdef HETIO
++      hetio_reset_term();
++#endif
+       if (setjmp(loc1.loc)) {
+               goto l1;
+       }
diff --git a/ash-jobs.patch b/ash-jobs.patch
new file mode 100644 (file)
index 0000000..9e89118
--- /dev/null
@@ -0,0 +1,108 @@
+diff -ur netbsd-sh/jobs.c netbsd-sh-/jobs.c
+--- netbsd-sh/jobs.c   Tue May 23 12:03:19 2000
++++ netbsd-sh-/jobs.c  Mon Apr 23 23:31:47 2001
+@@ -92,6 +92,7 @@
+ int initialpgrp;              /* pgrp of shell on invocation */
+ short curjob;                 /* current job */
+ #endif
++STATIC int intreceived;
+ STATIC void restartjob __P((struct job *));
+ STATIC void freejob __P((struct job *));
+@@ -101,8 +102,10 @@
+ STATIC int waitproc __P((int, int *));
+ STATIC void cmdtxt __P((union node *));
+ STATIC void cmdputs __P((const char *));
++STATIC void waitonint(int);
++#if JOBS
+ /*
+  * Turn job control on and off.
+  *
+@@ -171,6 +174,7 @@
+       }
+       jobctl = on;
+ }
++#endif
+ #ifdef mkinit
+@@ -594,9 +598,6 @@
+               TRACE(("Child shell %d\n", getpid()));
+               wasroot = rootshell;
+               rootshell = 0;
+-              for (i = njobs, p = jobtab ; --i >= 0 ; p++)
+-                      if (p->used)
+-                              freejob(p);
+               closescript();
+               INTON;
+               clear_traps();
+@@ -642,6 +643,9 @@
+                       }
+               }
+ #endif
++              for (i = njobs, p = jobtab ; --i >= 0 ; p++)
++                      if (p->used)
++                              freejob(p);
+               if (wasroot && iflag) {
+                       setsignal(SIGINT);
+                       setsignal(SIGQUIT);
+@@ -701,13 +705,33 @@
+ #endif
+       int status;
+       int st;
++      struct sigaction act, oact;
+       INTOFF;
++      intreceived = 0;
++#if JOBS
++      if (!jobctl) {
++#else
++      if (!iflag) {
++#endif
++              sigaction(SIGINT, 0, &act);
++              act.sa_handler = waitonint;
++              sigaction(SIGINT, &act, &oact);
++      }
+       TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
+       while (jp->state == 0) {
+               dowait(1, jp);
+       }
+ #if JOBS
++      if (!jobctl) {
++#else
++      if (!iflag) {
++#endif
++              extern char *trap[];
++              sigaction(SIGINT, &oact, 0);
++              if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
++      }
++#if JOBS
+       if (jp->jobctl) {
+ #ifdef OLD_TTY_DRIVER
+               if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
+@@ -896,10 +920,10 @@
+ #ifdef BSD
+       int flags;
+-#if JOBS
+-      flags = WUNTRACED;
+-#else
+       flags = 0;
++#if JOBS
++      if (jobctl)
++              flags |= WUNTRACED;
+ #endif
+       if (block == 0)
+               flags |= WNOHANG;
+@@ -1139,4 +1163,9 @@
+               }
+       }
+       cmdnextc = q;
++}
++
++STATIC void waitonint(int sig) {
++      intreceived = 1;
++      return;
+ }
diff --git a/ash-kill.patch b/ash-kill.patch
new file mode 100644 (file)
index 0000000..f2972d9
--- /dev/null
@@ -0,0 +1,675 @@
+diff -urN netbsd-sh/jobs.c ash-0.3.7.orig/jobs.c
+--- netbsd-sh/jobs.c   Tue May 23 12:03:19 2000
++++ ash-0.3.7.orig/jobs.c      Mon Apr 23 22:16:46 2001
+@@ -189,6 +193,94 @@
+ #if JOBS
+ int
++killcmd(argc, argv)
++      int argc;
++      char **argv;
++{
++      extern char *signal_names[];
++      int signo = -1;
++      int list = 0;
++      int i;
++      pid_t pid;
++      struct job *jp;
++
++      if (argc <= 1) {
++              error(
++"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
++"kill -l [exitstatus]"
++              );
++      }
++
++      if (*argv[1] == '-') {
++              signo = decode_signal(argv[1]+1);
++              if (signo < 0) {
++                      int c;
++
++                      while ((c = nextopt("ls:")) != '\0')
++                              switch (c) {
++                              case 'l':
++                                      list = 1;
++                                      break;
++                              case 's':
++                                      signo = decode_signal(optarg);
++                                      break;
++                              default:
++                                      error(
++      "nextopt returned character code 0%o", c);
++                      }
++              } else
++                      argptr++;
++      }
++
++      if (!list && signo < 0)
++              signo = SIGTERM;
++
++      if ((signo < 0 || !*argptr) ^ list) {
++              error(
++"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
++"kill -l [exitstatus]"
++              );
++      }
++
++      if (list) {
++              if (!*argptr) {
++                      out1fmt("0\n");
++                      for (i = 1; i < NSIG; i++) {
++                              if (strncmp(signal_names[i], "SIGJUNK(", 8)
++                                  == 0)
++                                      continue;
++                              out1fmt("%s\n", signal_names[i] + 3);
++                      }
++                      return 0;
++              }
++              signo = atoi(*argptr);
++              if (signo > 128)
++                      signo -= 128;
++              if (0 < signo && signo < NSIG)
++                      out1fmt("%s\n", signal_names[signo] + 3);
++              else
++                      error("invalid signal number or exit status: %s",
++                            *argptr);
++              return 0;
++      }
++
++      do {
++              if (**argptr == '%') {
++                      jp = getjob(*argptr);
++                      if (jp->jobctl == 0)
++                              error("job %s not created under job control",
++                                    *argptr);
++                      pid = -jp->ps[0].pid;
++              } else
++                      pid = atoi(*argptr);
++              if (kill(pid, signo) != 0)
++                      error("%s: %s", *argptr, strerror(errno));
++      } while (*++argptr);
++
++      return 0;
++}
++
++int
+ fgcmd(argc, argv)
+       int argc;
+       char **argv;
+
+diff -urN netbsd-sh/jobs.h ash-0.3.7.orig/jobs.h
+--- netbsd-sh/jobs.h   Tue May 23 12:03:19 2000
++++ ash-0.3.7.orig/jobs.h      Mon Apr 23 22:16:46 2001
+@@ -80,6 +80,7 @@
+ extern int job_warning;               /* user was warned about stopped jobs */
+ void setjobctl __P((int));
++int killcmd __P((int, char **));
+ int fgcmd __P((int, char **));
+ int bgcmd __P((int, char **));
+ int jobscmd __P((int, char **));
+diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def
+--- netbsd-sh/builtins.def     Mon Apr 10 13:02:58 2000
++++ ash-0.3.7.orig/builtins.def        Mon Apr 23 22:16:46 2001
+@@ -70,6 +71,7 @@
+ hashcmd               hash
+ jobidcmd      jobid
+ jobscmd               jobs
++killcmd -j    kill
+ #linecmd              line
+ localcmd      local
+ #nlechocmd    nlecho
+diff -urN netbsd-sh/mksignames.c ash-0.3.7.orig/mksignames.c
+--- netbsd-sh/mksignames.c     Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/mksignames.c        Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,400 @@
++/* signames.c -- Create and write `signames.c', which contains an array of
++   signal names. */
++
++/* Copyright (C) 1992 Free Software Foundation, Inc.
++
++   This file is part of GNU Bash, the Bourne Again SHell.
++
++   Bash is free software; you can redistribute it and/or modify it under
++   the terms of the GNU General Public License as published by the Free
++   Software Foundation; either version 2, or (at your option) any later
++   version.
++
++   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
++   WARRANTY; without even the implied warranty of MERCHANTABILITY or
++   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++   for more details.
++
++   You should have received a copy of the GNU General Public License along
++   with Bash; see the file COPYING.  If not, write to the Free Software
++   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
++
++#include <stdio.h>
++#include <sys/types.h>
++#include <signal.h>
++#include <stdlib.h>
++
++#if !defined (NSIG)
++#  define NSIG 64
++#endif
++
++char *signal_names[2 * NSIG];
++
++char *progname;
++
++#if defined (SIGRTMAX) || defined (SIGRTMIN)
++#  define RTLEN 14
++#  define RTLIM 256
++#endif
++
++void
++initialize_signames ()
++{
++  register int i;
++#if defined (SIGRTMAX) || defined (SIGRTMIN)
++  int rtmin, rtmax, rtcnt;
++#endif
++
++  for (i = 1; i < sizeof(signal_names)/sizeof(signal_names[0]); i++)
++    signal_names[i] = (char *)NULL;
++
++  /* `signal' 0 is what we do on exit. */
++  signal_names[0] = "EXIT";
++
++  /* Place signal names which can be aliases for more common signal
++     names first.  This allows (for example) SIGABRT to overwrite SIGLOST. */
++
++  /* POSIX 1003.1b-1993 real time signals, but take care of incomplete
++     implementations. Acoording to the standard, both, SIGRTMIN and
++     SIGRTMAX must be defined, SIGRTMIN must be stricly less than
++     SIGRTMAX, and the difference must be at least 7, that is, there
++     must be at least eight distinct real time signals. */
++
++  /* The generated signal names are SIGRTMIN, SIGRTMIN+1, ...,
++     SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number
++     of RT signals is odd, there is an extra SIGRTMIN+(x+1).
++     These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */
++
++#if defined (SIGRTMIN)
++  rtmin = SIGRTMIN;
++  signal_names[rtmin] = "SIGRTMIN";
++#endif
++
++#if defined (SIGRTMAX)
++  rtmax = SIGRTMAX;
++  signal_names[rtmax] = "SIGRTMAX";
++#endif
++
++#if defined (SIGRTMAX) && defined (SIGRTMIN)
++  if (rtmax > rtmin)
++    {
++      rtcnt = (rtmax - rtmin - 1) / 2;
++      /* croak if there are too many RT signals */
++      if (rtcnt >= RTLIM/2)
++      {
++        rtcnt = RTLIM/2-1;
++        fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n",
++                progname, RTLIM, progname);
++      }
++
++      for (i = 1; i <= rtcnt; i++)
++      {
++        signal_names[rtmin+i] = (char *)malloc(RTLEN);
++        sprintf (signal_names[rtmin+i], "SIGRTMIN+%d", i);
++        signal_names[rtmax-i] = (char *)malloc(RTLEN);
++        sprintf (signal_names[rtmax-i], "SIGRTMAX-%d", i);
++      }
++
++      if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2)
++      {
++        /* Need an extra RTMIN signal */
++        signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN);
++        sprintf (signal_names[rtmin+rtcnt+1], "SIGRTMIN+%d", rtcnt+1);
++      }
++    }
++#endif /* SIGRTMIN && SIGRTMAX */
++
++/* AIX */
++#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */
++  signal_names[SIGLOST] = "SIGLOST";
++#endif
++
++#if defined (SIGMSG)  /* HFT input data pending */
++  signal_names[SIGMSG] = "SIGMSG";
++#endif
++
++#if defined (SIGDANGER)       /* system crash imminent */
++  signal_names[SIGDANGER] = "SIGDANGER";
++#endif
++
++#if defined (SIGMIGRATE) /* migrate process to another CPU */
++  signal_names[SIGMIGRATE] = "SIGMIGRATE";
++#endif
++
++#if defined (SIGPRE)  /* programming error */
++  signal_names[SIGPRE] = "SIGPRE";
++#endif
++
++#if defined (SIGVIRT) /* AIX virtual time alarm */
++  signal_names[SIGVIRT] = "SIGVIRT";
++#endif
++
++#if defined (SIGALRM1)        /* m:n condition variables */
++  signal_names[SIGALRM1] = "SIGALRM1";
++#endif
++
++#if defined (SIGWAITING)      /* m:n scheduling */
++  signal_names[SIGWAITING] = "SIGWAITING";
++#endif
++
++#if defined (SIGGRANT)        /* HFT monitor mode granted */
++  signal_names[SIGGRANT] = "SIGGRANT";
++#endif
++
++#if defined (SIGKAP)  /* keep alive poll from native keyboard */
++  signal_names[SIGKAP] = "SIGKAP";
++#endif
++
++#if defined (SIGRETRACT) /* HFT monitor mode retracted */
++  signal_names[SIGRETRACT] = "SIGRETRACT";
++#endif
++
++#if defined (SIGSOUND)        /* HFT sound sequence has completed */
++  signal_names[SIGSOUND] = "SIGSOUND";
++#endif
++
++#if defined (SIGSAK)  /* Secure Attention Key */
++  signal_names[SIGSAK] = "SIGSAK";
++#endif
++
++/* SunOS5 */
++#if defined (SIGLWP)  /* special signal used by thread library */
++  signal_names[SIGLWP] = "SIGLWP";
++#endif
++
++#if defined (SIGFREEZE)       /* special signal used by CPR */
++  signal_names[SIGFREEZE] = "SIGFREEZE";
++#endif
++
++#if defined (SIGTHAW) /* special signal used by CPR */
++  signal_names[SIGTHAW] = "SIGTHAW";
++#endif
++
++#if defined (SIGCANCEL)       /* thread cancellation signal used by libthread */
++  signal_names[SIGCANCEL] = "SIGCANCEL";
++#endif
++
++/* HP-UX */
++#if defined (SIGDIL)  /* DIL signal (?) */
++  signal_names[SIGDIL] = "SIGDIL";
++#endif
++
++/* System V */
++#if defined (SIGCLD)  /* Like SIGCHLD.  */
++  signal_names[SIGCLD] = "SIGCLD";
++#endif
++
++#if defined (SIGPWR)  /* power state indication */
++  signal_names[SIGPWR] = "SIGPWR";
++#endif
++
++#if defined (SIGPOLL) /* Pollable event (for streams)  */
++  signal_names[SIGPOLL] = "SIGPOLL";
++#endif
++
++/* Unknown */
++#if defined (SIGWINDOW)
++  signal_names[SIGWINDOW] = "SIGWINDOW";
++#endif
++
++/* Common */
++#if defined (SIGHUP)  /* hangup */
++  signal_names[SIGHUP] = "SIGHUP";
++#endif
++
++#if defined (SIGINT)  /* interrupt */
++  signal_names[SIGINT] = "SIGINT";
++#endif
++
++#if defined (SIGQUIT) /* quit */
++  signal_names[SIGQUIT] = "SIGQUIT";
++#endif
++
++#if defined (SIGILL)  /* illegal instruction (not reset when caught) */
++  signal_names[SIGILL] = "SIGILL";
++#endif
++
++#if defined (SIGTRAP) /* trace trap (not reset when caught) */
++  signal_names[SIGTRAP] = "SIGTRAP";
++#endif
++
++#if defined (SIGIOT)  /* IOT instruction */
++  signal_names[SIGIOT] = "SIGIOT";
++#endif
++
++#if defined (SIGABRT) /* Cause current process to dump core. */
++  signal_names[SIGABRT] = "SIGABRT";
++#endif
++
++#if defined (SIGEMT)  /* EMT instruction */
++  signal_names[SIGEMT] = "SIGEMT";
++#endif
++
++#if defined (SIGFPE)  /* floating point exception */
++  signal_names[SIGFPE] = "SIGFPE";
++#endif
++
++#if defined (SIGKILL) /* kill (cannot be caught or ignored) */
++  signal_names[SIGKILL] = "SIGKILL";
++#endif
++
++#if defined (SIGBUS)  /* bus error */
++  signal_names[SIGBUS] = "SIGBUS";
++#endif
++
++#if defined (SIGSEGV) /* segmentation violation */
++  signal_names[SIGSEGV] = "SIGSEGV";
++#endif
++
++#if defined (SIGSYS)  /* bad argument to system call */
++  signal_names[SIGSYS] = "SIGSYS";
++#endif
++
++#if defined (SIGPIPE) /* write on a pipe with no one to read it */
++  signal_names[SIGPIPE] = "SIGPIPE";
++#endif
++
++#if defined (SIGALRM) /* alarm clock */
++  signal_names[SIGALRM] = "SIGALRM";
++#endif
++
++#if defined (SIGTERM) /* software termination signal from kill */
++  signal_names[SIGTERM] = "SIGTERM";
++#endif
++
++#if defined (SIGURG)  /* urgent condition on IO channel */
++  signal_names[SIGURG] = "SIGURG";
++#endif
++
++#if defined (SIGSTOP) /* sendable stop signal not from tty */
++  signal_names[SIGSTOP] = "SIGSTOP";
++#endif
++
++#if defined (SIGTSTP) /* stop signal from tty */
++  signal_names[SIGTSTP] = "SIGTSTP";
++#endif
++
++#if defined (SIGCONT) /* continue a stopped process */
++  signal_names[SIGCONT] = "SIGCONT";
++#endif
++
++#if defined (SIGCHLD) /* to parent on child stop or exit */
++  signal_names[SIGCHLD] = "SIGCHLD";
++#endif
++
++#if defined (SIGTTIN) /* to readers pgrp upon background tty read */
++  signal_names[SIGTTIN] = "SIGTTIN";
++#endif
++
++#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local&LTOSTOP) */
++  signal_names[SIGTTOU] = "SIGTTOU";
++#endif
++
++#if defined (SIGIO)   /* input/output possible signal */
++  signal_names[SIGIO] = "SIGIO";
++#endif
++
++#if defined (SIGXCPU) /* exceeded CPU time limit */
++  signal_names[SIGXCPU] = "SIGXCPU";
++#endif
++
++#if defined (SIGXFSZ) /* exceeded file size limit */
++  signal_names[SIGXFSZ] = "SIGXFSZ";
++#endif
++
++#if defined (SIGVTALRM)       /* virtual time alarm */
++  signal_names[SIGVTALRM] = "SIGVTALRM";
++#endif
++
++#if defined (SIGPROF) /* profiling time alarm */
++  signal_names[SIGPROF] = "SIGPROF";
++#endif
++
++#if defined (SIGWINCH)        /* window changed */
++  signal_names[SIGWINCH] = "SIGWINCH";
++#endif
++
++/* 4.4 BSD */
++#if defined (SIGINFO) && !defined (_SEQUENT_) /* information request */
++  signal_names[SIGINFO] = "SIGINFO";
++#endif
++
++#if defined (SIGUSR1) /* user defined signal 1 */
++  signal_names[SIGUSR1] = "SIGUSR1";
++#endif
++
++#if defined (SIGUSR2) /* user defined signal 2 */
++  signal_names[SIGUSR2] = "SIGUSR2";
++#endif
++
++#if defined (SIGKILLTHR)      /* BeOS: Kill Thread */
++  signal_names[SIGKILLTHR] = "SIGKILLTHR";
++#endif
++
++  for (i = 0; i < NSIG; i++)
++    if (signal_names[i] == (char *)NULL)
++      {
++      signal_names[i] = (char *)malloc (18);
++      sprintf (signal_names[i], "SIGJUNK(%d)", i);
++      }
++
++  signal_names[NSIG] = "DEBUG";
++}
++
++void
++write_signames (stream)
++     FILE *stream;
++{
++  register int i;
++
++  fprintf (stream, "/* This file was automatically created by %s.\n",
++         progname);
++  fprintf (stream, "   Do not edit.  Edit support/mksignames.c instead. */\n\n");
++  fprintf (stream, "#include <signal.h>\n\n");
++  fprintf (stream,
++         "/* A translation list so we can be polite to our users. */\n");
++  fprintf (stream, "char *signal_names[NSIG + 2] = {\n");
++
++  for (i = 0; i <= NSIG; i++)
++    fprintf (stream, "    \"%s\",\n", signal_names[i]);
++
++  fprintf (stream, "    (char *)0x0,\n");
++  fprintf (stream, "};\n");
++}
++
++int
++main (argc, argv)
++     int argc;
++     char **argv;
++{
++  char *stream_name;
++  FILE *stream;
++
++  progname = argv[0];
++
++  if (argc == 1)
++    {
++      stream_name = "signames.c";
++    }
++  else if (argc == 2)
++    {
++      stream_name = argv[1];
++    }
++  else
++    {
++      fprintf (stderr, "Usage: %s [output-file]\n", progname);
++      exit (1);
++    }
++
++  stream = fopen (stream_name, "w");
++  if (!stream)
++    {
++      fprintf (stderr, "%s: %s: cannot open for writing\n",
++             progname, stream_name);
++      exit (2);
++    }
++
++  initialize_signames ();
++  write_signames (stream);
++  exit (0);
++}
+diff -urN netbsd-sh/trap.c ash-0.3.7.orig/trap.c
+--- netbsd-sh/trap.c   Tue May 23 12:03:19 2000
++++ ash-0.3.7.orig/trap.c      Mon Apr 23 22:16:46 2001
+@@ -84,7 +88,7 @@
+ char gotsig[NSIG];            /* indicates specified signal received */
+ int pendingsigs;                      /* indicates some signal received */
+-static int getsigaction __P((int, sig_t *));
++extern char *signal_names[];
+ /*
+  * The trap builtin.
+@@ -107,16 +111,20 @@
+               return 0;
+       }
+       ap = argv + 1;
+-      if (is_number(*ap))
++      if (argc == 2)
+               action = NULL;
+       else
+               action = *ap++;
+       while (*ap) {
+-              if ((signo = number(*ap)) < 0 || signo > NSIG)
++              if ((signo = decode_signal(*ap)) < 0)
+                       error("%s: bad trap", *ap);
+               INTOFF;
+-              if (action)
+-                      action = savestr(action);
++              if (action) {
++                      if (action[0] == '-' && action[1] == '\0')
++                              action = NULL;
++                      else
++                              action = savestr(action);
++              }
+               if (trap[signo])
+                       ckfree(trap[signo]);
+               trap[signo] = action;
+@@ -157,13 +165,13 @@
+  * out what it should be set to.
+  */
+-long
++void
+ setsignal(signo)
+       int signo;
+ {
+       int action;
+-      sig_t sigact = SIG_DFL;
+       char *t;
++      struct sigaction act;
+       if ((t = trap[signo]) == NULL)
+               action = S_DFL;
+@@ -206,15 +214,15 @@
+               /*
+                * current setting unknown
+                */
+-              if (!getsigaction(signo, &sigact)) {
++              if (sigaction(signo, 0, &act) == -1) {
+                       /*
+                        * Pretend it worked; maybe we should give a warning
+                        * here, but other shells don't. We don't alter
+                        * sigmode, so that we retry every time.
+                        */
+-                      return 0;
++                      return;
+               }
+-              if (sigact == SIG_IGN) {
++              if (act.sa_handler == SIG_IGN) {
+                       if (mflag && (signo == SIGTSTP ||
+                            signo == SIGTTIN || signo == SIGTTOU)) {
+                               *t = S_IGN;     /* don't hard ignore these */
+@@ -225,31 +233,21 @@
+               }
+       }
+       if (*t == S_HARD_IGN || *t == action)
+-              return 0;
++              return;
+       switch (action) {
+-              case S_DFL:     sigact = SIG_DFL;       break;
+-              case S_CATCH:   sigact = onsig;         break;
+-              case S_IGN:     sigact = SIG_IGN;       break;
++      case S_CATCH:
++              act.sa_handler = onsig;
++              break;
++      case S_IGN:
++              act.sa_handler = SIG_IGN;
++              break;
++      default:
++              act.sa_handler = SIG_DFL;
+       }
+       *t = action;
+-      siginterrupt(signo, 1);
+-      return (long)signal(signo, sigact);
+-}
+-
+-/*
+- * Return the current setting for sig w/o changing it.
+- */
+-static int
+-getsigaction(signo, sigact)
+-      int signo;
+-      sig_t *sigact;
+-{
+-      struct sigaction sa;
+-
+-      if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
+-              return 0;
+-      *sigact = (sig_t) sa.sa_handler;
+-      return 1;
++      act.sa_flags = 0;
++      sigemptyset(&act.sa_mask);
++      sigaction(signo, &act, 0);
+ }
+ /*
+@@ -382,4 +384,18 @@
+ #endif
+ l2:   _exit(status);
+       /* NOTREACHED */
++}
++
++int decode_signal(const char *string)
++{
++      int signo;
++
++      if (is_number(string)) return atoi(string);
++
++      for (signo=0; signo < NSIG; signo++)
++              if (strcasecmp(string, signal_names[signo]) == 0 ||
++                      strcasecmp(string, &(signal_names[signo])[3]) == 0)
++                      return signo;
++
++      return -1;
+ }
+diff -urN netbsd-sh/trap.h ash-0.3.7.orig/trap.h
+--- netbsd-sh/trap.h   Tue May 23 12:03:19 2000
++++ ash-0.3.7.orig/trap.h      Mon Apr 23 22:16:46 2001
+@@ -42,9 +42,10 @@
+ int trapcmd __P((int, char **));
+ void clear_traps __P((void));
+-long setsignal __P((int));
++void setsignal __P((int));
+ void ignoresig __P((int));
+ void onsig __P((int));
+ void dotrap __P((void));
+ void setinteractive __P((int));
+ void exitshell __P((int)) __attribute__((noreturn));
++int decode_signal __P((const char *));
diff --git a/ash-makefile.patch b/ash-makefile.patch
new file mode 100644 (file)
index 0000000..bb75a71
--- /dev/null
@@ -0,0 +1,115 @@
+diff -u ash-0.4.0/Makefile ash-0.4.0-/Makefile
+--- ash-0.4.0/Makefile Fri Jan 12 17:50:34 2001
++++ ash-0.4.0-/Makefile        Tue Apr 24 00:49:56 2001
+@@ -7,56 +7,68 @@
+ SHSRCS=       alias.c cd.c echo.c error.c eval.c exec.c expand.c \
+       histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
+       mystring.c options.c parser.c redir.c show.c trap.c output.c var.c \
+-      test.c
+-GENSRCS=arith.c arith.h arith_lex.c builtins.c builtins.h init.c nodes.c \
+-      nodes.h syntax.c syntax.h token.h
++      test.c setmode.c test.c
++GENSRCS=builtins.c builtins.h init.c nodes.c arith.c arith.h lex.yy.c \
++      nodes.h syntax.c syntax.h token.h signames.c
+ SRCS= ${SHSRCS} ${GENSRCS}
+-LDADD+=       -ll -ledit -ltermcap
+-DPADD+=       ${LIBL} ${LIBEDIT} ${LIBTERMCAP}
++OBJS=alias.o cd.o bltin/echo.o error.o eval.o exec.o expand.o \
++      histedit.o input.o jobs.o mail.o main.o memalloc.o miscbltin.o \
++      mystring.o options.o output.o parser.o redir.o show.o \
++      trap.o var.o bltin/test.o signames.o \
++      builtins.o init.o nodes.o syntax.o arith.o lex.yy.o \
++      setmode.o bltin/times.o
++
++OPT_FLAGS=-O2 -g
++LDFLAGS=-g
++CFLAGS=$(OPT_FLAGS) -DSHELL -I. -DNO_HISTORY -DBSD=1 -DSMALL -D_GNU_SOURCE \
++      -DGLOB_BROKEN -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)=
++
++all: $(PROG)
++
++$(PROG): build-tools $(GENSRCS) $(GENHDRS) $(OBJS)
++      $(CC) $(LDFLAGS) -o $(PROG) $(OBJS) -lfl
++      
++lex.yy.c: arith_lex.l
++      flex -8 $< 
++      
++CLEANFILES+= mkinit mkinit.o mknodes mknodes.o \
++      mksyntax mksyntax.o
++      
++CLEANFILES+= ${GENSRCS} ${GENHDRS}
++
++build-tools: mkinit mknodes mksyntax
++
++.ORDER: builtins.c builtins.h
++builtins.c builtins.h: mkbuiltins builtins.def
++      sh mkbuiltins shell.h builtins.def `pwd`
++
++INIT_DEPS = alias.c eval.c exec.c input.c jobs.c options.c parser.c \
++      redir.c trap.c var.c output.c
++      
++init.c: mkinit $(INIT_DEPS)
++      ./mkinit $(INIT_DEPS)
++
++mkinit: mkinit.o
++mknodes: mknodes.o
++mksyntax: mksyntax.o
+-LFLAGS= -8    # 8-bit lex scanner for arithmetic
+-YFLAGS=       -d
+-
+-CPPFLAGS+=-DSHELL -I. -I${.CURDIR}
+-
+-.PATH:        ${.CURDIR}/bltin ${.CURDIR}/../../usr.bin/printf ${.CURDIR}/../test
+-
+-CLEANFILES+= mkinit mknodes mksyntax
+-CLEANFILES+= ${GENSRCS} y.tab.h
+-
+-token.h: mktokens
+-      sh ${.ALLSRC}
+-
+-builtins.c builtins.h: mkbuiltins shell.h builtins.def
+-      sh ${.ALLSRC} ${.OBJDIR}
+-
+-init.c: mkinit ${SHSRCS}
+-      ./${.ALLSRC}
++signames.c: mksignames
++      ./mksignames
+ nodes.c nodes.h: mknodes nodetypes nodes.c.pat
+-      ./${.ALLSRC}
++      ./mknodes ./nodetypes ./nodes.c.pat
+ syntax.c syntax.h: mksyntax
+-      ./${.ALLSRC}
+-
+-mkinit: mkinit.c
+-      ${HOST_LINK.c} -o mkinit ${.IMPSRC}
+-
+-mknodes: mknodes.c
+-      ${HOST_LINK.c} -o mknodes ${.IMPSRC}
++      ./mksyntax
+-.if   (${MACHINE_ARCH} == "powerpc") || \
+-      (${MACHINE_ARCH} == "arm32") || \
+-      (${MACHINE_ARCH} == "arm26")
+-TARGET_CHARFLAG= -DTARGET_CHAR="u_int8_t"
+-.else
+-TARGET_CHARFLAG= -DTARGET_CHAR="int8_t"
+-.endif
++arith.c arith.h: arith.y
++      yacc -d arith.y
++      mv y.tab.h arith.h
++      mv y.tab.c arith.c
+-mksyntax: mksyntax.c
+-      ${HOST_LINK.c} ${TARGET_CHARFLAG} -o mksyntax ${.IMPSRC}
+-
+-.include <bsd.prog.mk>
++token.h: mktokens
++      sh ./mktokens
+-${OBJS}: builtins.h nodes.h syntax.h token.h
++clean:
++      rm -f $(PROG) $(OBJS) $(CLEANFILES) core
diff --git a/ash-manpage.patch b/ash-manpage.patch
new file mode 100644 (file)
index 0000000..458367e
--- /dev/null
@@ -0,0 +1,42 @@
+diff -urN netbsd-sh/sh.1 ash-0.3.7.orig/sh.1
+--- netbsd-sh/sh.1     Fri Jan 12 17:50:40 2001
++++ ash-0.3.7.orig/sh.1        Mon Apr 23 22:16:46 2001
+@@ -649,7 +649,7 @@
+ they were one program:
+ .Pp
+ .Bd -literal -offset indent
+-{ echo -n \*q hello \*q ; echo \*q world" } > greeting
++{ echo \*q hello \\c\*q ; echo \*q world" } > greeting
+ .Ed
+ .Pp
+ .Ss Functions
+@@ -1306,14 +1306,16 @@
+ will continue to print the old name for the directory.
+ .It Xo read Op Fl p Ar prompt
+ .Op Fl r
+-.Op Ar variable...
++.Ar variable...
+ .Xc
+ The prompt is printed if the
+ .Fl p
+ option is specified and the standard input is a terminal.  Then a line is
+ read from the standard input.  The trailing newline is deleted from the
+ line and the line is split as described in the section on word splitting
+-above, and the pieces are assigned to the variables in order. If there are
++above, and the pieces are assigned to the variables in order.
++At least one variable must be specified.
++If there are
+ more pieces than variables, the remaining pieces (along with the
+ characters in
+ .Ev IFS
+@@ -1394,6 +1396,9 @@
+ by one. If there are zero positional parameters,
+ .Ic shift
+ does nothing.
++.It times
++Print the accumulated user and system times for the shell and for processes
++run from the shell.  The return status is 0.
+ .It Xo trap
+ .Op Ar action
+ .Ar signal...
+
diff --git a/ash-memout.patch b/ash-memout.patch
new file mode 100644 (file)
index 0000000..9e6bb32
--- /dev/null
@@ -0,0 +1,369 @@
+diff -u ash-0.4.0/eval.c ash-0.4.0-/eval.c
+--- ash-0.4.0/eval.c   Tue Apr 24 00:53:12 2001
++++ ash-0.4.0-/eval.c  Tue Apr 24 00:13:57 2001
+@@ -879,9 +879,13 @@
+ #endif
+               mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
+               if (flags == EV_BACKCMD) {
++#ifdef _GNU_SOURCE
++                      openmemout();
++#else
+                       memout.nleft = 0;
+                       memout.nextc = memout.buf;
+                       memout.bufsize = 64;
++#endif
+                       mode |= REDIR_BACKQ;
+               }
+               redirect(cmd->ncmd.redirect, mode);
+@@ -928,10 +932,18 @@
+               if (cmdentry.u.index != EXECCMD)
+                       popredir();
+               if (flags == EV_BACKCMD) {
++#ifdef _GNU_SOURCE
++                      closememout();
++#endif
+                       backcmd->buf = memout.buf;
++#ifdef _GNU_SOURCE
++                      backcmd->nleft = memout.bufsize;
++#else
+                       backcmd->nleft = memout.nextc - memout.buf;
++#endif
+                       memout.buf = NULL;
+               }
++              cmdenviron = NULL;
+       } else {
+ #ifdef DEBUG
+               trputs("normal command:  ");  trargs(argv);
+diff -u ash-0.4.0/eval.c.orig ash-0.4.0-/eval.c.orig
+--- ash-0.4.0/eval.c.orig      Tue Apr 24 00:53:12 2001
++++ ash-0.4.0-/eval.c.orig     Tue Apr 24 00:13:57 2001
+@@ -878,9 +878,13 @@
+ #endif
+               mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
+               if (flags == EV_BACKCMD) {
++#ifdef _GNU_SOURCE
++                      openmemout();
++#else
+                       memout.nleft = 0;
+                       memout.nextc = memout.buf;
+                       memout.bufsize = 64;
++#endif
+                       mode |= REDIR_BACKQ;
+               }
+               redirect(cmd->ncmd.redirect, mode);
+@@ -927,10 +931,18 @@
+               if (cmdentry.u.index != EXECCMD)
+                       popredir();
+               if (flags == EV_BACKCMD) {
++#ifdef _GNU_SOURCE
++                      closememout();
++#endif
+                       backcmd->buf = memout.buf;
++#ifdef _GNU_SOURCE
++                      backcmd->nleft = memout.bufsize;
++#else
+                       backcmd->nleft = memout.nextc - memout.buf;
++#endif
+                       memout.buf = NULL;
+               }
++              cmdenviron = NULL;
+       } else {
+ #ifdef DEBUG
+               trputs("normal command:  ");  trargs(argv);
+Common subdirectories: ash-0.4.0/funcs and ash-0.4.0-/funcs
+diff -u ash-0.4.0/output.c ash-0.4.0-/output.c
+--- ash-0.4.0/output.c Fri Jan 12 17:50:39 2001
++++ ash-0.4.0-/output.c        Tue Apr 24 00:43:44 2001
+@@ -65,6 +65,10 @@
+ #include <errno.h>
+ #include <unistd.h>
+ #include <stdlib.h>
++#ifdef _GNU_SOURCE
++#undef CEOF                   /* get rid of the redefine warning */
++#include <fcntl.h>
++#endif
+ #include "shell.h"
+ #include "syntax.h"
+@@ -79,9 +83,15 @@
+ #define OUTPUT_ERR 01         /* error occurred on output */
++#ifdef _GNU_SOURCE
++struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
++struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
++struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
++#else
+ struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
+ struct output errout = {NULL, 0, NULL, 100, 2, 0};
+ struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
++#endif
+ struct output *out1 = &output;
+ struct output *out2 = &errout;
+@@ -92,9 +102,19 @@
+ INCLUDE "output.h"
+ INCLUDE "memalloc.h"
++INIT {
++#ifdef _GNU_SOURCE
++      initstreams();
++#endif
++}
++
+ RESET {
+       out1 = &output;
+       out2 = &errout;
++#ifdef _GNU_SOURCE
++      if (memout.stream != NULL)
++              closememout();
++#endif
+       if (memout.buf != NULL) {
+               ckfree(memout.buf);
+               memout.buf = NULL;
+@@ -124,33 +144,22 @@
+ void
+-out1str(p)
+-      const char *p;
+-      {
+-      outstr(p, out1);
+-}
+-
+-
+-void
+-out2str(p)
+-      const char *p;
+-      {
+-      outstr(p, out2);
+-}
+-
+-
+-void
+ outstr(p, file)
+       const char *p;
+       struct output *file;
+       {
++#ifdef _GNU_SOURCE
++      fputs(p, file->stream);
++#else
+       while (*p)
+               outc(*p++, file);
++#endif
+       if (file == out2)
+               flushout(file);
+ }
++#ifndef _GNU_SOURCE
+ char out_junk[16];
+@@ -183,6 +192,7 @@
+       }
+       dest->nleft--;
+ }
++#endif
+ void
+@@ -192,11 +202,11 @@
+ }
++#ifndef _GNU_SOURCE
+ void
+ flushout(dest)
+       struct output *dest;
+       {
+-
+       if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
+               return;
+       if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
+@@ -204,6 +214,7 @@
+       dest->nextc = dest->buf;
+       dest->nleft = dest->bufsize;
+ }
++#endif
+ void
+@@ -264,6 +275,7 @@
+       va_end(ap);
+ }
++#ifndef __GLIBC__
+ void
+ #ifdef __STDC__
+ dprintf(const char *fmt, ...)
+@@ -285,6 +297,7 @@
+       va_end(ap);
+       flushout(out2);
+ }
++#endif
+ void
+ #ifdef __STDC__
+@@ -295,7 +308,9 @@
+ #endif
+ {
+       va_list ap;
++#ifndef _GNU_SOURCE
+       struct output strout;
++#endif
+ #ifndef __STDC__
+       char *outbuf;
+       size_t length;
+@@ -308,6 +323,9 @@
+ #else
+       va_start(ap, fmt);
+ #endif
++#ifdef _GNU_SOURCE
++      vsnprintf(outbuf, length, fmt, ap);
++#else
+       strout.nextc = outbuf;
+       strout.nleft = length;
+       strout.fd = BLOCK_OUT;
+@@ -316,8 +334,10 @@
+       outc('\0', &strout);
+       if (strout.flags & OUTPUT_ERR)
+               outbuf[length - 1] = '\0';
++#endif
+ }
++#ifndef _GNU_SOURCE
+ /*
+  * Formatted output.  This routine handles a subset of the printf formats:
+  * - Formats supported: d, u, o, p, X, s, and c.
+@@ -534,7 +554,7 @@
+       }
+ #endif        /* !HAVE_VASPRINTF */
+ }
+-
++#endif
+ /*
+@@ -544,7 +564,7 @@
+ int
+ xwrite(fd, buf, nbytes)
+       int fd;
+-      char *buf;
++      const char *buf;
+       int nbytes;
+       {
+       int ntry;
+@@ -570,6 +590,8 @@
+ }
++
++#ifdef notdef
+ /*
+  * Version of ioctl that retries after a signal is caught.
+  * XXX unused function
+@@ -586,3 +608,27 @@
+       while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
+       return i;
+ }
++#endif
++
++
++#ifdef _GNU_SOURCE
++void initstreams() {
++      output.stream = stdout;
++      errout.stream = stderr;
++}
++
++
++void
++openmemout() {
++      memout.stream = open_memstream(&memout.buf, &memout.bufsize);
++}
++
++
++void
++closememout() {
++      INTOFF;
++      fclose(memout.stream);
++      memout.stream = NULL;
++      INTON;
++}
++#endif
+diff -u ash-0.4.0/output.h ash-0.4.0-/output.h
+--- ash-0.4.0/output.h Sat Jan 31 19:28:11 1998
++++ ash-0.4.0-/output.h        Tue Apr 24 00:13:57 2001
+@@ -45,13 +45,19 @@
+ #else
+ #include <varargs.h>
+ #endif
++#ifdef _GNU_SOURCE
++#include <stdio.h>
++#endif
+ struct output {
++#ifdef _GNU_SOURCE
++      FILE *stream;
++#endif
+       char *nextc;
+       int nleft;
+       char *buf;
+       int bufsize;
+-      short fd;
++      int fd;
+       short flags;
+ };
+@@ -61,29 +67,44 @@
+ extern struct output *out1;
+ extern struct output *out2;
+-void open_mem __P((char *, int, struct output *));
+-void out1str __P((const char *));
+-void out2str __P((const char *));
+ void outstr __P((const char *, struct output *));
++#ifndef _GNU_SOURCE
+ void emptyoutbuf __P((struct output *));
++#endif
+ void flushall __P((void));
++#ifndef _GNU_SOURCE
+ void flushout __P((struct output *));
++#endif
+ void freestdout __P((void));
+ void outfmt __P((struct output *, const char *, ...))
+     __attribute__((__format__(__printf__,2,3)));
+ void out1fmt __P((const char *, ...))
+     __attribute__((__format__(__printf__,1,2)));
++#ifndef __GLIBC__
+ void dprintf __P((const char *, ...))
+     __attribute__((__format__(__printf__,1,2)));
++#endif
+ void fmtstr __P((char *, size_t, const char *, ...))
+     __attribute__((__format__(__printf__,3,4)));
++#ifndef _GNU_SOURCE
+ void doformat __P((struct output *, const char *, va_list));
+-int xwrite __P((int, char *, int));
+-int xioctl __P((int, unsigned long, char *));
++#endif
++int xwrite __P((int, const char *, int));
++#ifdef _GNU_SOURCE
++void initstreams __P((void));
++void openmemout __P((void));
++void closememout __P((void));
++#define outc(c, o)    putc(c, (o)->stream)
++#define flushout(o)   fflush((o)->stream)
++#define doformat(d, f, a)     vfprintf((d)->stream, f, a)
++#else
+ #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
+-#define out1c(c)      outc(c, out1);
+-#define out2c(c)      outc(c, out2);
++#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 OUTPUT_INCL
+ #endif
diff --git a/ash-misc.patch b/ash-misc.patch
new file mode 100644 (file)
index 0000000..9845a23
--- /dev/null
@@ -0,0 +1,122 @@
+diff -urN netbsd-sh/error.c ash-0.3.7.orig/error.c
+--- netbsd-sh/error.c  Fri Jan 12 17:50:35 2001
++++ ash-0.3.7.orig/error.c     Mon Apr 23 22:16:46 2001
+@@ -233,6 +233,7 @@
+       { ENOTDIR,      E_CREAT,"directory nonexistent" },
+       { ENOTDIR,      E_EXEC, "not found" },
+       { EISDIR,       ALL,    "is a directory" },
++      { EEXIST,       E_CREAT,"file exists" },
+ #ifdef notdef
+       { EMFILE,       ALL,    "too many open files" },
+ #endif
+diff -urN netbsd-sh/error.h ash-0.3.7.orig/error.h
+--- netbsd-sh/error.h  Fri Jul  9 13:02:05 1999
++++ ash-0.3.7.orig/error.h     Mon Apr 23 22:16:46 2001
+@@ -102,7 +102,7 @@
+  * so we use _setjmp instead.
+  */
+-#if defined(BSD) && !defined(__SVR4)
++#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
+ #define setjmp(jmploc)        _setjmp(jmploc)
+ #define longjmp(jmploc, val)  _longjmp(jmploc, val)
+ #endif
+diff -urN netbsd-sh/bltin/bltin.h ash-0.3.7.orig/bltin/bltin.h
+--- netbsd-sh/bltin/bltin.h    Sat Jul  5 13:12:37 1997
++++ ash-0.3.7.orig/bltin/bltin.h       Mon Apr 23 22:16:46 2001
+@@ -46,8 +46,10 @@
+ #include "../shell.h"
+ #include "../mystring.h"
++#include "../memalloc.h"
+ #ifdef SHELL
+ #include "../output.h"
++#ifndef _GNU_SOURCE
+ #define stdout out1
+ #define stderr out2
+ #define printf out1fmt
+@@ -56,12 +58,13 @@
+ #define fprintf outfmt
+ #define fputs outstr
+ #define fflush flushout
+-#define INITARGS(argv)
+ #define warnx(a, b, c) {                              \
+       char buf[64];                                   \
+       (void)snprintf(buf, sizeof(buf), a, b, c);      \
+       error("%s", buf);                               \
+ }
++#endif
++#define INITARGS(argv)
+ #else
+ #undef NULL
+diff -urN netbsd-sh/main.c ash-0.3.7.orig/main.c
+--- netbsd-sh/main.c   Fri Jan 12 17:50:36 2001
++++ ash-0.3.7.orig/main.c      Mon Apr 23 22:16:46 2001
+@@ -115,6 +119,9 @@
+ #if PROFILE
+       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+ #endif
++#if defined(linux) || defined(__GNU__)
++      signal(SIGCHLD, SIG_DFL);
++#endif
+       state = 0;
+       if (setjmp(jmploc.loc)) {
+               /*
+diff -urN netbsd-sh/var.c ash-0.3.7.orig/var.c
+--- netbsd-sh/var.c    Fri Jan 12 17:50:40 2001
++++ ash-0.3.7.orig/var.c       Mon Apr 23 22:19:54 2001
+@@ -114,7 +114,7 @@
+         NULL },
+       { &vmpath,      VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
+         NULL },
+-      { &vpath,       VSTRFIXED|VTEXTFIXED,           "PATH=" _PATH_DEFPATH,
++      { &vpath,       VSTRFIXED|VTEXTFIXED,           "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+         changepath },
+       /*
+        * vps1 depends on uid
+@@ -138,13 +138,16 @@
+ /*
+  * Initialize the varable symbol tables and import the environment
++ * Setting PWD added by herbert
+  */
+ #ifdef mkinit
++INCLUDE "cd.h"
+ INCLUDE "var.h"
+ INIT {
+       char **envp;
+       extern char **environ;
++      extern char *curdir;
+       initvar();
+       for (envp = environ ; *envp ; envp++) {
+@@ -152,6 +155,9 @@
+                       setvareq(*envp, VEXPORT|VTEXTFIXED);
+               }
+       }
++
++      getpwd();
++      setvar("PWD", curdir, VEXPORT|VTEXTFIXED);
+ }
+ #endif
+@@ -283,6 +289,7 @@
+       struct var *vp, **vpp;
+       vpp = hashvar(s);
++      flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
+       for (vp = *vpp ; vp ; vp = vp->next) {
+               if (varequal(s, vp->text)) {
+                       if (vp->flags & VREADONLY) {
+@@ -305,7 +312,8 @@
+                        * We could roll this to a function, to handle it as
+                        * a regular variable function callback, but why bother?
+                        */
+-                      if (vp == &vmpath || (vp == &vmail && ! mpathset()))
++                      if (iflag &&
++                          (vp == &vmpath || (vp == &vmail && ! mpathset())))
+                               chkmail(1);
+                       INTON;
+                       return;
diff --git a/ash-ppid.patch b/ash-ppid.patch
new file mode 100644 (file)
index 0000000..954b509
--- /dev/null
@@ -0,0 +1,21 @@
+diff -ur ash-0.4.0/var.c ash-0.4.0-ppid/var.c
+--- ash-0.4.0/var.c    Tue Apr 24 01:23:17 2001
++++ ash-0.4.0-ppid/var.c       Tue Apr 24 01:22:07 2001
+@@ -172,6 +172,7 @@
+       const struct varinit *ip;
+       struct var *vp;
+       struct var **vpp;
++      char ppid[30];
+       for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
+               if ((vp->flags & VEXPORT) == 0) {
+@@ -193,6 +194,9 @@
+               vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
+               vps1.flags = VSTRFIXED|VTEXTFIXED;
+       }
++      
++      snprintf(ppid, 29, "%ld", (long)getppid());
++      setvar("PPID", ppid, VREADONLY|VNOFUNC);
+ }
+ /*
diff --git a/ash-redir.patch b/ash-redir.patch
new file mode 100644 (file)
index 0000000..40cdbe9
--- /dev/null
@@ -0,0 +1,463 @@
+diff -ur netbsd-sh/eval.c netbsd-sh-/eval.c
+--- netbsd-sh/eval.c   Tue May 23 12:03:18 2000
++++ netbsd-sh-/eval.c  Mon Apr 23 23:33:34 2001
+@@ -442,6 +442,7 @@
+               case NFROM:
+               case NTO:
+               case NAPPEND:
++              case NTOOV:
+                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
+                       redir->nfile.expfname = fn.list->text;
+                       break;
+diff -ur netbsd-sh/exec.c netbsd-sh-/exec.c
+--- netbsd-sh/exec.c   Fri Jan 12 17:50:35 2001
++++ netbsd-sh-/exec.c  Mon Apr 23 23:33:34 2001
+@@ -125,6 +125,10 @@
+       char *cmdname;
+       int e;
++      if (fd2 >= 0 && fd2 != 2) {
++              close(fd2);
++      }
++
+       if (strchr(argv[0], '/') != NULL) {
+               tryexec(argv[0], argv, envp);
+               e = errno;
+diff -ur netbsd-sh/jobs.c netbsd-sh-/jobs.c
+--- netbsd-sh/jobs.c   Mon Apr 23 23:34:53 2001
++++ netbsd-sh-/jobs.c  Mon Apr 23 23:34:30 2001
+@@ -129,9 +129,9 @@
+       if (on) {
+               do { /* while we are in the background */
+ #ifdef OLD_TTY_DRIVER
+-                      if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
++                      if (ioctl(fd2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
+ #else
+-                      initialpgrp = tcgetpgrp(2);
++                      initialpgrp = tcgetpgrp(fd2);
+                       if (initialpgrp < 0) {
+ #endif
+                               out2str("sh: can't access tty; job control turned off\n");
+@@ -146,7 +146,7 @@
+                       }
+               } while (0);
+ #ifdef OLD_TTY_DRIVER
+-              if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
++              if (ioctl(fd2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
+                       out2str("sh: need new tty driver to run job control; job control turned off\n");
+                       mflag = 0;
+                       return;
+@@ -157,16 +157,16 @@
+               setsignal(SIGTTIN);
+               setpgid(0, rootpid);
+ #ifdef OLD_TTY_DRIVER
+-              ioctl(2, TIOCSPGRP, (char *)&rootpid);
++              ioctl(fd2, TIOCSPGRP, (char *)&rootpid);
+ #else
+-              tcsetpgrp(2, rootpid);
++              tcsetpgrp(fd2, rootpid);
+ #endif
+       } else { /* turning job control off */
+               setpgid(0, initialpgrp);
+ #ifdef OLD_TTY_DRIVER
+-              ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
++              ioctl(fd2, TIOCSPGRP, (char *)&initialpgrp);
+ #else
+-              tcsetpgrp(2, initialpgrp);
++              tcsetpgrp(fd2, initialpgrp);
+ #endif
+               setsignal(SIGTSTP);
+               setsignal(SIGTTOU);
+@@ -206,9 +206,9 @@
+               error("job not created under job control");
+       pgrp = jp->ps[0].pid;
+ #ifdef OLD_TTY_DRIVER
+-      ioctl(2, TIOCSPGRP, (char *)&pgrp);
++      ioctl(fd2, TIOCSPGRP, (char *)&pgrp);
+ #else
+-      tcsetpgrp(2, pgrp);
++      tcsetpgrp(fd2, pgrp);
+ #endif
+       restartjob(jp);
+       INTOFF;
+@@ -612,10 +612,10 @@
+                       if (mode == FORK_FG) {
+                               /*** this causes superfluous TIOCSPGRPS ***/
+ #ifdef OLD_TTY_DRIVER
+-                              if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
++                              if (ioctl(fd2, TIOCSPGRP, (char *)&pgrp) < 0)
+                                       error("TIOCSPGRP failed, errno=%d", errno);
+ #else
+-                              if (tcsetpgrp(2, pgrp) < 0)
++                              if (tcsetpgrp(fd2, pgrp) < 0)
+                                       error("tcsetpgrp failed, errno=%d", errno);
+ #endif
+                       }
+@@ -734,10 +734,10 @@
+ #if JOBS
+       if (jp->jobctl) {
+ #ifdef OLD_TTY_DRIVER
+-              if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
++              if (ioctl(fd2, TIOCSPGRP, (char *)&mypgrp) < 0)
+                       error("TIOCSPGRP failed, errno=%d\n", errno);
+ #else
+-              if (tcsetpgrp(2, mypgrp) < 0)
++              if (tcsetpgrp(fd2, mypgrp) < 0)
+                       error("tcsetpgrp failed, errno=%d\n", errno);
+ #endif
+       }
+@@ -1092,6 +1092,8 @@
+               p = ">>";  i = 1;  goto redir;
+       case NTOFD:
+               p = ">&";  i = 1;  goto redir;
++      case NTOOV:
++              p = ">|";  i = 1;  goto redir;
+       case NFROM:
+               p = "<";  i = 0;  goto redir;
+       case NFROMFD:
+Only in netbsd-sh-: jobs.c.orig
+diff -ur netbsd-sh/nodetypes netbsd-sh-/nodetypes
+--- netbsd-sh/nodetypes        Fri Feb  5 13:04:52 1999
++++ netbsd-sh-/nodetypes       Mon Apr 23 23:33:34 2001
+@@ -119,6 +119,7 @@
+ NFROM nfile                   # fd< fname
+ NFROMTO nfile                 # fd<> fname
+ NAPPEND nfile                 # fd>> fname
++NTOOV nfile                   # fd>| fname
+       type      int
+       next      nodeptr               # next redirection in list
+       fd        int                   # file descriptor being redirected
+diff -ur netbsd-sh/parser.c netbsd-sh-/parser.c
+--- netbsd-sh/parser.c Fri Jan 12 17:50:39 2001
++++ netbsd-sh-/parser.c        Mon Apr 23 23:33:34 2001
+@@ -1125,6 +1125,8 @@
+                       np->type = NAPPEND;
+               else if (c == '&')
+                       np->type = NTOFD;
++              else if (c == '|')
++                      np->type = NTOOV;
+               else {
+                       np->type = NTO;
+                       pungetc();
+diff -ur netbsd-sh/redir.c netbsd-sh-/redir.c
+--- netbsd-sh/redir.c  Tue May 23 12:03:19 2000
++++ netbsd-sh-/redir.c Mon Apr 23 23:33:34 2001
+@@ -45,6 +45,7 @@
+ #endif
+ #endif /* not lint */
++#include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/param.h>        /* PIPE_BUF */
+ #include <signal.h>
+@@ -66,6 +67,7 @@
+ #include "output.h"
+ #include "memalloc.h"
+ #include "error.h"
++#include "options.h"
+ #define EMPTY -2              /* marks an unused slot in redirtab */
+@@ -92,8 +94,15 @@
+ */
+ int fd0_redirected = 0;
+-STATIC void openredirect __P((union node *, char[10 ]));
++/*
++ * We also keep track of where fd2 goes.
++ */
++int fd2 = 2;
++
++STATIC int openredirect __P((union node *));
++STATIC void dupredirect __P((union node *, int, char[10 ]));
+ STATIC int openhere __P((union node *));
++STATIC int noclobberopen __P((const char *));
+ /*
+@@ -113,6 +122,7 @@
+       struct redirtab *sv = NULL;
+       int i;
+       int fd;
++      int newfd;
+       int try;
+       char memory[10];        /* file descriptors to write to memory */
+@@ -133,36 +143,47 @@
+                   n->ndup.dupfd == fd)
+                       continue; /* redirect from/to same file descriptor */
+-              if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
+-                      INTOFF;
+-again:
+-                      if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
++              INTOFF;
++              newfd = openredirect(n);
++              if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
++                  (fd == fd2)) {
++                      if (newfd == fd) {
++                              try++;
++                      } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
+                               switch (errno) {
+                               case EBADF:
+                                       if (!try) {
+-                                              openredirect(n, memory);
++                                              dupredirect(n, newfd, memory);
+                                               try++;
+-                                              goto again;
++                                              break;
+                                       }
+                                       /* FALLTHROUGH*/
+                               default:
++                                      if (newfd >= 0) {
++                                              close(newfd);
++                                      }
+                                       INTON;
+                                       error("%d: %s", fd, strerror(errno));
+                                       /* NOTREACHED */
+                               }
+                       }
+                       if (!try) {
+-                              sv->renamed[fd] = i;
+                               close(fd);
++                              if (flags & REDIR_PUSH) {
++                                      sv->renamed[fd] = i;
++                              }
++                              if (fd == fd2) {
++                                      fd2 = i;
++                              }
+                       }
+-                      INTON;
+-              } else {
++              } else if (fd != newfd) {
+                       close(fd);
+               }
+                 if (fd == 0)
+                         fd0_redirected++;
+               if (!try)
+-                      openredirect(n, memory);
++                      dupredirect(n, newfd, memory);
++              INTON;
+       }
+       if (memory[1])
+               out1 = &memout;
+@@ -171,22 +192,13 @@
+ }
+-STATIC void
+-openredirect(redir, memory)
++STATIC int
++openredirect(redir)
+       union node *redir;
+-      char memory[10];
+       {
+-      int fd = redir->nfile.fd;
+       char *fname;
+       int f;
+-      /*
+-       * We suppress interrupts so that we won't leave open file
+-       * descriptors around.  This may not be such a good idea because
+-       * an open of a device or a fifo can block indefinitely.
+-       */
+-      INTOFF;
+-      memory[fd] = 0;
+       switch (redir->nfile.type) {
+       case NFROM:
+               fname = redir->nfile.expfname;
+@@ -199,6 +211,14 @@
+                       goto ecreate;
+               break;
+       case NTO:
++              /* Take care of noclobber mode. */
++              if (Cflag) {
++                      fname = redir->nfile.expfname;
++                      if ((f = noclobberopen(fname)) < 0)
++                              goto ecreate;
++                      break;
++              }
++      case NTOOV:
+               fname = redir->nfile.expfname;
+ #ifdef O_CREAT
+               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+@@ -222,32 +242,48 @@
+               break;
+       case NTOFD:
+       case NFROMFD:
++              f = -1;
++              break;
++      case NHERE:
++      case NXHERE:
++              f = openhere(redir);
++              break;
++      default:
++              abort();
++      }
++
++      return f;
++ecreate:
++      error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
++eopen:
++      error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
++}
++
++
++STATIC void
++dupredirect(redir, f, memory)
++      union node *redir;
++      int f;
++      char memory[10];
++      {
++      int fd = redir->nfile.fd;
++
++      memory[fd] = 0;
++      if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
+               if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
+                       if (memory[redir->ndup.dupfd])
+                               memory[fd] = 1;
+                       else
+                               copyfd(redir->ndup.dupfd, fd);
+               }
+-              INTON;
+               return;
+-      case NHERE:
+-      case NXHERE:
+-              f = openhere(redir);
+-              break;
+-      default:
+-              abort();
+       }
+       if (f != fd) {
+               copyfd(f, fd);
+               close(f);
+       }
+-      INTON;
+       return;
+-ecreate:
+-      error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+-eopen:
+-      error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+ }
+@@ -304,6 +340,7 @@
+       struct redirtab *rp = redirlist;
+       int i;
++      INTOFF;
+       for (i = 0 ; i < 10 ; i++) {
+               if (rp->renamed[i] != EMPTY) {
+                         if (i == 0)
+@@ -313,9 +350,11 @@
+                               copyfd(rp->renamed[i], i);
+                               close(rp->renamed[i]);
+                       }
++                      if (rp->renamed[i] == fd2) {
++                              fd2 = i;
++                      }
+               }
+       }
+-      INTOFF;
+       redirlist = rp->next;
+       ckfree(rp);
+       INTON;
+@@ -359,6 +398,9 @@
+               for (i = 0 ; i < 10 ; i++) {
+                       if (rp->renamed[i] >= 0) {
+                               close(rp->renamed[i]);
++                              if (rp->renamed[i] == fd2) {
++                                      fd2 = -1;
++                              }
+                       }
+                       rp->renamed[i] = EMPTY;
+               }
+@@ -388,4 +430,63 @@
+                       error("%d: %s", from, strerror(errno));
+       }
+       return newfd;
++}
++
++/*
++ * Open a file in noclobber mode.
++ * The code was copied from bash.
++ */
++int
++noclobberopen(fname)
++      const char *fname;
++{
++      int r, fd;
++      struct stat finfo, finfo2;
++
++      /*
++       * If the file exists and is a regular file, return an error
++       * immediately.
++       */
++      r = stat(fname, &finfo);
++      if (r == 0 && S_ISREG(finfo.st_mode)) {
++              errno = EEXIST;
++              return -1;
++      }
++
++      /*
++       * If the file was not present (r != 0), make sure we open it
++       * exclusively so that if it is created before we open it, our open
++       * will fail.  Make sure that we do not truncate an existing file.
++       * Note that we don't turn on O_EXCL unless the stat failed -- if the
++       * file was not a regular file, we leave O_EXCL off.
++       */
++      if (r != 0)
++              return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
++      fd = open(fname, O_WRONLY|O_CREAT, 0666);
++
++      /* If the open failed, return the file descriptor right away. */
++      if (fd < 0)
++              return fd;
++
++      /*
++       * OK, the open succeeded, but the file may have been changed from a
++       * non-regular file to a regular file between the stat and the open.
++       * We are assuming that the O_EXCL open handles the case where FILENAME
++       * did not exist and is symlinked to an existing file between the stat
++       * and open.
++       */
++
++      /*
++       * If we can open it and fstat the file descriptor, and neither check
++       * revealed that it was a regular file, and the file has not been
++       * replaced, return the file descriptor.
++       */
++       if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
++           finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
++              return fd;
++
++      /* The file has been replaced.  badness. */
++      close(fd);
++      errno = EEXIST;
++      return -1;
+ }
+Only in netbsd-sh-: redir.c.orig
+diff -ur netbsd-sh/redir.h netbsd-sh-/redir.h
+--- netbsd-sh/redir.h  Tue May 23 12:03:19 2000
++++ netbsd-sh-/redir.h Mon Apr 23 23:33:34 2001
+@@ -42,6 +42,8 @@
+ #define REDIR_PUSH 01         /* save previous values of file descriptors */
+ #define REDIR_BACKQ 02                /* save the command output in memory */
++extern int fd2;
++
+ union node;
+ void redirect __P((union node *, int));
+ void popredir __P((void));
+diff -ur netbsd-sh/show.c netbsd-sh-/show.c
+--- netbsd-sh/show.c   Sat Oct  9 13:02:09 1999
++++ netbsd-sh-/show.c  Mon Apr 23 23:33:34 2001
+@@ -155,6 +155,7 @@
+                       case NTO:       s = ">";  dftfd = 1; break;
+                       case NAPPEND:   s = ">>"; dftfd = 1; break;
+                       case NTOFD:     s = ">&"; dftfd = 1; break;
++                      case NTOOV:     s = ">|"; dftfd = 1; break;
+                       case NFROM:     s = "<";  dftfd = 0; break;
+                       case NFROMFD:   s = "<&"; dftfd = 0; break;
+                       case NFROMTO:   s = "<>"; dftfd = 0; break;
diff --git a/ash-setmode.patch b/ash-setmode.patch
new file mode 100644 (file)
index 0000000..b9a26d9
--- /dev/null
@@ -0,0 +1,510 @@
+diff -urN netbsd-sh/miscbltin.c ash-0.3.7.orig/miscbltin.c
+--- netbsd-sh/miscbltin.c      Fri Jan 12 17:50:37 2001
++++ ash-0.3.7.orig/miscbltin.c Mon Apr 23 22:16:46 2001
+@@ -70,6 +70,15 @@
+ #undef rflag
++#ifdef __GLIBC__
++mode_t getmode(const void *, mode_t);
++void *setmode(const char *);
++
++#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
++typedef enum __rlimit_resource rlim_t;
++#endif
++#endif
++
+ extern char **argptr;         /* argument list for builtin command */
+diff -urN netbsd-sh/setmode.c ash-0.3.7.orig/setmode.c
+--- netbsd-sh/setmode.c        Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/setmode.c   Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,486 @@
++/*    $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $       */
++
++/*
++ * Copyright (c) 1989, 1993, 1994
++ *    The Regents of the University of California.  All rights reserved.
++ *
++ * This code is derived from software contributed to Berkeley by
++ * Dave Borman at Cray Research, Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ *    must display the following acknowledgement:
++ *    This product includes software developed by the University of
++ *    California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ *    may be used to endorse or promote products derived from this software
++ *    without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#include <sys/cdefs.h>
++#if defined(LIBC_SCCS) && !defined(lint)
++#if 0
++static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94";
++#else
++__RCSID("$NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $");
++#endif
++#endif /* LIBC_SCCS and not lint */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++
++#include <assert.h>
++#include <ctype.h>
++#include <errno.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++#ifdef SETMODE_DEBUG
++#include <stdio.h>
++#endif
++
++#ifdef __weak_alias
++__weak_alias(getmode,_getmode)
++__weak_alias(setmode,_setmode)
++#endif
++
++#ifdef __GLIBC__
++#define S_ISTXT __S_ISVTX
++#endif
++
++#define       SET_LEN 6               /* initial # of bitcmd struct to malloc */
++#define       SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
++
++typedef struct bitcmd {
++      char    cmd;
++      char    cmd2;
++      mode_t  bits;
++} BITCMD;
++
++#define       CMD2_CLR        0x01
++#define       CMD2_SET        0x02
++#define       CMD2_GBITS      0x04
++#define       CMD2_OBITS      0x08
++#define       CMD2_UBITS      0x10
++
++static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int));
++static void    compress_mode __P((BITCMD *));
++#ifdef SETMODE_DEBUG
++static void    dumpmode __P((BITCMD *));
++#endif
++
++/*
++ * Given the old mode and an array of bitcmd structures, apply the operations
++ * described in the bitcmd structures to the old mode, and return the new mode.
++ * Note that there is no '=' command; a strict assignment is just a '-' (clear
++ * bits) followed by a '+' (set bits).
++ */
++mode_t
++getmode(bbox, omode)
++      const void *bbox;
++      mode_t omode;
++{
++      const BITCMD *set;
++      mode_t clrval, newmode, value;
++
++      _DIAGASSERT(bbox != NULL);
++
++      set = (const BITCMD *)bbox;
++      newmode = omode;
++      for (value = 0;; set++)
++              switch(set->cmd) {
++              /*
++               * When copying the user, group or other bits around, we "know"
++               * where the bits are in the mode so that we can do shifts to
++               * copy them around.  If we don't use shifts, it gets real
++               * grundgy with lots of single bit checks and bit sets.
++               */
++              case 'u':
++                      value = (newmode & S_IRWXU) >> 6;
++                      goto common;
++
++              case 'g':
++                      value = (newmode & S_IRWXG) >> 3;
++                      goto common;
++
++              case 'o':
++                      value = newmode & S_IRWXO;
++common:                       if (set->cmd2 & CMD2_CLR) {
++                              clrval =
++                                  (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
++                              if (set->cmd2 & CMD2_UBITS)
++                                      newmode &= ~((clrval<<6) & set->bits);
++                              if (set->cmd2 & CMD2_GBITS)
++                                      newmode &= ~((clrval<<3) & set->bits);
++                              if (set->cmd2 & CMD2_OBITS)
++                                      newmode &= ~(clrval & set->bits);
++                      }
++                      if (set->cmd2 & CMD2_SET) {
++                              if (set->cmd2 & CMD2_UBITS)
++                                      newmode |= (value<<6) & set->bits;
++                              if (set->cmd2 & CMD2_GBITS)
++                                      newmode |= (value<<3) & set->bits;
++                              if (set->cmd2 & CMD2_OBITS)
++                                      newmode |= value & set->bits;
++                      }
++                      break;
++
++              case '+':
++                      newmode |= set->bits;
++                      break;
++
++              case '-':
++                      newmode &= ~set->bits;
++                      break;
++
++              case 'X':
++                      if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
++                              newmode |= set->bits;
++                      break;
++
++              case '\0':
++              default:
++#ifdef SETMODE_DEBUG
++                      (void)printf("getmode:%04o -> %04o\n", omode, newmode);
++#endif
++                      return (newmode);
++              }
++}
++
++#define       ADDCMD(a, b, c, d) do {                                         \
++      if (set >= endset) {                                            \
++              BITCMD *newset;                                         \
++              setlen += SET_LEN_INCR;                                 \
++              newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
++              if (newset == NULL) {                                   \
++                      free(saveset);                                  \
++                      return (NULL);                                  \
++              }                                                       \
++              set = newset + (set - saveset);                         \
++              saveset = newset;                                       \
++              endset = newset + (setlen - 2);                         \
++      }                                                               \
++      set = addcmd(set, (a), (b), (c), (d));                          \
++} while (/*CONSTCOND*/0)
++
++#define       STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
++
++void *
++setmode(p)
++      const char *p;
++{
++      int perm, who;
++      char op, *ep;
++      BITCMD *set, *saveset, *endset;
++      sigset_t sigset, sigoset;
++      mode_t mask;
++      int equalopdone = 0;    /* pacify gcc */
++      int permXbits, setlen;
++
++      if (!*p)
++              return (NULL);
++
++      /*
++       * Get a copy of the mask for the permissions that are mask relative.
++       * Flip the bits, we want what's not set.  Since it's possible that
++       * the caller is opening files inside a signal handler, protect them
++       * as best we can.
++       */
++      sigfillset(&sigset);
++      (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
++      (void)umask(mask = umask(0));
++      mask = ~mask;
++      (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
++
++      setlen = SET_LEN + 2;
++      
++      if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
++              return (NULL);
++      saveset = set;
++      endset = set + (setlen - 2);
++
++      /*
++       * If an absolute number, get it and return; disallow non-octal digits
++       * or illegal bits.
++       */
++      if (isdigit((unsigned char)*p)) {
++              perm = (mode_t)strtol(p, &ep, 8);
++              if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
++                      free(saveset);
++                      return (NULL);
++              }
++              ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
++              set->cmd = 0;
++              return (saveset);
++      }
++
++      /*
++       * Build list of structures to set/clear/copy bits as described by
++       * each clause of the symbolic mode.
++       */
++      for (;;) {
++              /* First, find out which bits might be modified. */
++              for (who = 0;; ++p) {
++                      switch (*p) {
++                      case 'a':
++                              who |= STANDARD_BITS;
++                              break;
++                      case 'u':
++                              who |= S_ISUID|S_IRWXU;
++                              break;
++                      case 'g':
++                              who |= S_ISGID|S_IRWXG;
++                              break;
++                      case 'o':
++                              who |= S_IRWXO;
++                              break;
++                      default:
++                              goto getop;
++                      }
++              }
++
++getop:                if ((op = *p++) != '+' && op != '-' && op != '=') {
++                      free(saveset);
++                      return (NULL);
++              }
++              if (op == '=')
++                      equalopdone = 0;
++
++              who &= ~S_ISTXT;
++              for (perm = 0, permXbits = 0;; ++p) {
++                      switch (*p) {
++                      case 'r':
++                              perm |= S_IRUSR|S_IRGRP|S_IROTH;
++                              break;
++                      case 's':
++                              /*
++                               * If specific bits where requested and 
++                               * only "other" bits ignore set-id. 
++                               */
++                              if (who == 0 || (who & ~S_IRWXO))
++                                      perm |= S_ISUID|S_ISGID;
++                              break;
++                      case 't':
++                              /*
++                               * If specific bits where requested and 
++                               * only "other" bits ignore set-id. 
++                               */
++                              if (who == 0 || (who & ~S_IRWXO)) {
++                                      who |= S_ISTXT;
++                                      perm |= S_ISTXT;
++                              }
++                              break;
++                      case 'w':
++                              perm |= S_IWUSR|S_IWGRP|S_IWOTH;
++                              break;
++                      case 'X':
++                              permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
++                              break;
++                      case 'x':
++                              perm |= S_IXUSR|S_IXGRP|S_IXOTH;
++                              break;
++                      case 'u':
++                      case 'g':
++                      case 'o':
++                              /*
++                               * When ever we hit 'u', 'g', or 'o', we have
++                               * to flush out any partial mode that we have,
++                               * and then do the copying of the mode bits.
++                               */
++                              if (perm) {
++                                      ADDCMD(op, who, perm, mask);
++                                      perm = 0;
++                              }
++                              if (op == '=')
++                                      equalopdone = 1;
++                              if (op == '+' && permXbits) {
++                                      ADDCMD('X', who, permXbits, mask);
++                                      permXbits = 0;
++                              }
++                              ADDCMD(*p, who, op, mask);
++                              break;
++
++                      default:
++                              /*
++                               * Add any permissions that we haven't already
++                               * done.
++                               */
++                              if (perm || (op == '=' && !equalopdone)) {
++                                      if (op == '=')
++                                              equalopdone = 1;
++                                      ADDCMD(op, who, perm, mask);
++                                      perm = 0;
++                              }
++                              if (permXbits) {
++                                      ADDCMD('X', who, permXbits, mask);
++                                      permXbits = 0;
++                              }
++                              goto apply;
++                      }
++              }
++
++apply:                if (!*p)
++                      break;
++              if (*p != ',')
++                      goto getop;
++              ++p;
++      }
++      set->cmd = 0;
++#ifdef SETMODE_DEBUG
++      (void)printf("Before compress_mode()\n");
++      dumpmode(saveset);
++#endif
++      compress_mode(saveset);
++#ifdef SETMODE_DEBUG
++      (void)printf("After compress_mode()\n");
++      dumpmode(saveset);
++#endif
++      return (saveset);
++}
++
++static BITCMD *
++addcmd(set, op, who, oparg, mask)
++      BITCMD *set;
++      int oparg, who;
++      int op;
++      u_int mask;
++{
++
++      _DIAGASSERT(set != NULL);
++
++      switch (op) {
++      case '=':
++              set->cmd = '-';
++              set->bits = who ? who : STANDARD_BITS;
++              set++;
++
++              op = '+';
++              /* FALLTHROUGH */
++      case '+':
++      case '-':
++      case 'X':
++              set->cmd = op;
++              set->bits = (who ? who : mask) & oparg;
++              break;
++
++      case 'u':
++      case 'g':
++      case 'o':
++              set->cmd = op;
++              if (who) {
++                      set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
++                                  ((who & S_IRGRP) ? CMD2_GBITS : 0) |
++                                  ((who & S_IROTH) ? CMD2_OBITS : 0);
++                      set->bits = (mode_t)~0;
++              } else {
++                      set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
++                      set->bits = mask;
++              }
++      
++              if (oparg == '+')
++                      set->cmd2 |= CMD2_SET;
++              else if (oparg == '-')
++                      set->cmd2 |= CMD2_CLR;
++              else if (oparg == '=')
++                      set->cmd2 |= CMD2_SET|CMD2_CLR;
++              break;
++      }
++      return (set + 1);
++}
++
++#ifdef SETMODE_DEBUG
++static void
++dumpmode(set)
++      BITCMD *set;
++{
++
++      _DIAGASSERT(set != NULL);
++
++      for (; set->cmd; ++set)
++              (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
++                  set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
++                  set->cmd2 & CMD2_CLR ? " CLR" : "",
++                  set->cmd2 & CMD2_SET ? " SET" : "",
++                  set->cmd2 & CMD2_UBITS ? " UBITS" : "",
++                  set->cmd2 & CMD2_GBITS ? " GBITS" : "",
++                  set->cmd2 & CMD2_OBITS ? " OBITS" : "");
++}
++#endif
++
++/*
++ * Given an array of bitcmd structures, compress by compacting consecutive
++ * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
++ * 'g' and 'o' commands continue to be separate.  They could probably be 
++ * compacted, but it's not worth the effort.
++ */
++static void
++compress_mode(set)
++      BITCMD *set;
++{
++      BITCMD *nset;
++      int setbits, clrbits, Xbits, op;
++
++      _DIAGASSERT(set != NULL);
++
++      for (nset = set;;) {
++              /* Copy over any 'u', 'g' and 'o' commands. */
++              while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
++                      *set++ = *nset++;
++                      if (!op)
++                              return;
++              }
++
++              for (setbits = clrbits = Xbits = 0;; nset++) {
++                      if ((op = nset->cmd) == '-') {
++                              clrbits |= nset->bits;
++                              setbits &= ~nset->bits;
++                              Xbits &= ~nset->bits;
++                      } else if (op == '+') {
++                              setbits |= nset->bits;
++                              clrbits &= ~nset->bits;
++                              Xbits &= ~nset->bits;
++                      } else if (op == 'X')
++                              Xbits |= nset->bits & ~setbits;
++                      else
++                              break;
++              }
++              if (clrbits) {
++                      set->cmd = '-';
++                      set->cmd2 = 0;
++                      set->bits = clrbits;
++                      set++;
++              }
++              if (setbits) {
++                      set->cmd = '+';
++                      set->cmd2 = 0;
++                      set->bits = setbits;
++                      set++;
++              }
++              if (Xbits) {
++                      set->cmd = 'X';
++                      set->cmd2 = 0;
++                      set->bits = Xbits;
++                      set++;
++              }
++      }
++}
+
diff --git a/ash-syntax.patch b/ash-syntax.patch
new file mode 100644 (file)
index 0000000..43ce786
--- /dev/null
@@ -0,0 +1,270 @@
+diff -urN netbsd-sh/mksyntax.c ash-0.3.7.orig/mksyntax.c
+--- netbsd-sh/mksyntax.c       Fri Jan 12 17:50:38 2001
++++ ash-0.3.7.orig/mksyntax.c  Mon Apr 23 22:16:46 2001
+@@ -238,14 +238,14 @@
+       add("$", "CVAR");
+       add("}", "CENDVAR");
+       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+-      add("!*?[=~:/-", "CCTL");
++      add("!*?[=~:/-]", "CCTL");
+       print("dqsyntax");
+       init();
+       fputs("\n/* syntax table used when in single quotes */\n", cfile);
+       add("\n", "CNL");
+       add("'", "CENDQUOTE");
+       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+-      add("!*?[=~:/-", "CCTL");
++      add("!*?[=~:/-]\\", "CCTL");
+       print("sqsyntax");
+       init();
+       fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+diff -urN netbsd-sh/parser.c ash-0.3.7.orig/parser.c
+--- netbsd-sh/parser.c Fri Jan 12 17:50:39 2001
++++ ash-0.3.7.orig/parser.c    Mon Apr 23 22:16:46 2001
+@@ -221,6 +221,7 @@
+       union node *n1, *n2, *n3;
+       int t;
++      checkkwd = 1;
+       n1 = pipeline();
+       for (;;) {
+               if ((t = readtoken()) == TAND) {
+@@ -231,6 +232,7 @@
+                       tokpushback++;
+                       return n1;
+               }
++              checkkwd = 2;
+               n2 = pipeline();
+               n3 = (union node *)stalloc(sizeof (struct nbinary));
+               n3->type = t;
+@@ -250,9 +252,11 @@
+       negate = 0;
+       TRACE(("pipeline: entered\n"));
+-      while (readtoken() == TNOT)
++      if (readtoken() == TNOT) {
+               negate = !negate;
+-      tokpushback++;
++              checkkwd = 1;
++      } else
++              tokpushback++;
+       n1 = command();
+       if (readtoken() == TPIPE) {
+               pipenode = (union node *)stalloc(sizeof (struct npipe));
+@@ -264,6 +268,7 @@
+               do {
+                       prev = lp;
+                       lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
++                      checkkwd = 2;
+                       lp->n = command();
+                       prev->next = lp;
+               } while (readtoken() == TPIPE);
+@@ -288,9 +293,8 @@
+       union node *ap, **app;
+       union node *cp, **cpp;
+       union node *redir, **rpp;
+-      int t, negate = 0;
++      int t;
+-      checkkwd = 2;
+       redir = NULL;
+       n1 = NULL;
+       rpp = &redir;
+@@ -303,12 +307,6 @@
+       }
+       tokpushback++;
+-      while (readtoken() == TNOT) {
+-              TRACE(("command: TNOT recognized\n"));
+-              negate = !negate;
+-      }
+-      tokpushback++;
+-
+       switch (readtoken()) {
+       case TIF:
+               n1 = (union node *)stalloc(sizeof (struct nif));
+@@ -417,6 +415,8 @@
+               cpp = &n1->ncase.cases;
+               checkkwd = 2, readtoken();
+               do {
++                      if (lasttoken == TLP)
++                              readtoken();
+                       *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+                       cp->type = NCLIST;
+                       app = &cp->nclist.pattern;
+@@ -464,21 +464,22 @@
+               break;
+       /* Handle an empty command like other simple commands.  */
+       case TSEMI:
++      case TAND:
++      case TOR:
++      case TNL:
++      case TEOF:
++      case TRP:
++      case TBACKGND:
+               /*
+                * An empty command before a ; doesn't make much sense, and
+                * should certainly be disallowed in the case of `if ;'.
+                */
+               if (!redir)
+                       synexpect(-1);
+-      case TAND:
+-      case TOR:
+-      case TNL:
+-      case TEOF:
+       case TWORD:
+-      case TRP:
+               tokpushback++;
+               n1 = simplecmd(rpp, redir);
+-              goto checkneg;
++              return n1;
+       default:
+               synexpect(-1);
+               /* NOTREACHED */
+@@ -502,15 +503,7 @@
+               n1->nredir.redirect = redir;
+       }
+-checkneg:
+-      if (negate) {
+-              n2 = (union node *)stalloc(sizeof (struct nnot));
+-              n2->type = NNOT;
+-              n2->nnot.com = n1;
+-              return n2;
+-      }
+-      else
+-              return n1;
++      return n1;
+ }
+@@ -520,8 +513,7 @@
+       {
+       union node *args, **app;
+       union node **orig_rpp = rpp;
+-      union node *n = NULL, *n2;
+-      int negate = 0;
++      union node *n = NULL;
+       /* If we don't have any redirections already, then we must reset */
+       /* rpp to be the address of the local redir variable.  */
+@@ -537,12 +529,6 @@
+        */
+       orig_rpp = rpp;
+-      while (readtoken() == TNOT) {
+-              TRACE(("command: TNOT recognized\n"));
+-              negate = !negate;
+-      }
+-      tokpushback++;
+-
+       for (;;) {
+               if (readtoken() == TWORD) {
+                       n = (union node *)stalloc(sizeof (struct narg));
+@@ -565,8 +551,9 @@
+                               synerror("Bad function name");
+ #endif
+                       n->type = NDEFUN;
++                      checkkwd = 2;
+                       n->narg.next = command();
+-                      goto checkneg;
++                      return n;
+               } else {
+                       tokpushback++;
+                       break;
+@@ -579,16 +566,7 @@
+       n->ncmd.backgnd = 0;
+       n->ncmd.args = args;
+       n->ncmd.redirect = redir;
+-
+-checkneg:
+-      if (negate) {
+-              n2 = (union node *)stalloc(sizeof (struct nnot));
+-              n2->type = NNOT;
+-              n2->nnot.com = n;
+-              return n2;
+-      }
+-      else
+-              return n;
++      return n;
+ }
+ STATIC union node *
+@@ -743,7 +721,7 @@
+                       }
+               }
+ out:
+-              checkkwd = (t == TNOT) ? savecheckkwd : 0;
++              checkkwd = 0;
+       }
+ #ifdef DEBUG
+       if (!alreadyseen)
+@@ -882,6 +860,7 @@
+       int varnest;    /* levels of variables expansion */
+       int arinest;    /* levels of arithmetic expansion */
+       int parenlevel; /* levels of parens in arithmetic */
++      int dqvarnest;  /* levels of variables expansion within double quotes */
+       int oldstyle;
+       char const *prevsyntax; /* syntax before arithmetic */
+ #if __GNUC__
+@@ -892,6 +871,7 @@
+       (void) &varnest;
+       (void) &arinest;
+       (void) &parenlevel;
++      (void) &dqvarnest;
+       (void) &oldstyle;
+       (void) &prevsyntax;
+       (void) &syntax;
+@@ -906,6 +886,7 @@
+       varnest = 0;
+       arinest = 0;
+       parenlevel = 0;
++      dqvarnest = 0;
+       STARTSTACKSTR(out);
+       loop: { /* for each line, until end of word */
+@@ -938,7 +919,8 @@
+                               USTPUTC(c, out);
+                               break;
+                       case CCTL:
+-                              if (eofmark == NULL || dblquote)
++                              if ((eofmark == NULL || dblquote) &&
++                                  dqvarnest == 0)
+                                       USTPUTC(CTLESC, out);
+                               USTPUTC(c, out);
+                               break;
+@@ -983,7 +965,8 @@
+                                       if (arinest) {
+                                               syntax = ARISYNTAX;
+                                               dblquote = 0;
+-                                      } else if (eofmark == NULL) {
++                                      } else if (eofmark == NULL &&
++                                                 dqvarnest == 0) {
+                                               syntax = BASESYNTAX;
+                                               dblquote = 0;
+                                       }
+@@ -996,6 +979,9 @@
+                       case CENDVAR:   /* '}' */
+                               if (varnest > 0) {
+                                       varnest--;
++                                      if (dqvarnest > 0) {
++                                              dqvarnest--;
++                                      }
+                                       USTPUTC(CTLENDVAR, out);
+                               } else {
+                                       USTPUTC(c, out);
+@@ -1260,8 +1248,12 @@
+               if (dblquote || arinest)
+                       flags |= VSQUOTE;
+               *(stackblock() + typeloc) = subtype | flags;
+-              if (subtype != VSNORMAL)
++              if (subtype != VSNORMAL) {
+                       varnest++;
++                      if (dblquote) {
++                              dqvarnest++;
++                      }
++              }
+       }
+       goto parsesub_return;
+ }
+
diff --git a/ash-test.patch b/ash-test.patch
new file mode 100644 (file)
index 0000000..14c9f68
--- /dev/null
@@ -0,0 +1,588 @@
+diff -urN netbsd-sh/bltin/test.c ash-0.3.7.orig/bltin/test.c
+--- netbsd-sh/bltin/test.c     Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/bltin/test.c        Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,583 @@
++/*    $NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $       */
++
++/*
++ * test(1); version 7-like  --  author Erik Baalbergen
++ * modified by Eric Gisin to be used as built-in.
++ * modified by Arnold Robbins to add SVR3 compatibility
++ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
++ * modified by J.T. Conklin for NetBSD.
++ *
++ * This program is in the Public Domain.
++ */
++
++#include <sys/cdefs.h>
++#ifndef lint
++__RCSID("$NetBSD: test.c,v 1.22 2000/04/09 23:24:59 christos Exp $");
++#endif
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <ctype.h>
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <err.h>
++#ifdef __STDC__
++#include <stdarg.h>
++#else
++#include <varargs.h>
++#endif
++
++/* test(1) accepts the following grammar:
++      oexpr   ::= aexpr | aexpr "-o" oexpr ;
++      aexpr   ::= nexpr | nexpr "-a" aexpr ;
++      nexpr   ::= primary | "!" primary
++      primary ::= unary-operator operand
++              | operand binary-operator operand
++              | operand
++              | "(" oexpr ")"
++              ;
++      unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
++              "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
++
++      binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
++                      "-nt"|"-ot"|"-ef";
++      operand ::= <any legal UNIX file name>
++*/
++
++enum token {
++      EOI,
++      FILRD,
++      FILWR,
++      FILEX,
++      FILEXIST,
++      FILREG,
++      FILDIR,
++      FILCDEV,
++      FILBDEV,
++      FILFIFO,
++      FILSOCK,
++      FILSYM,
++      FILGZ,
++      FILTT,
++      FILSUID,
++      FILSGID,
++      FILSTCK,
++      FILNT,
++      FILOT,
++      FILEQ,
++      FILUID,
++      FILGID,
++      STREZ,
++      STRNZ,
++      STREQ,
++      STRNE,
++      STRLT,
++      STRGT,
++      INTEQ,
++      INTNE,
++      INTGE,
++      INTGT,
++      INTLE,
++      INTLT,
++      UNOT,
++      BAND,
++      BOR,
++      LPAREN,
++      RPAREN,
++      OPERAND
++};
++
++enum token_types {
++      UNOP,
++      BINOP,
++      BUNOP,
++      BBINOP,
++      PAREN
++};
++
++static struct t_op {
++      const char *op_text;
++      short op_num, op_type;
++} const ops [] = {
++      {"-r",  FILRD,  UNOP},
++      {"-w",  FILWR,  UNOP},
++      {"-x",  FILEX,  UNOP},
++      {"-e",  FILEXIST,UNOP},
++      {"-f",  FILREG, UNOP},
++      {"-d",  FILDIR, UNOP},
++      {"-c",  FILCDEV,UNOP},
++      {"-b",  FILBDEV,UNOP},
++      {"-p",  FILFIFO,UNOP},
++      {"-u",  FILSUID,UNOP},
++      {"-g",  FILSGID,UNOP},
++      {"-k",  FILSTCK,UNOP},
++      {"-s",  FILGZ,  UNOP},
++      {"-t",  FILTT,  UNOP},
++      {"-z",  STREZ,  UNOP},
++      {"-n",  STRNZ,  UNOP},
++      {"-h",  FILSYM, UNOP},          /* for backwards compat */
++      {"-O",  FILUID, UNOP},
++      {"-G",  FILGID, UNOP},
++      {"-L",  FILSYM, UNOP},
++      {"-S",  FILSOCK,UNOP},
++      {"=",   STREQ,  BINOP},
++      {"!=",  STRNE,  BINOP},
++      {"<",   STRLT,  BINOP},
++      {">",   STRGT,  BINOP},
++      {"-eq", INTEQ,  BINOP},
++      {"-ne", INTNE,  BINOP},
++      {"-ge", INTGE,  BINOP},
++      {"-gt", INTGT,  BINOP},
++      {"-le", INTLE,  BINOP},
++      {"-lt", INTLT,  BINOP},
++      {"-nt", FILNT,  BINOP},
++      {"-ot", FILOT,  BINOP},
++      {"-ef", FILEQ,  BINOP},
++      {"!",   UNOT,   BUNOP},
++      {"-a",  BAND,   BBINOP},
++      {"-o",  BOR,    BBINOP},
++      {"(",   LPAREN, PAREN},
++      {")",   RPAREN, PAREN},
++      {0,     0,      0}
++};
++
++static char **t_wp;
++static struct t_op const *t_wp_op;
++static gid_t *group_array = NULL;
++static int ngroups;
++
++static void syntax __P((const char *, const char *));
++static int oexpr __P((enum token));
++static int aexpr __P((enum token));
++static int nexpr __P((enum token));
++static int primary __P((enum token));
++static int binop __P((void));
++static int filstat __P((char *, enum token));
++static enum token t_lex __P((char *));
++static int isoperand __P((void));
++static int getn __P((const char *));
++static int newerf __P((const char *, const char *));
++static int olderf __P((const char *, const char *));
++static int equalf __P((const char *, const char *));
++static int test_eaccess();
++static int bash_group_member();
++static void initialize_group_array();
++
++#if defined(SHELL)
++extern void error __P((const char *, ...)) __attribute__((__noreturn__));
++#else
++static void error __P((const char *, ...)) __attribute__((__noreturn__));
++
++static void
++#ifdef __STDC__
++error(const char *msg, ...)
++#else
++error(va_alist)
++      va_dcl
++#endif
++{
++      va_list ap;
++#ifndef __STDC__
++      const char *msg;
++
++      va_start(ap);
++      msg = va_arg(ap, const char *);
++#else
++      va_start(ap, msg);
++#endif
++      verrx(2, msg, ap);
++      /*NOTREACHED*/
++      va_end(ap);
++}
++#endif
++
++#ifdef SHELL
++int testcmd __P((int, char **));
++
++int
++testcmd(argc, argv)
++      int argc;
++      char **argv;
++#else
++int main __P((int, char **));
++
++int
++main(argc, argv)
++      int argc;
++      char **argv;
++#endif
++{
++      int     res;
++
++
++      if (strcmp(argv[0], "[") == 0) {
++              if (strcmp(argv[--argc], "]"))
++                      error("missing ]");
++              argv[argc] = NULL;
++      }
++
++      if (argc < 2)
++              return 1;
++
++      t_wp = &argv[1];
++      res = !oexpr(t_lex(*t_wp));
++
++      if (*t_wp != NULL && *++t_wp != NULL)
++              syntax(*t_wp, "unexpected operator");
++
++      return res;
++}
++
++static void
++syntax(op, msg)
++      const char      *op;
++      const char      *msg;
++{
++      if (op && *op)
++              error("%s: %s", op, msg);
++      else
++              error("%s", msg);
++}
++
++static int
++oexpr(n)
++      enum token n;
++{
++      int res;
++
++      res = aexpr(n);
++      if (t_lex(*++t_wp) == BOR)
++              return oexpr(t_lex(*++t_wp)) || res;
++      t_wp--;
++      return res;
++}
++
++static int
++aexpr(n)
++      enum token n;
++{
++      int res;
++
++      res = nexpr(n);
++      if (t_lex(*++t_wp) == BAND)
++              return aexpr(t_lex(*++t_wp)) && res;
++      t_wp--;
++      return res;
++}
++
++static int
++nexpr(n)
++      enum token n;                   /* token */
++{
++      if (n == UNOT)
++              return !nexpr(t_lex(*++t_wp));
++      return primary(n);
++}
++
++static int
++primary(n)
++      enum token n;
++{
++      enum token nn;
++      int res;
++
++      if (n == EOI)
++              return 0;               /* missing expression */
++      if (n == LPAREN) {
++              if ((nn = t_lex(*++t_wp)) == RPAREN)
++                      return 0;       /* missing expression */
++              res = oexpr(nn);
++              if (t_lex(*++t_wp) != RPAREN)
++                      syntax(NULL, "closing paren expected");
++              return res;
++      }
++      if (t_wp_op && t_wp_op->op_type == UNOP) {
++              /* unary expression */
++              if (*++t_wp == NULL)
++                      syntax(t_wp_op->op_text, "argument expected");
++              switch (n) {
++              case STREZ:
++                      return strlen(*t_wp) == 0;
++              case STRNZ:
++                      return strlen(*t_wp) != 0;
++              case FILTT:
++                      return isatty(getn(*t_wp));
++              default:
++                      return filstat(*t_wp, n);
++              }
++      }
++
++      if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
++              return binop();
++      }         
++
++      return strlen(*t_wp) > 0;
++}
++
++static int
++binop()
++{
++      const char *opnd1, *opnd2;
++      struct t_op const *op;
++
++      opnd1 = *t_wp;
++      (void) t_lex(*++t_wp);
++      op = t_wp_op;
++
++      if ((opnd2 = *++t_wp) == (char *)0)
++              syntax(op->op_text, "argument expected");
++              
++      switch (op->op_num) {
++      case STREQ:
++              return strcmp(opnd1, opnd2) == 0;
++      case STRNE:
++              return strcmp(opnd1, opnd2) != 0;
++      case STRLT:
++              return strcmp(opnd1, opnd2) < 0;
++      case STRGT:
++              return strcmp(opnd1, opnd2) > 0;
++      case INTEQ:
++              return getn(opnd1) == getn(opnd2);
++      case INTNE:
++              return getn(opnd1) != getn(opnd2);
++      case INTGE:
++              return getn(opnd1) >= getn(opnd2);
++      case INTGT:
++              return getn(opnd1) > getn(opnd2);
++      case INTLE:
++              return getn(opnd1) <= getn(opnd2);
++      case INTLT:
++              return getn(opnd1) < getn(opnd2);
++      case FILNT:
++              return newerf (opnd1, opnd2);
++      case FILOT:
++              return olderf (opnd1, opnd2);
++      case FILEQ:
++              return equalf (opnd1, opnd2);
++      default:
++              abort();
++              /* NOTREACHED */
++      }
++}
++
++static int
++filstat(nm, mode)
++      char *nm;
++      enum token mode;
++{
++      struct stat s;
++
++      if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
++              return 0;
++
++      switch (mode) {
++      case FILRD:
++              return test_eaccess(nm, R_OK) == 0;
++      case FILWR:
++              return test_eaccess(nm, W_OK) == 0;
++      case FILEX:
++              return test_eaccess(nm, X_OK) == 0;
++      case FILEXIST:
++              return 1;
++      case FILREG:
++              return S_ISREG(s.st_mode);
++      case FILDIR:
++              return S_ISDIR(s.st_mode);
++      case FILCDEV:
++              return S_ISCHR(s.st_mode);
++      case FILBDEV:
++              return S_ISBLK(s.st_mode);
++      case FILFIFO:
++              return S_ISFIFO(s.st_mode);
++      case FILSOCK:
++              return S_ISSOCK(s.st_mode);
++      case FILSYM:
++              return S_ISLNK(s.st_mode);
++      case FILSUID:
++              return (s.st_mode & S_ISUID) != 0;
++      case FILSGID:
++              return (s.st_mode & S_ISGID) != 0;
++      case FILSTCK:
++              return (s.st_mode & S_ISVTX) != 0;
++      case FILGZ:
++              return s.st_size > (off_t)0;
++      case FILUID:
++              return s.st_uid == geteuid();
++      case FILGID:
++              return s.st_gid == getegid();
++      default:
++              return 1;
++      }
++}
++
++static enum token
++t_lex(s)
++      char *s;
++{
++      struct t_op const *op = ops;
++
++      if (s == 0) {
++              t_wp_op = (struct t_op *)0;
++              return EOI;
++      }
++      while (op->op_text) {
++              if (strcmp(s, op->op_text) == 0) {
++                      if ((op->op_type == UNOP && isoperand()) ||
++                          (op->op_num == LPAREN && *(t_wp+1) == 0))
++                              break;
++                      t_wp_op = op;
++                      return op->op_num;
++              }
++              op++;
++      }
++      t_wp_op = (struct t_op *)0;
++      return OPERAND;
++}
++
++static int
++isoperand()
++{
++      struct t_op const *op = ops;
++      char *s;
++      char *t;
++
++      if ((s  = *(t_wp+1)) == 0)
++              return 1;
++      if ((t = *(t_wp+2)) == 0)
++              return 0;
++      while (op->op_text) {
++              if (strcmp(s, op->op_text) == 0)
++                      return op->op_type == BINOP &&
++                          (t[0] != ')' || t[1] != '\0'); 
++              op++;
++      }
++      return 0;
++}
++
++/* atoi with error detection */
++static int
++getn(s)
++      const char *s;
++{
++      char *p;
++      long r;
++
++      errno = 0;
++      r = strtol(s, &p, 10);
++
++      if (errno != 0)
++            error("%s: out of range", s);
++
++      while (isspace((unsigned char)*p))
++            p++;
++      
++      if (*p)
++            error("%s: bad number", s);
++
++      return (int) r;
++}
++
++static int
++newerf (f1, f2)
++const char *f1, *f2;
++{
++      struct stat b1, b2;
++
++      return (stat (f1, &b1) == 0 &&
++              stat (f2, &b2) == 0 &&
++              b1.st_mtime > b2.st_mtime);
++}
++
++static int
++olderf (f1, f2)
++const char *f1, *f2;
++{
++      struct stat b1, b2;
++
++      return (stat (f1, &b1) == 0 &&
++              stat (f2, &b2) == 0 &&
++              b1.st_mtime < b2.st_mtime);
++}
++
++static int
++equalf (f1, f2)
++const char *f1, *f2;
++{
++      struct stat b1, b2;
++
++      return (stat (f1, &b1) == 0 &&
++              stat (f2, &b2) == 0 &&
++              b1.st_dev == b2.st_dev &&
++              b1.st_ino == b2.st_ino);
++}
++
++/* Do the same thing access(2) does, but use the effective uid and gid,
++   and don't make the mistake of telling root that any file is
++   executable. */
++static int
++test_eaccess (path, mode)
++char *path;
++int mode;
++{
++      struct stat st;
++      int euid = geteuid();
++
++      if (stat (path, &st) < 0)
++              return (-1);
++
++      if (euid == 0) {
++              /* Root can read or write any file. */
++              if (mode != X_OK)
++              return (0);
++
++              /* Root can execute any file that has any one of the execute
++                 bits set. */
++              if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
++                      return (0);
++      }
++
++      if (st.st_uid == euid)          /* owner */
++              mode <<= 6;
++      else if (bash_group_member (st.st_gid))
++              mode <<= 3;
++
++      if (st.st_mode & mode)
++              return (0);
++
++      return (-1);
++}
++
++static void
++initialize_group_array ()
++{
++      ngroups = getgroups(0, NULL);
++      group_array = malloc(ngroups * sizeof(gid_t));
++      if (!group_array)
++              error(strerror(ENOMEM));
++      getgroups(ngroups, group_array);
++}
++
++/* Return non-zero if GID is one that we have in our groups list. */
++static int
++bash_group_member (gid)
++gid_t gid;
++{
++      register int i;
++
++      /* Short-circuit if possible, maybe saving a call to getgroups(). */
++      if (gid == getgid() || gid == getegid())
++              return (1);
++
++      if (ngroups == 0)
++              initialize_group_array ();
++
++      /* Search through the list looking for GID. */
++      for (i = 0; i < ngroups; i++)
++              if (gid == group_array[i])
++                      return (1);
++
++      return (0);
++}
+
diff --git a/ash-times.patch b/ash-times.patch
new file mode 100644 (file)
index 0000000..f271800
--- /dev/null
@@ -0,0 +1,42 @@
+diff -urN netbsd-sh/bltin/times.c ash-0.3.7.orig/bltin/times.c
+--- netbsd-sh/bltin/times.c    Thu Jan  1 01:00:00 1970
++++ ash-0.3.7.orig/bltin/times.c       Mon Apr 23 22:16:46 2001
+@@ -0,0 +1,30 @@
++#ifdef _GNU_SOURCE
++/*
++ * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
++ * This file contains code for the times builtin.
++ * $Id$
++ */
++
++#include <stdio.h>
++#include <sys/times.h>
++#include <unistd.h>
++
++#define main timescmd
++
++int main() {
++      struct tms buf;
++      long int clk_tck = sysconf(_SC_CLK_TCK);
++
++      times(&buf);
++      printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
++             (int) (buf.tms_utime / clk_tck / 60),
++             ((double) buf.tms_utime) / clk_tck,
++             (int) (buf.tms_stime / clk_tck / 60),
++             ((double) buf.tms_stime) / clk_tck,
++             (int) (buf.tms_cutime / clk_tck / 60),
++             ((double) buf.tms_cutime) / clk_tck,
++             (int) (buf.tms_cstime / clk_tck / 60),
++             ((double) buf.tms_cstime) / clk_tck);
++      return 0;
++}
++#endif        /* _GNU_SOURCE */
+diff -urN netbsd-sh/builtins.def ash-0.3.7.orig/builtins.def
+--- netbsd-sh/builtins.def     Mon Apr 10 13:02:58 2000
++++ ash-0.3.7.orig/builtins.def        Mon Apr 23 22:16:46 2001
+@@ -91,3 +93,4 @@
+ aliascmd      alias
+ ulimitcmd     ulimit
+ testcmd               test [
++timescmd      times
This page took 0.49165 seconds and 4 git commands to generate.