Logo Search packages:      
Sourcecode: fdclone version File versions  Download package

builtin.c

/*
 *    builtin.c
 *
 *    Builtin Command
 */

#include "fd.h"
#include "func.h"
#include "funcno.h"
#include "kanji.h"

#ifdef      _NOORIGSHELL
#define     RET_SUCCESS 0
#define     RET_NOTICE  255
#else
#include "system.h"
#endif

#ifndef     _NOARCHIVE
extern launchtable launchlist[];
extern int maxlaunch;
extern archivetable archivelist[];
extern int maxarchive;
# ifndef    _NOBROWSE
extern char **browsevar;
# endif
#endif
extern char *macrolist[];
extern int maxmacro;
extern bindtable bindlist[];
extern strtable keyidentlist[];
extern functable funclist[];
extern char **history[];
extern short histsize[];
extern short histno[];
extern char *helpindex[];
#ifndef     _NOCUSTOMIZE
extern char **orighelpindex;
#endif
extern int fd_restricted;
#if   FD >= 2
extern char *progpath;
extern char *progname;
extern char *promptstr;
extern int lcmdline;
#endif
extern int internal_status;
#ifdef      _NOORIGSHELL
extern char **environ2;
extern aliastable aliaslist[];
extern int maxalias;
extern userfunctable userfunclist[];
extern int maxuserfunc;
extern int win_x;
extern int win_y;
extern int hideclock;
#endif
extern int inruncom;
#ifndef     _NOKANJICONV
extern int unicodebuffer;
#endif

static VOID NEAR builtinerror __P_((char *[], char *, int));
#ifdef      _NOORIGSHELL
static VOID NEAR hitkey __P_((int));
#else
#define     hitkey(n)
#endif
static VOID NEAR fputsmeta __P_((char *, FILE *));
#ifndef     _NOARCHIVE
# if  FD >= 2
static int NEAR getlaunchopt __P_((int, char *[], char *, launchtable *));
# endif
static int NEAR setlaunch __P_((int, char *[]));
static int NEAR setarch __P_((int, char *[]));
static int NEAR printlaunch __P_((int, char *[]));
static int NEAR printarch __P_((int, char *[]));
# ifndef    _NOBROWSE
static char **NEAR readargv __P_((char **, char **));
static int NEAR custbrowse __P_((int, char *[]));
# endif
#endif
static int NEAR getmacro __P_((char *));
static int NEAR setkeybind __P_((int, char *[]));
static int NEAR printbind __P_((int, char *[]));
#ifdef      _USEDOSEMU
static int NEAR _setdrive __P_((int, char *[], int));
static int NEAR setdrive __P_((int, char *[]));
static int NEAR unsetdrive __P_((int, char *[]));
static int NEAR printdrive __P_((int, char *[]));
#endif
#ifndef     _NOKEYMAP
static int NEAR setkeymap __P_((int, char *[]));
static int NEAR keytest __P_((int, char *[]));
#endif
static int NEAR printhist __P_((int, char *[]));
#if   FD >= 2
# ifndef    NOPOSIXUTIL
static int NEAR fixcommand __P_((int, char *[]));
# endif
static VOID NEAR voidmd5 __P_((u_long, u_long, u_long, u_long));
static VOID NEAR calcmd5 __P_((u_long [], u_long []));
static int NEAR printmd5 __P_((char *, FILE *));
static int NEAR md5sum __P_((int, char *[]));
static int NEAR evalmacro __P_((int, char *[]));
# ifndef    _NOKANJICONV
static int NEAR kconv __P_((int, char *[]));
# endif
static int NEAR getinputstr __P_((int, char *[]));
static int NEAR getyesno __P_((int, char *[]));
#endif      /* FD >= 2 */
#ifdef      _NOORIGSHELL
static int NEAR printenv __P_((int, char *[]));
static int NEAR setalias __P_((int, char *[]));
static int NEAR unalias __P_((int, char *[]));
static int NEAR checkuserfunc __P_((int, char *[]));
static int NEAR setuserfunc __P_((int, char *[]));
static int NEAR exportenv __P_((int, char *[]));
static int NEAR dochdir __P_((int, char *[]));
static int NEAR loadsource __P_((int, char *[]));
#endif      /* _NOORIGSHELL */

#if   FD >= 2
#define     BINDCOMMENT ':'
#define     DRIVESEP    ' '
#define     ALIASSEP    '='
#define     FUNCNAME    0
#else
#define     BINDCOMMENT ';'
#define     DRIVESEP    ','
#define     ALIASSEP    '\t'
#define     FUNCNAME    1
#endif

static CONST char *builtinerrstr[] = {
      "",
#define     ER_FEWMANYARG     1
      "Too few or many arguments",
#define     ER_OUTOFLIMIT     2
      "Out of limits",
#define     ER_NOENTRY  3
      "No such entry",
#define     ER_SYNTAXERR      4
      "Syntax error",
#define     ER_EXIST    5
      "Entry already exists",
#define     ER_INVALDEV 6
      "Invalid device",
#define     ER_EVENTNOFOUND   7
      "Event not found",
#define     ER_UNKNOWNOPT     8
      "Unknown option",
#define     ER_NOARGSPEC      9
      "No argument is specified",
#define     ER_NOTINSHELL     10
      "Cannot execute in shell mode",
#define     ER_NOTINRUNCOM    11
      "Cannot execute in startup file",
#define     ER_NOTRECURSE     12
      "Cannot execute recursively",
#define     ER_NOTDUMBTERM    13
      "Cannot execute on dumb term",
};
#define     BUILTINERRSIZ     ((int)(sizeof(builtinerrstr) / sizeof(char *)))

static CONST builtintable builtinlist[] = {
#ifndef     _NOARCHIVE
      {setlaunch, BL_LAUNCH},
      {setarch,   BL_ARCH},
      {printlaunch,     BL_PLAUNCH},
      {printarch, BL_PARCH},
# ifndef    _NOBROWSE
      {custbrowse,      BL_BROWSE},
# endif
#endif
      {setkeybind,      BL_BIND},
      {printbind, BL_PBIND},
#ifdef      _USEDOSEMU
      {setdrive,  BL_SDRIVE},
      {unsetdrive,      BL_UDRIVE},
      {printdrive,      BL_PDRIVE},
#endif
#ifndef     _NOKEYMAP
      {setkeymap, BL_KEYMAP},
      {keytest,   BL_GETKEY},
#endif
      {printhist, BL_HISTORY},
#if   FD >= 2
# ifndef    NOPOSIXUTIL
      {fixcommand,      BL_FC},
# endif
      {md5sum,    BL_CHECKID},
      {evalmacro, BL_EVALMACRO},
# ifndef    _NOKANJICONV
      {kconv,           BL_KCONV},
# endif
      {getinputstr,     BL_READLINE},
      {getyesno,  BL_YESNO},
#endif      /* FD >= 2 */
#ifdef      _NOORIGSHELL
# if  FD >= 2
      {printenv,  BL_SET},
# else
      {printenv,  BL_PENV},
# endif
      {setalias,  BL_ALIAS},
      {unalias,   BL_UALIAS},
# if  FD < 2
      {setuserfunc,     BL_FUNCTION},
# endif
      {exportenv, BL_EXPORT},
# if  MSDOS || (FD < 2)
      {dochdir,   BL_CHDIR},
# endif
      {dochdir,   BL_CD},
      {loadsource,      BL_SOURCE},
# if  FD >= 2
      {loadsource,      BL_DOT},
# endif
#endif      /* _NOORIGSHELL */
};
#define     BUILTINSIZ  ((int)(sizeof(builtinlist) / sizeof(builtintable)))


static VOID NEAR builtinerror(argv, s, n)
char *argv[], *s;
int n;
{
      int duperrno;

      duperrno = errno;
      if (n >= BUILTINERRSIZ || (n < 0 && !errno)) return;
      if (argv && argv[0]) fprintf2(stderr, "%k: ", argv[0]);
      if (s) fprintf2(stderr, "%k: ", s);
      fprintf2(stderr, "%s.",
            (n >= 0) ? builtinerrstr[n] : strerror2(duperrno));
      fputnl(stderr);
}

#ifdef      _NOORIGSHELL
static VOID NEAR hitkey(init)
int init;
{
      static int n = 0;

      if (init) {
            if (init < 0) n = init;
            else if (init == 1) n = 0;
            else if (init == 2) {
                  if (n >= 0) n = 1;
            }
            else if (n > 0 && n < n_line) {
                  hideclock = 1;
                  warning(0, HITKY_K);
            }
            return;
      }

      if (n <= 0) return;

      if (n >= n_line) n = 1;
      if (++n >= n_line) {
            fflush(stdout);
            ttyiomode(1);
            win_x = 0;
            win_y = n_line - 1;
            hideclock = 1;
            warning(0, HITKY_K);
            stdiomode();
      }
}
#endif      /* _NOORIGSHELL */

static VOID NEAR fputsmeta(arg, fp)
char *arg;
FILE *fp;
{
      char *cp;

      if (!*arg) fputs("\"\"", fp);
      else {
            cp = killmeta(arg);
            kanjifputs(cp, fp);
            free(cp);
      }
}

#ifndef     _NOARCHIVE
# if  FD >= 2
static int NEAR getlaunchopt(n, argv, opts, lp)
int n;
char *argv[], *opts;
launchtable *lp;
{
      char *cp;
      int i, c;

      if (argv[n][0] != '-') return(0);
      c = argv[n][1];
      if (!c || c == '-') return(++n);
      else if (!strchr2(opts, c)) {
            lp -> topskip = ER_UNKNOWNOPT;
            lp -> bottomskip = n;
            return(-1);
      }

      if (argv[n][2]) cp = &(argv[n][2]);
      else if (argv[n + 1]) cp = argv[++n];
      else {
            lp -> topskip = ER_NOARGSPEC;
            lp -> bottomskip = n;
            return(-1);
      }

      if (c == 'f') {
            i = countvar(lp -> format);
            lp -> format = (char **)realloc2(lp -> format,
                  sizeof(char *) * (i + 2));
            lp -> format[i++] = strdup2(cp);
            lp -> format[i] = NULL;
      }
      else if (c == 'i') {
            i = countvar(lp -> lignore);
            lp -> lignore = (char **)realloc2(lp -> lignore,
                  sizeof(char *) * (i + 2));
            lp -> lignore[i++] = strdup2(cp);
            lp -> lignore[i] = NULL;
      }
      else if (c == 'e') {
            i = countvar(lp -> lerror);
            lp -> lerror = (char **)realloc2(lp -> lerror,
                  sizeof(char *) * (i + 2));
            lp -> lerror[i++] = strdup2(cp);
            lp -> lerror[i] = NULL;
      }
      else if (c == 't' || c == 'b') {
            if ((i = atoi2(cp)) < 0) {
                  lp -> topskip = ER_SYNTAXERR;
                  lp -> bottomskip = n;
                  return(-1);
            }
            if (c == 't') lp -> topskip = i;
            else lp -> bottomskip = i;
      }
      else if (c == 'p') {
            if (lp -> ext) free (lp -> ext);
            lp -> ext = strdup2(cp);
      }
      else {
            if (!strcmp(cp, "loop"))
                  i = (c == 'd') ? LF_DIRLOOP : LF_FILELOOP;
            else if (!strcmp(cp, "noprep"))
                  i = (c == 'd') ? LF_DIRNOPREP : LF_FILENOPREP;
            else {
                  lp -> topskip = ER_SYNTAXERR;
                  lp -> bottomskip = n;
                  return(-1);
            }
            lp -> flags |= i;
      }
      n++;

      return(n);
}
# endif

VOID freelaunch(lp)
launchtable *lp;
{
      if (lp -> ext) free(lp -> ext);
      if (lp -> comm) free(lp -> comm);
# if  FD >= 2
      freevar(lp -> format);
      freevar(lp -> lignore);
      freevar(lp -> lerror);
# endif
}

int searchlaunch(list, max, lp)
launchtable *list;
int max;
launchtable *lp;
{
      int i, n;

      for (i = 0; i < max; i++) {
            n = extcmp(lp -> ext, lp -> flags,
                  list[i].ext, list[i].flags, 1);
            if (!n) break;
      }
      return(i);
}

int parselaunch(argc, argv, lp)
int argc;
char *argv[];
launchtable *lp;
{
# if  FD >= 2
      int j, opt, err;
# else
      char *cp, *tmp;
      u_char c;
      int ch;
# endif
      int i, n;

      lp -> comm = NULL;
# if  FD >= 2
      lp -> format = lp -> lignore = lp -> lerror = NULL;
# endif

      if (argc <= 1) {
            lp -> topskip = ER_FEWMANYARG;
            lp -> bottomskip = 0;
            return(-1);
      }

      lp -> ext = getext(argv[1], &(lp -> flags));

      n = searchlaunch(launchlist, maxlaunch, lp);
      if (n >= MAXLAUNCHTABLE) {
            free(lp -> ext);
            lp -> topskip = ER_OUTOFLIMIT;
            lp -> bottomskip = 0;
            return(-1);
      }

      if (argc < 3) return(n);

# if  FD >= 2
      lp -> topskip = lp -> bottomskip = 0;
      opt = err = 0;
      for (i = 2; i < argc; i++) {
            j = getlaunchopt(i, argv, "fietb", lp);
            if (!j) {
                  if (lp -> comm) break;
                  lp -> comm = strdup2(argv[i]);
            }
            else if (j > 0) {
                  opt++;
                  i = j - 1;
            }
            else {
                  err++;
                  break;
            }
      }

      if (err);
      else if (!(lp -> comm)) {
            lp -> topskip = ER_FEWMANYARG;
            lp -> bottomskip = 0;
            err++;
      }
      else if (i + 3 < argc) {
            lp -> topskip = ER_FEWMANYARG;
            lp -> bottomskip = i + 3;
            err++;
      }
      else if (i < argc && opt) {
            lp -> topskip = ER_FEWMANYARG;
            lp -> bottomskip = i;
            err++;
      }
      if (err) {
            freelaunch(lp);
            return(-1);
      }

      if (i < argc) {
            lp -> format = (char **)malloc2(sizeof(char *) * 2);
            lp -> format[0] = strdup2(argv[i]);
            lp -> format[1] = NULL;
      }

      if (i + 1 >= argc) /*EMPTY*/;
      else if ((j = atoi2(argv[i + 1])) >= 0) lp -> topskip = j;
      else {
            lp -> topskip = ER_SYNTAXERR;
            lp -> bottomskip = i + 1;
            freelaunch(lp);
            return(-1);
      }

      if (i + 2 >= argc) /*EMPTY*/;
      else if ((j = atoi2(argv[i + 2])) >= 0) lp -> bottomskip = j;
      else {
            lp -> topskip = ER_SYNTAXERR;
            lp -> bottomskip = i + 2;
            freelaunch(lp);
            return(-1);
      }

# else      /* FD < 2 */
      lp -> comm = strdup2(argv[2]);
      if (argc <= 3) lp -> topskip = lp -> bottomskip = 255;
      else {
            cp = tmp = catvar(&(argv[3]), '\0');
            if (!(cp = sscanf2(cp, "%Cu,", &c))) {
                  lp -> topskip = ER_SYNTAXERR;
                  lp -> bottomskip = (u_char)-1;
                  free(lp -> ext);
                  free(lp -> comm);
                  lp -> ext = tmp;
                  return(-1);
            }
            lp -> topskip = c;
            if (!(cp = sscanf2(cp, "%Cu", &c))) {
                  lp -> topskip = ER_SYNTAXERR;
                  lp -> bottomskip = (u_char)-1;
                  free(lp -> ext);
                  free(lp -> comm);
                  lp -> ext = tmp;
                  return(-1);
            }
            lp -> bottomskip = c;

            ch = ':';
            for (i = 0; i < MAXLAUNCHFIELD; i++) {
                  cp = getrange(cp, ch, &(lp -> field[i]),
                        &(lp -> delim[i]), &(lp -> width[i]));
                  if (!cp) {
                        lp -> topskip = ER_SYNTAXERR;
                        lp -> bottomskip = (u_char)-1;
                        free(lp -> ext);
                        free(lp -> comm);
                        lp -> ext = tmp;
                        return(-1);
                  }
                  ch = ',';
            }

            ch = ':';
            for (i = 0; i < MAXLAUNCHSEP; i++) {
                  if (*cp != ch) break;
                  if (!(cp = sscanf2(++cp, "%Cu", &c))) {
                        lp -> topskip = ER_SYNTAXERR;
                        lp -> bottomskip = (u_char)-1;
                        free(lp -> ext);
                        free(lp -> comm);
                        lp -> ext = tmp;
                        return(-1);
                  }
                  lp -> sep[i] = (c) ? c - 1 : 255;
                  ch = ',';
            }
            for (; i < MAXLAUNCHSEP; i++) lp -> sep[i] = 255;

            if (!*cp) lp -> lines = 1;
            else {
                  if (!sscanf2(cp, ":%Cu%$", &c)) {
                        lp -> topskip = ER_SYNTAXERR;
                        lp -> bottomskip = (u_char)-1;
                        free(lp -> ext);
                        free(lp -> comm);
                        lp -> ext = tmp;
                        return(-1);
                  }
                  lp -> lines = (c) ? c : 1;
            }

            free(tmp);
      }
# endif     /* FD < 2 */

      return(n);
}

static int NEAR setlaunch(argc, argv)
int argc;
char *argv[];
{
      launchtable launch;
      int n;

      if ((n = parselaunch(argc, argv, &launch)) < 0) {
# if  FD < 2
            if (launch.bottomskip == (u_char)-1) {
                  builtinerror(argv, launch.ext, launch.topskip);
                  free(launch.ext);
            }
            else
# endif
            builtinerror(argv,
                  (launch.bottomskip) ? argv[launch.bottomskip] : NULL,
                  launch.topskip);
            return(-1);
      }

      if (!(launch.comm)) {
            free(launch.ext);
            if (n >= maxlaunch) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }

            freelaunch(&(launchlist[n]));
            maxlaunch--;
            for (; n < maxlaunch; n++)
                  memcpy((char *)&(launchlist[n]),
                        (char *)&(launchlist[n + 1]),
                        sizeof(launchtable));
            return(0);
      }

      if (n >= maxlaunch) maxlaunch++;
      else freelaunch(&(launchlist[n]));
      memcpy((char *)&(launchlist[n]), (char *)&launch, sizeof(launch));
      return(0);
}

VOID freearch(ap)
archivetable *ap;
{
      if (ap -> ext) free(ap -> ext);
      if (ap -> p_comm) free(ap -> p_comm);
      if (ap -> u_comm) free(ap -> u_comm);
}

int searcharch(list, max, ap)
archivetable *list;
int max;
archivetable *ap;
{
      int i, n;

      for (i = 0; i < max; i++) {
            n = extcmp(ap -> ext, ap -> flags,
                  list[i].ext, list[i].flags, 1);
            if (!n) break;
      }
      return(i);
}

int parsearch(argc, argv, ap)
int argc;
char *argv[];
archivetable *ap;
{
      int n;

      ap -> p_comm = ap -> u_comm = NULL;

      if (argc <= 1 || argc >= 5) {
            ap -> flags = ER_FEWMANYARG;
            ap -> ext = NULL;
            return(-1);
      }

      ap -> ext = getext(argv[1], &(ap -> flags));

      n = searcharch(archivelist, maxarchive, ap);
      if (n >= MAXARCHIVETABLE) {
            free(ap -> ext);
            ap -> flags = ER_OUTOFLIMIT;
            ap -> ext = NULL;
            return(-1);
      }

      if (argc < 3) return(n);

      if (argv[2][0]) ap -> p_comm = strdup2(argv[2]);
      if (argc > 3 && argv[3][0]) ap -> u_comm = strdup2(argv[3]);
      if (!(ap -> p_comm) && !(ap -> u_comm)) {
            free(ap -> ext);
            ap -> flags = ER_FEWMANYARG;
            ap -> ext = NULL;
            return(-1);
      }

      return(n);
}

static int NEAR setarch(argc, argv)
int argc;
char *argv[];
{
      archivetable arch;
      int n;

      if ((n = parsearch(argc, argv, &arch)) < 0) {
            builtinerror(argv, arch.ext, arch.flags);
            return(-1);
      }

      if (!(arch.p_comm) && !(arch.u_comm)) {
            free(arch.ext);
            if (n >= maxarchive) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }

            freearch(&(archivelist[n]));
            maxarchive--;
            for (; n < maxarchive; n++)
                  memcpy((char *)&(archivelist[n]),
                        (char *)&(archivelist[n + 1]),
                        sizeof(archivetable));
            return(0);
      }

      if (n >= maxarchive) maxarchive++;
      else freearch(&(archivelist[n]));
      memcpy((char *)&(archivelist[n]), (char *)&arch, sizeof(arch));
      return(0);
}

/*ARGSUSED*/
VOID printlaunchcomm(list, n, isset, omit, fp)
launchtable *list;
int n, isset, omit;
FILE *fp;
{
      int i, ch;

      fprintf2(fp, "%s ", BL_LAUNCH);
# if  FD >= 2
      if (list[n].flags & LF_IGNORECASE) fputc('/', fp);
# endif
      fputsmeta(&(list[n].ext[1]), fp);
      if (isset) for (;;) {
            fputc('\t', fp);

            fputsmeta(list[n].comm, fp);
# if  FD >= 2
            if (!list[n].format) break;

            ch = 0;
            for (i = 0; list[n].format[i]; i++) {
                  if (i) {
                        fputs(" \\\n", fp);
                        ch++;
                  }
                  fputs("\t-f ", fp);
                  fputsmeta(list[n].format[i], fp);
            }
            if (list[n].lignore) for (i = 0; list[n].lignore[i]; i++) {
                  fputs(" \\\n\t-i ", fp);
                  ch++;
                  fputsmeta(list[n].lignore[i], fp);
            }
            if (list[n].lerror) for (i = 0; list[n].lerror[i]; i++) {
                  fputs(" \\\n\t-e ", fp);
                  ch++;
                  fputsmeta(list[n].lerror[i], fp);
            }
            if (!list[n].topskip && !list[n].bottomskip) break;

            if (list[n].topskip) {
                  if (ch) fputs(" \\\n", fp);
                  fprintf2(fp, "\t-t %d", (int)(list[n].topskip));
            }
            if (list[n].bottomskip) {
                  if (list[n].topskip) fputc(' ', fp);
                  else if (ch) fputs(" \\\n\t", fp);
                  else fputc('\t', fp);
                  fprintf2(fp, "-b %d", (int)(list[n].bottomskip));
            }
# else      /* FD < 2 */
            if (list[n].topskip >= 255) break;
            if (omit) {
                  fputs("\t(Arch)", fp);
                  break;
            }
            fprintf2(fp, "\t%d,%d",
                  (int)(list[n].topskip), (int)(list[n].bottomskip));
            ch = ':';
            for (i = 0; i < MAXLAUNCHFIELD; i++) {
                  fputc(ch, fp);
                  if (list[n].field[i] >= 255) fputc('0', fp);
                  else fprintf2(fp, "%d", (int)(list[n].field[i]) + 1);
                  if (list[n].delim[i] >= 128)
                        fprintf2(fp, "[%d]",
                              (int)(list[n].delim[i]) - 128 + 1);
                  else if (list[n].delim[i])
                        fprintf2(fp, "'%c'", (int)(list[n].delim[i]));
                  if (!(list[n].width[i])) /*EMPTY*/;
                  else if (list[n].width[i] >= 128)
                        fprintf2(fp, "-%d",
                              (int)(list[n].width[i]) - 128);
                  else fprintf2(fp, "-'%c'", (int)(list[n].width[i]));
                  ch = ',';
            }
            ch = ':';
            for (i = 0; i < MAXLAUNCHSEP; i++) {
                  if (list[n].sep[i] >= 255) break;
                  fprintf2(fp, "%c%d", ch, (int)(list[n].sep[i]) + 1);
                  ch = ',';
            }
            if (list[n].lines > 1) {
                  if (!i) fputc(':', fp);
                  fprintf2(fp, "%d", (int)(list[n].lines));
            }
# endif     /* FD < 2 */
            break;
/*NOTREACHED*/
      }

      fputnl(fp);
}

static int NEAR printlaunch(argc, argv)
int argc;
char *argv[];
{
      char *ext;
      int i, n;
      u_char flags;

      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      hitkey(2);
      if (argc <= 1) for (i = 0; i < maxlaunch; i++) {
            printlaunchcomm(launchlist, i, 1, 1, stdout);
            hitkey(0);
      }
      else {
            ext = getext(argv[1], &flags);
            for (i = 0; i < maxlaunch; i++) {
                  n = extcmp(ext, flags,
                        launchlist[i].ext, launchlist[i].flags, 0);
                  if (!n) break;
            }
            free(ext);
            if (i >= maxlaunch) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
            printlaunchcomm(launchlist, i, 1, 0, stdout);
      }
      return(0);
}

VOID printarchcomm(list, n, isset, fp)
archivetable *list;
int n, isset;
FILE *fp;
{
      fprintf2(fp, "%s ", BL_ARCH);
# if  FD >= 2
      if (list[n].flags & LF_IGNORECASE) fputc('/', fp);
# endif
      fputsmeta(&(list[n].ext[1]), fp);
      if (isset) {
            fputc('\t', fp);

            if (list[n].p_comm) fputsmeta(list[n].p_comm, fp);
            if (!list[n].u_comm) return;
            fputc('\t', fp);
            fputsmeta(list[n].u_comm, fp);
      }
      fputnl(fp);
}

static int NEAR printarch(argc, argv)
int argc;
char *argv[];
{
      char *ext;
      int i, n;
      u_char flags;

      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      hitkey(2);
      if (argc <= 1) for (i = 0; i < maxarchive; i++) {
            printarchcomm(archivelist, i, 1, stdout);
            hitkey(0);
      }
      else {
            ext = getext(argv[1], &flags);
            for (i = 0; i < maxarchive; i++) {
                  n = extcmp(ext, flags,
                        archivelist[i].ext, archivelist[i].flags, 0);
                  if (!n) break;
            }
            free(ext);
            if (i >= maxarchive) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
            printarchcomm(archivelist, i, 1, stdout);
      }
      return(0);
}

# ifndef    _NOBROWSE
static char **NEAR readargv(sargv, dargv)
char **sargv, **dargv;
{
      FILE *fp;
      char *cp, *line, **argv;
      ALLOC_T size;
      int i, j, n, argc, dargc, meta, quote, quoted;

      dargc = countvar(dargv);
      for (n = 1; sargv[n]; n++) {
            if (sargv[n][0] != '-' || sargv[n][1] != '@') {
                  dargv = (char **)realloc2(dargv,
                        (dargc + 2) * sizeof(char *));
                  dargv[dargc++] = strdup2(sargv[n]);
                  dargv[dargc] = NULL;
                  continue;
            }
            if (sargv[n][2]) cp = &(sargv[n][2]);
            else if (sargv[n + 1]) cp = sargv[++n];
            else {
                  builtinerror(sargv, sargv[n], ER_NOARGSPEC);
                  freevar(dargv);
                  return(NULL);
            }
            if (cp[0] == '-' && !cp[1]) fp = stdin;
            else if (!(fp = Xfopen(cp, "r"))) {
                  builtinerror(sargv, cp, -1);
                  freevar(dargv);
                  return(NULL);
            }

            argc = 1;
            argv = (char **)malloc2(2 * sizeof(char *));
            argv[0] = strdup2(sargv[0]);
            argv[1] = NULL;
            j = meta = 0;
            quote = quoted = '\0';
            cp = c_realloc(NULL, 0, &size);
            while ((line = fgets2(fp, 0))) {
                  if (!meta && !quote && *line == '#') {
                        free(line);
                        continue;
                  }
                  meta = 0;
                  for (i = 0; line[i]; i++) {
                        cp = c_realloc(cp, j + 2, &size);
                        if (line[i] == quote) {
                              quoted = quote;
                              quote = '\0';
                        }
                        else if (iskanji1(line, i)) {
                              cp[j++] = line[i++];
                              cp[j++] = line[i];
                        }
#  ifdef    CODEEUC
                        else if (isekana(line, i)) {
                              cp[j++] = line[i++];
                              cp[j++] = line[i];
                        }
#  endif
                        else if (quote) cp[j++] = line[i];
                        else if (line[i] == PMETA) {
                              if (!line[++i]) {
                                    meta = 1;
                                    break;
                              }
                              cp[j++] = line[i];
                        }
                        else if (line[i] == '\'' || line[i] == '"') {
                              quoted = '\0';
                              quote = line[i];
                        }
                        else if (!strchr(IFS_SET, line[i]))
                              cp[j++] = line[i];
                        else if (j || quoted) {
                              quoted = cp[j] = '\0';
                              argv = (char **)realloc2(argv,
                                    (argc + 2) * sizeof(char *));
                              argv[argc++] = strdup2(cp);
                              argv[argc] = NULL;
                              j = 0;
                        }
                  }
                  if (meta);
                  else if (quote) cp[j++] = '\n';
                  else if (j || quoted) {
                        quoted = cp[j] = '\0';
                        argv = (char **)realloc2(argv,
                              (argc + 2) * sizeof(char *));
                        argv[argc++] = strdup2(cp);
                        argv[argc] = NULL;
                        j = 0;
                  }
                  free(line);
            }
            if (fp != stdin) Xfclose(fp);
            else clearerr(fp);
            if (j) {
                  cp[j] = '\0';
                  argv = (char **)realloc2(argv,
                        (argc + 2) * sizeof(char *));
                  argv[argc++] = strdup2(cp);
                  argv[argc] = NULL;
            }
            free(cp);
            dargv = readargv(argv, dargv);
            freevar(argv);
            if (!dargv) return(NULL);
            dargc = countvar(dargv);
      }
      return(dargv);
}

VOID freebrowse(list)
launchtable *list;
{
      int i;

      browselevel = 0;
      freevar(browsevar);
      browsevar = NULL;
      if (argvar) {
            for (i = 1; argvar[i]; i++) {
                  free(argvar[i]);
                  argvar[i] = NULL;
            }
      }
      if (!list) return;
      for (i = 0; list[i].comm; i++) freelaunch(&(list[i]));
      free(list);
}

static int NEAR custbrowse(argc, argv)
int argc;
char *argv[];
{
      launchtable *list;
      char **argv2;
      int i, n, lvl;

#  ifndef   _NOORIGSHELL
      if (shellmode) {
            builtinerror(argv, NULL, ER_NOTINSHELL);
            return(-1);
      }
#  endif
      if (inruncom) {
            builtinerror(argv, NULL, ER_NOTINRUNCOM);
            return(-1);
      }
      if (browselist) {
            builtinerror(argv, NULL, ER_NOTRECURSE);
            return(-1);
      }
      argv2 = (char **)malloc2(2 * sizeof(char *));
      argv2[0] = strdup2(argv[0]);
      argv2[1] = NULL;
      if (!(argv2 = readargv(argv, argv2))) return(-1);

      list = NULL;
      lvl = 0;
      n = 1;
      while (argv2[n]) {
            list = (launchtable *)realloc2(list,
                  (lvl + 2) * sizeof(launchtable));
            list[lvl].topskip = list[lvl].bottomskip = 0;
            list[lvl].comm = strdup2(argv2[n++]);
            list[lvl].flags = 0;
            list[lvl].ext = list[lvl + 1].comm = NULL;
            list[lvl].format = list[lvl].lignore = list[lvl].lerror = NULL;
            while (argv2[n]) {
                  i = getlaunchopt(n, argv2, "fietbpdn", &(list[lvl]));
                  if (!i) break;
                  else if (i > 0) n = i;
                  else {
                        builtinerror(argv,
                              (list[lvl].bottomskip)
                              ? argv[list[lvl].bottomskip] : NULL,
                              list[lvl].topskip);
                        freevar(argv2);
                        freebrowse(list);
                        return(-1);
/*NOTREACHED*/
                        break;
                  }
            }
            lvl++;
      }
      for (i = 0; i < lvl; i++)
            if ((!i || i < lvl - 1) && !list[i].format) break;
      if (!lvl || i < lvl) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            freevar(argv2);
            freebrowse(list);
            return(-1);
      }
      freevar(argv2);
      if (list) {
            freebrowse(browselist);
            if (dolaunch(&(list[0]), 1) < 0) {
                  freebrowse(list);
                  return(-1);
            }
            browselist = list;
      }
      return(0);
}
# endif     /* !_NOBROWSE */
#endif      /* !_NOARCHIVE */

static int NEAR getmacro(cp)
char *cp;
{
      if (maxmacro >= MAXMACROTABLE) return(0);
      else {
            macrolist[maxmacro] = strdup2(cp);
            return(FUNCLISTSIZ + maxmacro++);
      }
}

int ismacro(n)
int n;
{
      if (n < FUNCLISTSIZ || n >= FUNCLISTSIZ + MAXMACROTABLE) return(0);
      return(1);
}

int freemacro(n)
int n;
{
      int i;

      if (!ismacro(n)) return(-1);

      free(macrolist[n - FUNCLISTSIZ]);
      maxmacro--;
      memmove((char *)&(macrolist[n - FUNCLISTSIZ]),
            (char *)&(macrolist[n - FUNCLISTSIZ + 1]),
            (maxmacro - (n - FUNCLISTSIZ)) * sizeof(char *));

      for (i = 0; i < MAXBINDTABLE && bindlist[i].key >= 0; i++) {
            if (ismacro(bindlist[i].f_func) && bindlist[i].f_func > n)
                  bindlist[i].f_func--;
            if (ismacro(bindlist[i].d_func) && bindlist[i].d_func > n)
                  bindlist[i].d_func--;
      }

      return(0);
}

int searchkeybind(list, bindp)
bindtable *list, *bindp;
{
      int i;

      for (i = 0; i < MAXBINDTABLE && list[i].key >= 0; i++)
            if (list[i].key == bindp -> key) break;
      return(i);
}

int parsekeybind(argc, argv, bindp)
int argc;
char *argv[];
bindtable *bindp;
{
      int i, n;

      if (argc <= 1 || argc >= 6) {
            bindp -> key = ER_FEWMANYARG;
            bindp -> f_func = 0;
            return(-1);
      }
      if ((i = getkeycode(argv[1], 0)) < 0 || i == '\033') {
            bindp -> key = ER_SYNTAXERR;
            bindp -> f_func = 1;
            return(-1);
      }
      bindp -> key = i;

      n = searchkeybind(bindlist, bindp);
      if (n >= MAXBINDTABLE - 1) {
            bindp -> key = ER_OUTOFLIMIT;
            bindp -> f_func = 0;
            return(-1);
      }

      if (argc == 2) {
            bindp -> f_func = bindp -> d_func = 255;
            return(n);
      }

      for (i = 0; i < FUNCLISTSIZ; i++)
            if (!strcommcmp(argv[2], funclist[i].ident)) break;
      bindp -> f_func = (i < FUNCLISTSIZ) ? i : 254;

      if (argc <= 3 || argv[3][0] == BINDCOMMENT) {
            bindp -> d_func = 255;
            i = 3;
      }
      else {
            for (i = 0; i < FUNCLISTSIZ; i++)
                  if (!strcommcmp(argv[3], funclist[i].ident)) break;
            bindp -> d_func = (i < FUNCLISTSIZ) ? i : 254;
            i = 4;
      }

      if (argc > i + 1) {
            bindp -> key = ER_FEWMANYARG;
            bindp -> f_func = 0;
            return(-1);
      }
      else if (argc > i) {
            if (argv[i][0] != BINDCOMMENT
            || bindp -> key < K_F(1) || bindp -> key > K_F(10)) {
                  bindp -> key = ER_SYNTAXERR;
                  bindp -> f_func = i;
                  return(-1);
            }
      }

      return(n);
}

static int NEAR setkeybind(argc, argv)
int argc;
char *argv[];
{
      bindtable bind;
      int i, n1, n2;

      if ((i = parsekeybind(argc, argv, &bind)) < 0) {
            builtinerror(argv,
                  (bind.f_func) ? argv[bind.f_func] : NULL, bind.key);
            return(-1);
      }

      if (bind.f_func == 255) {
            if (bindlist[i].key < 0) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }

            freemacro(bindlist[i].f_func);
            freemacro(bindlist[i].d_func);
            if (bind.key >= K_F(1) && bind.key <= K_F(10)) {
                  free(helpindex[bind.key - K_F(1)]);
                  helpindex[bind.key - K_F(1)] = strdup2("");
            }
            for (; i < MAXBINDTABLE && bindlist[i].key >= 0; i++)
                  memcpy((char *)&(bindlist[i]),
                        (char *)&(bindlist[i + 1]),
                        sizeof(bindtable));
            return(0);
      }

      if (bind.f_func == 254 && !(bind.f_func = getmacro(argv[2]))) {
            builtinerror(argv, argv[2], ER_OUTOFLIMIT);
            return(-1);
      }
      if (bind.d_func == 254 && !(bind.d_func = getmacro(argv[3]))) {
            builtinerror(argv, argv[3], ER_OUTOFLIMIT);
            freemacro(bind.f_func);
            return(-1);
      }

      n1 = (bind.d_func == 255) ? 3 : 4;
      if (argc > n1) {
            free(helpindex[bind.key - K_F(1)]);
            helpindex[bind.key - K_F(1)] = strdup2(&(argv[n1][1]));
      }

      if (bindlist[i].key < 0) {
            n1 = n2 = -1;
            memcpy((char *)&(bindlist[i + 1]), (char *)&(bindlist[i]),
                  sizeof(bindtable));
      }
      else {
            n1 = bindlist[i].f_func;
            n2 = bindlist[i].d_func;
      }
      memcpy((char *)&(bindlist[i]), (char *)&bind, sizeof(bindtable));
      freemacro(n1);
      freemacro(n2);
      return(0);
}

char *gethelp(bindp)
bindtable *bindp;
{
      int n;

      if (bindp -> key < K_F(1) || bindp -> key > K_F(10)) return(NULL);
      n = bindp -> key - K_F(1);
#ifndef     _NOCUSTOMIZE
      if (!strcmp(helpindex[n], orighelpindex[n])) return(NULL);
#endif
      return(helpindex[n]);
}

VOID printmacro(list, n, isset, fp)
bindtable *list;
int n, isset;
FILE *fp;
{
      char *cp;

      fprintf2(fp, "%s ", BL_BIND);
      fputsmeta(getkeysym(list[n].key, 0), fp);
      if (isset) {
            fputc('\t', fp);

            if (list[n].f_func < FUNCLISTSIZ)
                  fputs(funclist[list[n].f_func].ident, fp);
            else if (ismacro(list[n].f_func))
                  fputsmeta(macrolist[list[n].f_func - FUNCLISTSIZ], fp);
            else fputs("\"\"", fp);
            if (list[n].d_func < FUNCLISTSIZ)
                  fprintf2(fp, "\t%s", funclist[list[n].d_func].ident);
            else if (ismacro(list[n].d_func)) {
                  fputc('\t', fp);
                  fputsmeta(macrolist[list[n].d_func - FUNCLISTSIZ], fp);
            }
            if ((cp = gethelp(&(list[n]))))
                  fprintf2(fp, "\t%c%k", BINDCOMMENT, cp);
      }
      fputnl(fp);
}

static int NEAR printbind(argc, argv)
int argc;
char *argv[];
{
      int i, c;

      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      hitkey(2);
      if (argc <= 1)
      for (i = 0; i < MAXBINDTABLE && bindlist[i].key >= 0; i++) {
            if (!ismacro(bindlist[i].f_func)
            && !ismacro(bindlist[i].d_func))
                  continue;
            printmacro(bindlist, i, 1, stdout);
            hitkey(0);
      }
      else if ((c = getkeycode(argv[1], 0)) < 0) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }
      else {
            for (i = 0; i < MAXBINDTABLE && bindlist[i].key >= 0; i++)
                  if (c == bindlist[i].key) break;
            if (i >= MAXBINDTABLE || bindlist[i].key < 0) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
            printmacro(bindlist, i, 1, stdout);
      }
      return(0);
}

#ifdef      _USEDOSEMU
/*ARGSUSED*/
int searchdrv(list, devp, isset)
devinfo *list, *devp;
int isset;
{
      int i;

      for (i = 0; list[i].name; i++) if (devp -> drive == list[i].drive) {
# ifdef     HDDMOUNT
            if (!list[i].cyl && isset) break;
# endif
            if (devp -> head == list[i].head
            && devp -> sect == list[i].sect
            && devp -> cyl == list[i].cyl
            && !strpathcmp(devp -> name, list[i].name))
                  break;
      }
      return(i);
}

int deletedrv(no)
int no;
{
      int i, n;

      n = 1;
# ifdef     HDDMOUNT
      if (!fdtype[no].cyl) {
            char *dev;
            int s;

            dev = fdtype[no].name;
            for (s = 0; s < no; s++) {
                  if (fdtype[no - s - 1].cyl
                  || fdtype[no - s - 1].drive + 1 != fdtype[no - s].drive
                  || strpathcmp(dev, fdtype[no - s - 1].name))
                        break;
            }
            for (n = 1; fdtype[no + n].name; n++) {
                  if (fdtype[no + n].cyl
                  || fdtype[no + n].drive != fdtype[no + n - 1].drive + 1
                  || strpathcmp(dev, fdtype[no + n].name))
                        break;
            }
            no -= s;
            n += s;
      }
# endif     /* HDDMOUNT */
      for (i = 0; i < n; i++) free(fdtype[no + i].name);
      for (i = no; fdtype[i + n].name; i++)
            memcpy((char *)&(fdtype[i]),
                  (char *)&(fdtype[i + n]), sizeof(devinfo));
      fdtype[i].name = NULL;
      return(no);
}

int insertdrv(no, devp)
int no;
devinfo *devp;
{
# ifdef     HDDMOUNT
      l_off_t *sp;
      char *drvlist;
# endif
      int i, n, min, max;

      min = -1;
# ifdef     FAKEUNINIT
      max = -1;   /* fake for -Wuninitialized */
# endif
      for (i = 0; fdtype[i].name; i++)
      if (!strpathcmp(devp -> name, fdtype[i].name)) {
            if (min < 0) min = i;
            max = i;
      }
      if (min < 0) {
            if (no > 0 && no < i
            && !strpathcmp(fdtype[no - 1].name, fdtype[no].name))
                  no = i;
      }
      else if (no < min) no = min;
      else if (no > max + 1) no = max + 1;

      max = i;
      n = 1;
# ifdef     HDDMOUNT
      sp = NULL;
      if (!(devp -> cyl)) {
            int j, drive;

            if (!(sp = readpt(devp -> name, devp -> sect))) return(-1);
            for (n = 0; sp[n + 1]; n++);
            if (!n) {
                  free(sp);
                  return(-1);
            }
            else if (n >= MAXDRIVEENTRY - no) {
                  free(sp);
                  return(-2);
            }
            devp -> sect = sp[0];

            drvlist = malloc2(n);
            drvlist[0] = devp -> drive;
            for (i = 0; i < n - 1; i++) {
                  for (drive = drvlist[i] + 1; drive <= 'Z'; drive++) {
                        for (j = 0; fdtype[j].name; j++)
                              if (drive == fdtype[j].drive) break;
                        if (!fdtype[j].name) break;
                  }
                  if (drive > 'Z') break;
                  drvlist[i + 1] = drive;
            }
            if (i < n - 1) {
                  free(sp);
                  free(drvlist);
                  return(-2);
            }
      }
#  ifdef    FAKEUNINIT
      else drvlist = NULL;          /* fake for -Wuninitialized */
#  endif
# endif     /* HDDMOUNT */

      fdtype[max + n].name = NULL;
      for (i = max; i > no; i--) {
            memcpy((char *)&(fdtype[i + n - 1]),
                  (char *)&(fdtype[i - 1]), sizeof(devinfo));
      }

# ifdef     HDDMOUNT
      if (!(devp -> cyl)) {
            for (i = 0; i < n; i++) {
                  memcpy((char *)&(fdtype[no + i]), (char *)devp,
                        sizeof(devinfo));
                  fdtype[no + i].drive = drvlist[i];
                  fdtype[no + i].name = strdup2(devp -> name);
                  fdtype[no + i].offset = sp[i + 1];
            }
            free(sp);
            free(drvlist);
            return(no);
      }
      fdtype[no].offset = 0;
# endif     /* HDDMOUNT */
      memcpy((char *)&(fdtype[no]), (char *)devp, sizeof(devinfo));
      fdtype[no].name = strdup2(devp -> name);
      return(no);
}

int parsesetdrv(argc, argv, devp)
int argc;
char *argv[];
devinfo *devp;
{
      int head, sect, cyl;

      if (argc <= 3) {
            devp -> drive = ER_FEWMANYARG;
            devp -> head = 0;
            return(-1);
      }
# if  FD >= 2
      if (argc >= 7) {
            devp -> drive = ER_FEWMANYARG;
            devp -> head = 0;
            return(-1);
      }
# endif

      devp -> drive = toupper2(argv[1][0]);
      devp -> name = argv[2];
      if (!isalpha2(devp -> drive)) {
            devp -> drive = ER_SYNTAXERR;
            devp -> head = 1;
            return(-1);
      }

# ifdef     HDDMOUNT
      if (!strncmp(argv[3], "HDD", sizeof("HDD") - 1)) {
            if (argc > 5) {
                  devp -> drive = ER_FEWMANYARG;
                  devp -> head = 0;
                  return(-1);
            }
            cyl = 0;
            if (!argv[3][3]) sect = 0;
            else if (!strcmp(&(argv[3][3]), "98")) sect = 98;
            else {
                  devp -> drive = ER_SYNTAXERR;
                  devp -> head = 3;
                  return(-1);
            }
            if (argc < 5) head = 'n';
            else if (!strcmp(argv[4], "ro")) head = 'r';
            else if (!strcmp(argv[4], "rw")) head = 'w';
            else {
                  devp -> drive = ER_SYNTAXERR;
                  devp -> head = 4;
                  return(-1);
            }
            if (sect) head = toupper2(head);
      }
      else
# endif     /* HDDMOUNT */
# if  FD >= 2
      if (argc != 6) {
            devp -> drive = ER_FEWMANYARG;
            devp -> head = 0;
            return(-1);
      }
      else if ((head = atoi2(argv[3])) <= 0) {
            devp -> drive = ER_SYNTAXERR;
            devp -> head = 3;
            return(-1);
      }
      else if (head > MAXUTYPE(u_char)) {
            devp -> drive = ER_OUTOFLIMIT;
            devp -> head = 3;
            return(-1);
      }
      else if ((sect = atoi2(argv[4])) <= 0) {
            devp -> drive = ER_SYNTAXERR;
            devp -> head = 4;
            return(-1);
      }
      else if (sect > MAXUTYPE(u_short)) {
            devp -> drive = ER_OUTOFLIMIT;
            devp -> head = 4;
            return(-1);
      }
      else if ((cyl = atoi2(argv[5])) <= 0) {
            devp -> drive = ER_SYNTAXERR;
            devp -> head = 5;
            return(-1);
      }
      else if (cyl > MAXUTYPE(u_short)) {
            devp -> drive = ER_OUTOFLIMIT;
            devp -> head = 5;
            return(-1);
      }
# else      /* FD < 2 */
      {
            char *cp, *tmp;
            u_char c;

            cp = tmp = catvar(&(argv[3]), '\0');

            if (!(cp = sscanf2(cp, "%+Cu%c", &c, DRIVESEP))) {
                  devp -> drive = ER_SYNTAXERR;
                  devp -> head = (u_char)-1;
                  devp -> name = tmp;
                  return(-1);
            }
            head = c;
            if (!(cp = sscanf2(cp, "%+Cu%c", &c, DRIVESEP))) {
                  devp -> drive = ER_SYNTAXERR;
                  devp -> head = (u_char)-1;
                  devp -> name = tmp;
                  return(-1);
            }
            sect = c;
            if (!sscanf2(cp, "%+Cu%$", &c)) {
                  devp -> drive = ER_SYNTAXERR;
                  devp -> head = (u_char)-1;
                  devp -> name = tmp;
                  return(-1);
            }
            cyl = c;
            if (head > MAXUTYPE(u_char)
            || sect > MAXUTYPE(u_short)
            || cyl > MAXUTYPE(u_short)) {
                  devp -> drive = ER_OUTOFLIMIT;
                  devp -> head = (u_char)-1;
                  devp -> name = tmp;
                  return(-1);
            }
            free(tmp);
      }
# endif     /* FD < 2 */
      devp -> head = head;
      devp -> sect = sect;
      devp -> cyl = cyl;

      return(0);
}

static int NEAR _setdrive(argc, argv, isset)
int argc;
char *argv[];
int isset;
{
      devinfo dev;
      int i, n;

      if (parsesetdrv(argc, argv, &dev) < 0) {
# if  FD < 2
            if (dev.head == (u_char)-1) {
                  builtinerror(argv, dev.name, dev.drive);
                  free(dev.name);
            }
            else
# endif
            builtinerror(argv,
                  (dev.head) ? argv[dev.head] : NULL, dev.drive);
            return(-1);
      }

# ifdef     HDDMOUNT
      if (!(dev.cyl)) for (i = 0; fdtype[i].name; i++) {
            if (dev.drive == fdtype[i].drive) break;
      }
      else
# endif
      i = searchdrv(fdtype, &dev, isset);

      if (!isset) {
            if (!fdtype[i].name) {
                  builtinerror(argv, argv[2], ER_NOENTRY);
                  return(-1);
            }
# ifdef     HDDMOUNT
            if (!(dev.cyl)
            && (fdtype[i].cyl || strpathcmp(argv[2], fdtype[i].name))) {
                  builtinerror(argv, argv[2], ER_NOENTRY);
                  return(-1);
            }
# endif
            deletedrv(i);
      }
      else {
            if (fdtype[i].name) {
                  builtinerror(argv, argv[1], ER_EXIST);
                  return(-1);
            }
            if (i >= MAXDRIVEENTRY - 1) {
                  builtinerror(argv, NULL, ER_OUTOFLIMIT);
                  return(-1);
            }

            n = insertdrv(i, &dev);
            if (n < -1) {
                  builtinerror(argv, NULL, ER_OUTOFLIMIT);
                  return(-1);
            }
            if (!inruncom && n < 0) {
                  builtinerror(argv, argv[2], ER_INVALDEV);
                  return(-1);
            }
      }

      return(0);
}

static int NEAR setdrive(argc, argv)
int argc;
char *argv[];
{
      return(_setdrive(argc, argv, 1));
}

static int NEAR unsetdrive(argc, argv)
int argc;
char *argv[];
{
      return(_setdrive(argc, argv, 0));
}

/*ARGSUSED*/
VOID printsetdrv(fdlist, n, isset, verbose, fp)
devinfo fdlist[];
int n, isset, verbose;
FILE *fp;
{
      fprintf2(fp, "%s %c\t",
            (isset) ? BL_SDRIVE : BL_UDRIVE, fdlist[n].drive);

      fputsmeta(fdlist[n].name, fp);
      fputc('\t', fp);
# ifdef     HDDMOUNT
      if (!fdlist[n].cyl) {
            fputs("HDD", fp);
            if (isupper2(fdlist[n].head)) fputs("98", fp);
            if (verbose) fprintf2(fp, " #offset=%'Ld",
                  fdlist[n].offset / fdlist[n].sect);
            return;
      }
# endif     /* HDDMOUNT */
      fprintf2(fp, "%d%c%d%c%d", (int)(fdlist[n].head), DRIVESEP,
            (int)(fdlist[n].sect), DRIVESEP, (int)(fdlist[n].cyl));
      fputnl(fp);
}

static int NEAR printdrive(argc, argv)
int argc;
char *argv[];
{
      int i, n;

      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      hitkey(2);
      if (argc <= 1) for (i = 0; fdtype[i].name; i++) {
            printsetdrv(fdtype, i, 1, 1, stdout);
            hitkey(0);
      }
      else {
            for (i = n = 0; fdtype[i].name; i++)
            if (toupper2(argv[1][0]) == fdtype[i].drive) {
                  n++;
                  printsetdrv(fdtype, i, 1, 1, stdout);
                  hitkey(0);
            }
            if (!n) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
      }
      return(0);
}
#endif      /* _USEDOSEMU */

#ifndef     _NOKEYMAP
VOID printkeymap(kp, isset, fp)
keyseq_t *kp;
int isset;
FILE *fp;
{
      char *cp;

      fprintf2(fp, "%s ", BL_KEYMAP);
      fputsmeta(getkeysym(kp -> code, 1), fp);
      if (isset) {
            fputc('\t', fp);

            cp = encodestr(kp -> str, kp -> len);
            fputsmeta(cp, fp);
            free(cp);
      }
      fputnl(fp);
}

int parsekeymap(argc, argv, kp)
int argc;
char *argv[];
keyseq_t *kp;
{
      kp -> code = (short)-1;
      kp -> len = 0;
      kp -> str = NULL;

      if (argc >= 4) {
            kp -> code = ER_FEWMANYARG;
            kp -> len = 0;
            return(-1);
      }

      if (argc <= 1) return(0);
      if ((kp -> code = getkeycode(argv[1], 1)) < 0) {
            kp -> code = ER_SYNTAXERR;
            kp -> len = 1;
            return(-1);
      }
      if (argc == 2) return(0);

      if (!(argv[2][0])) {
            kp -> len = (u_char)-1;
            return(0);
      }

      kp -> str = decodestr(argv[2], &(kp -> len), 1);
      if (!(kp -> len)) {
            free(kp -> str);
            kp -> code = ER_SYNTAXERR;
            kp -> len = 2;
            return(-1);
      }

      return(0);
}

static int NEAR setkeymap(argc, argv)
int argc;
char *argv[];
{
      keyseq_t key;
      int i;

      if (parsekeymap(argc, argv, &key) < 0) {
            builtinerror(argv, (key.len) ? argv[key.len] : NULL, key.code);
            return(-1);
      }

      if (key.code < 0) {
            hitkey(2);
            for (i = 1; i <= 20; i++) {
                  key.code = K_F(i);
                  if (getkeyseq(&key) < 0 || !(key.len)) continue;
                  printkeymap(&key, 1, stdout);
                  hitkey(0);
            }
            for (i = 0; (key.code = keyidentlist[i].no) > 0; i++) {
                  if (getkeyseq(&key) < 0 || !(key.len)) continue;
                  printkeymap(&key, 1, stdout);
                  hitkey(0);
            }
            return(0);
      }

      if (!(key.len)) {
            if (getkeyseq(&key) < 0 || !(key.len)) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
            hitkey(2);
            printkeymap(&key, 1, stdout);
            return(0);
      }
      if (!(key.str)) {
            setkeyseq(key.code, NULL, 0);
            return(0);
      }

      setkeyseq(key.code, key.str, key.len);

      return(0);
}

static int NEAR keytest(argc, argv)
int argc;
char *argv[];
{
      char *cp, buf[2];
      int i, n, ch, next;

      if (dumbterm > 1) {
            builtinerror(argv, NULL, ER_NOTDUMBTERM);
            return(-1);
      }
      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }

      n = (argc >= 2) ? atoi2(argv[1]) : 1;
      if (n < 0) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }

      hitkey(2);
      ttyiomode(1);
      i = 0;
      for (;;) {
            kanjiputs(GETKY_K);
            if (n != 1) kanjiputs(SPCED_K);
            tflush();

            next = 0;
            while (!kbhit2(1000000L / SENSEPERSEC));
            cputs2("\r\"");
            putterm(l_clear);
            buf[1] = '\0';
            do {
                  if ((ch = getch2()) == EOF) break;
                  next = kbhit2(WAITKEYPAD * 1000L);
                  buf[0] = ch;
                  cp = encodestr(buf, 1);
                  cputs2(cp);
                  free(cp);
            } while (next);
            putch2('"');
            cputnl();
            if (n) {
                  if (++i >= n) break;
            }
            if (n != 1 && ch == ' ') break;
      }
      stdiomode();
      return(0);
}
#endif      /* !_NOKEYMAP */

static int NEAR printhist(argc, argv)
int argc;
char *argv[];
{
      int i, n, max, size;

      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      size = (int)histsize[0];
      if (argc < 2) n = size;
      else if ((n = atoi2(argv[1])) < 1) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }
      else if (n > size) n = size;

      if (!history[0]) return(0);
      if (--n > (int)MAXHISTNO) n = (int)MAXHISTNO;
      for (max = n; max >= 0; max--) if (history[0][max]) break;
      if (max < (int)histno[0]) n = (int)histno[0] - max - 1;
      else n = (int)MAXHISTNO - (max - (int)histno[0]);

      hitkey(2);
      for (i = max; i >= 0; i--) {
            fprintf2(stdout, "%5d  %k", n + 1, history[0][i]);
            fputnl(stdout);
            if (n++ >= (int)MAXHISTNO) n = 0;
            hitkey(0);
      }
      return(0);
}

#if   FD >= 2
# ifndef    NOPOSIXUTIL
static int NEAR fixcommand(argc, argv)
int argc;
char *argv[];
{
      FILE *fp;
      char *cp, *tmp, *editor, path[MAXPATHLEN];
      int i, n, f, l, skip, list, nonum, rev, exe, ret;

      editor = NULL;
      skip = list = nonum = rev = exe = 0;
      for (n = 1; n < argc && argv[n][0] == '-'; n++) {
            skip = 0;
            for (i = 1; argv[n][i]; i++) {
                  skip = 0;
                  switch(argv[n][i]) {
                        case 'e':
                              if (argv[n][i + 1]) {
                                    editor = &(argv[n][i + 1]);
                                    skip = 1;
                              }
                              else if (n + 1 < argc) {
                                    editor = argv[++n];
                                    skip = 1;
                              }
                              else skip = -1;
                              break;
                        case 'l':
                              list = 1;
                              break;
                        case 'n':
                              nonum = 1;
                              break;
                        case 'r':
                              rev = 1;
                              break;
                        case 's':
                              exe = 1;
                              break;
                        default:
                              skip = -1;
                              break;
                  }
                  if (skip) {
                        skip--;
                        break;
                  }
            }
            if (skip) {
                  skip--;
                  break;
            }
      }
      if (skip) {
            fprintf2(stderr,
      "%k: usage: %k [-ls] [-nr] [-e editor] [old=new] [first] [last]",
                  argv[0], argv[0]);
            fputnl(stderr);
            return(-1);
      }

      if (!history[0]) return(0);
      tmp = removehist(0);
      if (exe) {
            char *s, *r;
            int j, l1, l2, len, max;

            i = n;
            for (; n < argc; n++) if (!strchr(argv[n], '=')) break;
            if ((f = parsehist((n < argc) ? argv[n] : "!", NULL)) < 0) {
                  builtinerror(argv, argv[n], ER_EVENTNOFOUND);
                  entryhist(0, tmp, 0);
                  free(tmp);
                  return(-1);
            }
            free(tmp);
            s = strdup2(history[0][f]);
            max = len = strlen(s);
            for (; i < n; i++) {
                  if (!(r = strchr(argv[i], '='))) continue;
                  l1 = r - argv[i];
                  for (cp = s; (cp = strchr2(cp, argv[i][0])); cp++)
                        if (!strncmp(cp, argv[i], l1)) break;
                  if (!cp) continue;
                  r++;
                  l2 = strlen(r);
                  len += l2 - l1;
                  if (len > max) {
                        max = len;
                        j = cp - s;
                        s = realloc2(s, max + 1);
                        cp = s + j;
                  }
                  memmove(&(cp[l2]), &(cp[l1]),
                        &(s[len]) - &(cp[l2]) + 1);
                  strncpy(cp, r, l2);
            }
            kanjifputs(s, stdout);
            fputnl(stdout);
            entryhist(0, s, 0);
            if ((ret = execmacro(s, NULL, 1, -1, 1)) < 0) ret = 0;
            free(s);
            return(ret);
      }

      if (!editor) editor = getenv2("FD_FCEDIT");
      if (!editor) editor = getenv2("FD_EDITOR");
      if (!editor) editor = EDITOR;

      if (list) {
            f = parsehist((n < argc) ? argv[n] : "-16", NULL);
            l = parsehist((n + 1 < argc) ? argv[n + 1] : "!", NULL);
      }
      else {
            f = parsehist((n < argc) ? argv[n] : "!", NULL);
            l = (n + 1 < argc) ? parsehist(argv[n + 1], NULL) : f;
      }
      if (f < 0 || l < 0) {
            if (f < 0) builtinerror(argv, argv[n], ER_EVENTNOFOUND);
            else builtinerror(argv,
                  (n + 1 < argc) ? argv[n + 1] : NULL, ER_EVENTNOFOUND);
            entryhist(0, tmp, 0);
            free(tmp);
            return(-1);
      }

      if (rev) {
            n = f;
            f = l;
            l = n;
      }

      if (f < (int)histno[0]) n = (int)histno[0] - f - 1;
      else n = (int)MAXHISTNO - (f - (int)histno[0]);

      if (list) {
            fp = stdout;
            hitkey(2);
      }
      else {
            int fd;

            if ((fd = mktmpfile(path)) < 0) {
                  builtinerror(argv, argv[0], -1);
                  free(tmp);
                  return(-1);
            }
            if (!(fp = Xfdopen(fd, "w"))) {
                  builtinerror(argv, path, -1);
                  Xclose(fd);
                  rmtmpfile(path);
                  free(tmp);
                  return(-1);
            }
            nonum = 1;
      }

      if (f >= l) for (i = f; i >= l; i--) {
            if (history[0][i]) {
                  if (!nonum) {
                        fprintf2(fp, "%5d  ", n + 1);
                        if (n++ >= (int)MAXHISTNO) n = 0;
                  }
                  kanjifputs(history[0][i], fp);
                  fputnl(fp);
#  ifdef    _NOORIGSHELL
                  if (list) hitkey(0);
#  endif
            }
      }
      else for (i = f; i <= l; i++) {
            if (history[0][i]) {
                  if (!nonum) {
                        fprintf2(fp, "%5d  ", n + 1);
                        if (--n < 0) n = (int)MAXHISTNO;
                  }
                  kanjifputs(history[0][i], fp);
                  fputnl(fp);
#  ifdef    _NOORIGSHELL
                  if (list) hitkey(0);
#  endif
            }
      }

      if (list) {
            fflush(stdout);
            entryhist(0, tmp, 0);
            free(tmp);
            return(0);
      }

      Xfclose(fp);
      ret = execmacro(editor, path, 1, 0, 1);
      if (ret < 0) ret = 0;
      if (ret) {
            builtinerror(argv, editor, -1);
            rmtmpfile(path);
            free(tmp);
            return(-1);
      }

      if (!(fp = Xfopen(path, "r"))) {
            builtinerror(argv, path, -1);
            rmtmpfile(path);
            free(tmp);
            return(-1);
      }
      free(tmp);

      for (n = 0; (cp = fgets2(fp, 0)); n++) {
            if (!*cp) {
                  free(cp);
                  continue;
            }
            kanjifputs(cp, stdout);
            fputnl(stdout);
            entryhist(0, cp, 0);
            ret = execmacro(cp, NULL, 1, -1, 1);
            free(cp);
      }
      Xfclose(fp);
      rmtmpfile(path);
      return(ret);
}
# endif     /* !NOPOSIXUTIL */

/*ARGSUSED*/
static VOID NEAR voidmd5(a, b, c, d)
u_long a, b, c, d;
{
      /* For bugs on NEWS-OS optimizer */
}

static VOID NEAR calcmd5(sum, x)
u_long sum[4], x[16];
{
      u_long a, b, c, d, tmp, t[16];
      int i, s[4];

      a = sum[0];
      b = sum[1];
      c = sum[2];
      d = sum[3];

      s[0] = 7;
      s[1] = 12;
      s[2] = 17;
      s[3] = 22;
      t[0] = 0xd76aa478;      /* floor(4294967296.0 * fabs(sin(1.0))) */
      t[1] = 0xe8c7b756;
      t[2] = 0x242070db;
      t[3] = 0xc1bdceee;
      t[4] = 0xf57c0faf;
      t[5] = 0x4787c62a;
      t[6] = 0xa8304613;
      t[7] = 0xfd469501;
      t[8] = 0x698098d8;
      t[9] = 0x8b44f7af;
      t[10] = 0xffff5bb1;
      t[11] = 0x895cd7be;
      t[12] = 0x6b901122;
      t[13] = 0xfd987193;
      t[14] = 0xa679438e;
      t[15] = 0x49b40821;
      for (i = 0; i < 16; i++) {
            a += ((b & c) | (~b & d)) + x[i] + t[i];
            tmp = b + ((a << s[i % 4]) | a >> (32 - s[i % 4]));
            tmp &= (u_long)0xffffffff;
            a = d;
            d = c;
            c = b;
            b = tmp;
            voidmd5(a, b, c, d);
      }

      s[0] = 5;
      s[1] = 9;
      s[2] = 14;
      s[3] = 20;
      t[0] = 0xf61e2562;      /* floor(4294967296.0 * fabs(sin(16.0))) */
      t[1] = 0xc040b340;
      t[2] = 0x265e5a51;
      t[3] = 0xe9b6c7aa;
      t[4] = 0xd62f105d;
      t[5] = 0x02441453;
      t[6] = 0xd8a1e681;
      t[7] = 0xe7d3fbc8;
      t[8] = 0x21e1cde6;
      t[9] = 0xc33707d6;
      t[10] = 0xf4d50d87;
      t[11] = 0x455a14ed;
      t[12] = 0xa9e3e905;
      t[13] = 0xfcefa3f8;
      t[14] = 0x676f02d9;
      t[15] = 0x8d2a4c8a;
      for (i = 0; i < 16; i++) {
            a += ((b & d) | (c & ~d)) + x[(i * 5 + 1) % 16] + t[i];
            tmp = b + ((a << s[i % 4]) | a >> (32 - s[i % 4]));
            tmp &= (u_long)0xffffffff;
            a = d;
            d = c;
            c = b;
            b = tmp;
            voidmd5(a, b, c, d);
      }

      s[0] = 4;
      s[1] = 11;
      s[2] = 16;
      s[3] = 23;
      t[0] = 0xfffa3942;      /* floor(4294967296.0 * fabs(sin(32.0))) */
      t[1] = 0x8771f681;
      t[2] = 0x6d9d6122;
      t[3] = 0xfde5380c;
      t[4] = 0xa4beea44;
      t[5] = 0x4bdecfa9;
      t[6] = 0xf6bb4b60;
      t[7] = 0xbebfbc70;
      t[8] = 0x289b7ec6;
      t[9] = 0xeaa127fa;
      t[10] = 0xd4ef3085;
      t[11] = 0x04881d05;
      t[12] = 0xd9d4d039;
      t[13] = 0xe6db99e5;
      t[14] = 0x1fa27cf8;
      t[15] = 0xc4ac5665;
      for (i = 0; i < 16; i++) {
            a += (b ^ c ^ d) + x[(i * 3 + 5) % 16] + t[i];
            tmp = b + ((a << s[i % 4]) | a >> (32 - s[i % 4]));
            tmp &= (u_long)0xffffffff;
            a = d;
            d = c;
            c = b;
            b = tmp;
            voidmd5(a, b, c, d);
      }

      s[0] = 6;
      s[1] = 10;
      s[2] = 15;
      s[3] = 21;
      t[0] = 0xf4292244;      /* floor(4294967296.0 * fabs(sin(48.0))) */
      t[1] = 0x432aff97;
      t[2] = 0xab9423a7;
      t[3] = 0xfc93a039;
      t[4] = 0x655b59c3;
      t[5] = 0x8f0ccc92;
      t[6] = 0xffeff47d;
      t[7] = 0x85845dd1;
      t[8] = 0x6fa87e4f;
      t[9] = 0xfe2ce6e0;
      t[10] = 0xa3014314;
      t[11] = 0x4e0811a1;
      t[12] = 0xf7537e82;
      t[13] = 0xbd3af235;
      t[14] = 0x2ad7d2bb;
      t[15] = 0xeb86d391;
      for (i = 0; i < 16; i++) {
            a += (c ^ (b | ~d)) + x[(i * 7) % 16] + t[i];
            tmp = b + ((a << s[i % 4]) | a >> (32 - s[i % 4]));
            tmp &= (u_long)0xffffffff;
            a = d;
            d = c;
            c = b;
            b = tmp;
            voidmd5(a, b, c, d);
      }

      sum[0] = (sum[0] + a) & (u_long)0xffffffff;
      sum[1] = (sum[1] + b) & (u_long)0xffffffff;
      sum[2] = (sum[2] + c) & (u_long)0xffffffff;
      sum[3] = (sum[3] + d) & (u_long)0xffffffff;
}

static int NEAR printmd5(path, fp)
char *path;
FILE *fp;
{
      FILE *fpin;
      u_long cl, ch, sum[4], x[16];
      int i, c, b, n;

      if (!(fpin = Xfopen(path, "rb"))) return(-1);

      cl = ch = (u_long)0;
      sum[0] = (u_long)0x67452301;
      sum[1] = (u_long)0xefcdab89;
      sum[2] = (u_long)0x98badcfe;
      sum[3] = (u_long)0x10325476;

      n = b = 0;
      for (i = 0; i < 16; i++) x[i] = (u_long)0;
      while ((c = Xfgetc(fpin)) != EOF) {
            if (cl <= (u_long)0xffffffff - (u_long)BITSPERBYTE)
                  cl += (u_long)BITSPERBYTE;
            else {
                  cl -= (u_long)0xffffffff - (u_long)BITSPERBYTE + 1;
                  ch++;
                  ch &= (u_long)0xffffffff;
            }
            x[n] |= c << b;
            if ((b += BITSPERBYTE) >= 32) {
                  b = 0;
                  if (++n >= 16) {
                        calcmd5(sum, x);
                        n = 0;
                        for (i = 0; i < 16; i++) x[i] = (u_long)0;
                  }
            }
      }
      Xfclose(fpin);

      x[n] |= 1 << (b + BITSPERBYTE - 1);
      if (n >= 14) {
            calcmd5(sum, x);
            for (i = 0; i < 16; i++) x[i] = (u_long)0;
      }
      x[14] = cl;
      x[15] = ch;
      calcmd5(sum, x);

      fprintf2(fp, "MD5 (%k) = ", path);
      for (i = 0; i < 4; i++) for (n = 0; n < 4; n++) {
            fprintf2(fp, "%02x", (int)(sum[i] & 0xff));
            sum[i] >>= 8;
      }
      fputnl(fp);
      return(0);
}

static int NEAR md5sum(argc, argv)
int argc;
char *argv[];
{
      char path[MAXPATHLEN];
      int i, ret;

      hitkey(2);
      if (argc < 2) {
# if  MSDOS
            strcpy(strcatdelim2(path, progpath, progname), ".EXE");
# else
            strcatdelim2(path, progpath, progname);
# endif
            if (printmd5(path, stdout) < 0) {
                  builtinerror(argv, path, -1);
                  return(-1);
            }
            return(0);
      }

      ret = 0;
      for (i = 1; i < argc; i++) {
            if (printmd5(argv[i], stdout) < 0) {
                  builtinerror(argv, argv[i], -1);
                  ret = -1;
                  continue;
            }
            hitkey(0);
      }
      return(ret);
}

static int NEAR evalmacro(argc, argv)
int argc;
char *argv[];
{
      char *cp;
      int ret;

      if (argc <= 1 || !(cp = catvar(&(argv[1]), ' '))) return(0);
      if ((ret = execmacro(cp, NULL, 1, -1, 0)) < 0) ret = 0;
      free(cp);
      return(ret);
}

# ifndef    _NOKANJICONV
static int NEAR kconv(argc, argv)
int argc;
char *argv[];
{
      FILE *fpin, *fpout;
      char *cp, *tmp;
      int i, in, out, err;

      err = 0;
      in = out = DEFCODE;
      for (i = 1; i < argc; i++) {
            if (argv[i][0] != '-') break;
            if (argv[i][1] == '-' && !argv[i][2]) {
                  i++;
                  break;
            }
            switch (argv[i][1]) {
                  case 'i':
                        if (argv[i][2]) cp = &(argv[i][2]);
                        else if (!(cp = argv[++i]) || !*cp) {
                              err = 1;
                              break;
                        }
                        if ((in = getlang(cp, L_FNAME)) == NOCNV)
                              in = DEFCODE;
                        break;
                  case 'o':
                        if (argv[i][2]) cp = &(argv[i][2]);
                        else if (!(cp = argv[++i]) || !*cp) {
                              err = 1;
                              break;
                        }
                        if ((out = getlang(cp, L_FNAME)) == NOCNV)
                              out = DEFCODE;
                        break;
                  default:
                        err = 1;
                        break;
            }
            if (err) {
                  fprintf2(stderr,
            "Usage: %s [-i inputcode] [-o outputcode] [filename]",
                        argv[0]);
                  fputnl(stderr);
                  return(-1);
            }
      }

      if (i >= argc || !*(argv[i])) {
            fpin = stdin;
            fpout = stdout;
      }
      else if (!(fpin = Xfopen(argv[i], "r"))) {
            builtinerror(argv, argv[i], -1);
            return(-1);
      }
      else if (i + 1 >= argc || !*(argv[i + 1])) fpout = stdout;
      else if (!(fpout = Xfopen(argv[i + 1], "w"))) {
            builtinerror(argv, argv[i + 1], -1);
            Xfclose(fpin);
            return(-1);
      }

      if (in == M_UTF8 || out == M_UTF8) readunitable(1);
      else if (in == UTF8 || out == UTF8) readunitable(0);
      while ((cp = fgets2(fpin, 0))) {
            if (in != DEFCODE) {
                  tmp = newkanjiconv(cp, in, DEFCODE, L_OUTPUT);
                  if (cp != tmp) free(cp);
                  cp = tmp;
            }
            tmp = newkanjiconv(cp, DEFCODE, out, L_OUTPUT);
            if (cp != tmp) free(cp);
            fputs(tmp, fpout);
            fputnl(fpout);
            free(tmp);
      }

      if (!unicodebuffer) discardunitable();
      if (fpin != stdin) Xfclose(fpin);
      else clearerr(fpin);
      if (fpout != stdout) Xfclose(fpout);
      return(0);
}
# endif     /* !_NOKANJICONV */

static int NEAR getinputstr(argc, argv)
int argc;
char *argv[];
{
      char *s, *duppromptstr;
      int wastty;

      if (dumbterm > 1) {
            builtinerror(argv, NULL, ER_NOTDUMBTERM);
            return(-1);
      }
      if (!(wastty = isttyiomode)) ttyiomode(1);
      duppromptstr = promptstr;
      promptstr = (argc >= 2) ? argv[1] : "";
      s = inputstr(NULL, 0, -1, NULL, -1);
      promptstr = duppromptstr;
      if (!wastty) stdiomode();
      if (!s) return(-1);

      kanjifputs(s, stdout);
      fputnl(stdout);
      free(s);
      return(0);
}

static int NEAR getyesno(argc, argv)
int argc;
char *argv[];
{
      char *s;
      int ret, wastty;

      if (dumbterm > 1) {
            builtinerror(argv, NULL, ER_NOTDUMBTERM);
            return(-1);
      }
      if (argc < 2) s = "";
      else s = argv[1];

      if (!(wastty = isttyiomode)) ttyiomode(1);
      lcmdline = -1;
      ret = yesno(s);
      if (!wastty) stdiomode();
      return((ret) ? 0 : -1);
}
#endif      /* FD >= 2 */

#ifdef      _NOORIGSHELL
static int NEAR printenv(argc, argv)
int argc;
char *argv[];
{
# if  FD < 2
      int len;
# endif
      int i;

# if  FD >= 2
      if (argc >= 2) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
# else
      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }

      if (argc > 1) {
            hitkey(2);
            len = strlen(argv[1]);
            for (i = 0; environ2[i]; i++)
                  if (!strnenvcmp(environ2[i], argv[1], len)
                  && environ2[i][len] == '=')
                        break;
            if (!environ2[i]) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
            kanjifputs(environ2[i], stdout);
            fputnl(stdout);
            return(0);
      }
# endif

      hitkey(2);
      if (environ2) for (i = 0; environ2[i]; i++) {
            kanjifputs(environ2[i], stdout);
            fputnl(stdout);
            hitkey(0);
      }
# if  FD >= 2
      for (i = 0; i < maxuserfunc; i++) {
            printfunction(i, 0, stdout);
            fputnl(stdout);
            hitkey(0);
      }
# endif
      return(0);
}

VOID printalias(n, fp)
int n;
FILE *fp;
{
      fprintf2(fp, "%s %k%c\n", BL_ALIAS, aliaslist[n].alias, ALIASSEP);
      fputsmeta(aliaslist[n].comm, fp);
}

static int NEAR setalias(argc, argv)
int argc;
char *argv[];
{
      char *cp;
      int i, len;

# if  FD >= 2
      if (argc >= 3) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
# else
      if (argc >= 4) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
# endif

      if (argc <= 1) {
            hitkey(2);
            for (i = 0; i < maxalias; i++) {
                  printalias(i, stdout);
                  fputnl(stdout);
                  hitkey(0);
            }
            return(0);
      }

# if  FD >= 2
      if (!(cp = gettoken(argv[1])) || (*cp && *cp != ALIASSEP)) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }
      len = cp - argv[1];
# else
      if (!(cp = gettoken(argv[1])) || *cp) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }
      len = strlen(argv[1]);
# endif

      for (i = 0; i < maxalias; i++)
            if (!strncommcmp(argv[1], aliaslist[i].alias, len)) break;

# if  FD >= 2
      if (*cp) *cp = '\0';
# else
      if (argc > 2) /*EMPTY*/;
# endif
      else {
            if (i >= maxalias) {
                  builtinerror(argv, argv[1], ER_NOENTRY);
                  return(-1);
            }
            hitkey(2);
            printalias(i, stdout);
            fputnl(stdout);
            return(0);
      }

      if (i >= MAXALIASTABLE) {
            builtinerror(argv, NULL, ER_OUTOFLIMIT);
            return(-1);
      }
      if (i >= maxalias) maxalias++;
      else {
            free(aliaslist[i].comm);
            free(aliaslist[i].alias);
      }
      aliaslist[i].alias = strdup2(argv[1]);
      aliaslist[i].comm = strdup2(argv[2]);
# ifdef     COMMNOCASE
      for (cp = aliaslist[i].alias; cp && *cp; cp++) *cp = tolower2(*cp);
# endif
      return(0);
}

/*ARGSUSED*/
static int NEAR unalias(argc, argv)
int argc;
char *argv[];
{
      reg_t *re;
      int i, j, n;

      if (argc != 2) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      n = 0;
      re = regexp_init(argv[1], -1);
      for (i = 0; i < maxalias; i++)
            if (regexp_exec(re, aliaslist[i].alias, 0)) {
                  free(aliaslist[i].alias);
                  free(aliaslist[i].comm);
                  maxalias--;
                  for (j = i; j < maxalias; j++)
                        memcpy((char *)&(aliaslist[j]),
                              (char *)&(aliaslist[j + 1]),
                              sizeof(aliastable));
                  i--;
                  n++;
            }
      regexp_free(re);
      if (!n) {
            builtinerror(argv, argv[1], ER_NOENTRY);
            return(-1);
      }
      return(0);
}

VOID printfunction(no, verbose, fp)
int no, verbose;
FILE *fp;
{
      int i;

# if  FD < 2
      fprintf2(fp, "%s ", BL_FUNCTION);
# endif
      fprintf2(fp, "%k() {", userfunclist[no].func);
      if (verbose) fputnl(fp);
      for (i = 0; userfunclist[no].comm[i]; i++) {
            if (verbose) fprintf2(fp, "\t%k;\n", userfunclist[no].comm[i]);
            else fprintf2(fp, " %k;", userfunclist[no].comm[i]);
      }
      fputs(" }", fp);
}

static int NEAR checkuserfunc(argc, argv)
int argc;
char *argv[];
{
      char *cp;
      int i, n;

      n = 0;
      if (n >= argc) return(-1);
      if (!(cp = gettoken(argv[n]))) return(-1);
      if (!*cp) cp = argv[++n];

      if (!cp || *cp != '(') return(-1);
      *(cp++) = '\0';
      if (!*cp) cp = argv[++n];

      if (!cp || *(cp++) != ')') return(-1);
      if (!*cp) cp = argv[++n];

      if (!cp) return(0);
      if (*(cp++) != '{' || *cp) return(-2);

      if (n > 0) {
            for (i = 1; i <= n; i++) free(argv[i]);
            memmove((char *)&(argv[1]), (char *)&(argv[n + 1]),
                  (argc - n) * sizeof(char *));
            argc -= n;
      }

      return(argc);
}

static int NEAR setuserfunc(argc, argv)
int argc;
char *argv[];
{
      char *cp, *tmp, *line, *list[MAXFUNCLINES + 1];
      int i, j, n;

      if (argc <= 1) {
# if  FD >= 2
            builtinerror(argv, NULL, ER_SYNTAXERR);
            return(-1);
# else      /* FD < 2 */
            hitkey(2);
            for (i = 0; i < maxuserfunc; i++) {
                  printfunction(i, 0, stdout);
                  fputnl(stdout);
                  hitkey(0);
            }
            return(0);
# endif     /* FD < 2 */
      }

# if  FD < 2
      if ((n = checkuserfunc(argc - 1, &(argv[FUNCNAME]))) < 0) {
            builtinerror(argv, argv[FUNCNAME], ER_SYNTAXERR);
            return(-1);
      }
# endif

      for (i = 0; i < maxuserfunc; i++)
            if (!strcommcmp(argv[FUNCNAME], userfunclist[i].func)) break;

# if  FD < 2
      if (!n) {
            if (i >= maxuserfunc) {
                  builtinerror(argv, argv[FUNCNAME], ER_NOENTRY);
                  return(-1);
            }
            hitkey(2);
            printfunction(i, 1, stdout);
            fputnl(stdout);
            return(0);
      }
# endif     /* FD < 2 */

      cp = line = catvar(&(argv[FUNCNAME + 1]), ' ');
      for (n = 0; n < MAXFUNCLINES && *cp; n++) {
            if (!(tmp = strtkchr(cp, ';', 0))) break;
            *(tmp++) = '\0';
            list[n] = strdup2(cp);
            cp = skipspace(tmp);
      }
      if (!(tmp = strtkchr(cp, '}', 0)) || *(tmp + 1)) {
            builtinerror(argv, line, ER_SYNTAXERR);
            for (j = 0; j < n; j++) free(list[j]);
            free(line);
            return(-1);
      }

      if (tmp > cp) {
            *tmp = '\0';
            list[n++] = strdup2(cp);
      }
      else if (!n) {
            free(line);
            if (i >= maxuserfunc) {
                  builtinerror(argv, argv[FUNCNAME], ER_NOENTRY);
                  return(-1);
            }

            free(userfunclist[i].func);
            for (j = 0; userfunclist[i].comm[j]; j++)
                  free(userfunclist[i].comm[j]);
            free(userfunclist[i].comm);
            maxuserfunc--;
            for (; i < maxuserfunc; i++)
                  memcpy((char *)&(userfunclist[i]),
                        (char *)&(userfunclist[i + 1]),
                        sizeof(userfunctable));
            return(0);
      }
      free(line);

      if (i >= MAXFUNCTABLE) {
            builtinerror(argv, NULL, ER_OUTOFLIMIT);
            for (j = 0; j < n; j++) free(list[j]);
            return(-1);
      }

      if (i >= maxuserfunc) {
            userfunclist[i].func = strdup2(argv[FUNCNAME]);
# ifdef     COMMNOCASE
            for (cp = userfunclist[i].func; *cp; cp++) *cp = tolower2(*cp);
# endif
            maxuserfunc++;
      }
      else {
            for (j = 0; userfunclist[i].comm[j]; j++)
                  free(userfunclist[i].comm[j]);
            free(userfunclist[i].comm);
      }
      userfunclist[i].comm = (char **)malloc2(sizeof(char *) * (n + 1));
      for (j = 0; j < n; j++) userfunclist[i].comm[j] = list[j];
      userfunclist[i].comm[j] = NULL;
      return(0);
}

static int NEAR exportenv(argc, argv)
int argc;
char *argv[];
{
      char *cp;
      int i;

      if (argc <= 1) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      i = argc - 1;
      if ((cp = getenvval(&i, &(argv[1]))) == (char *)-1) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }
      if (i + 1 < argc) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      setenv2(argv[1], cp, 1);
      if (cp) free(cp);
      adjustpath();
      evalenv();
      return(0);
}

static int NEAR dochdir(argc, argv)
int argc;
char *argv[];
{
      if (argc != 2) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      if (chdir3(argv[1], 0) < 0) {
            builtinerror(argv, argv[1], -1);
            return(-1);
      }
      return(0);
}

static int NEAR loadsource(argc, argv)
int argc;
char *argv[];
{
      int ret;

      if (argc != 2) {
            builtinerror(argv, NULL, ER_FEWMANYARG);
            return(-1);
      }
      ttyiomode(1);
      ret = loadruncom(argv[1], 1);
      stdiomode();
      if (ret < 0) {
            builtinerror(argv, argv[1], ER_SYNTAXERR);
            return(-1);
      }
      return(0);
}
#endif      /* _NOORIGSHELL */

int checkbuiltin(comname)
char *comname;
{
      int i;

      for (i = 0; i < BUILTINSIZ; i++)
            if (!strcommcmp(comname, builtinlist[i].ident)) return(i);
      return(-1);
}

int checkinternal(comname)
char *comname;
{
      int i;

      for (i = 0; i < FUNCLISTSIZ; i++)
            if (!strcommcmp(comname, funclist[i].ident)) return(i);
      return(-1);
}

int execbuiltin(n, argc, argv)
int n, argc;
char *argv[];
{
      return(((*builtinlist[n].func)(argc, argv) < 0)
            ? RET_NOTICE : RET_SUCCESS);
}

int execinternal(n, argc, argv)
int n, argc;
char *argv[];
{
      if (dumbterm > 1) {
            builtinerror(argv, NULL, ER_NOTDUMBTERM);
            return(-1);
      }
      if (fd_restricted && (funclist[n].status & RESTRICT)) {
            fprintf2(stderr, "%s: %k", argv[0], RESTR_K);
            fputnl(stderr);
            return(RET_NOTICE);
      }
      if (argc > 2 || !filelist || maxfile <= 0) {
            fprintf2(stderr, "%s: %k", argv[0], ILFNC_K);
            fputnl(stderr);
            return(RET_NOTICE);
      }
      ttyiomode(0);
      internal_status = (*funclist[n].func)(argv[1]);
      locate(0, n_line - 1);
      stdiomode();
      return(RET_SUCCESS);
}

#ifdef      _NOORIGSHELL
int execpseudoshell(command, comline, ignorelist)
char *command;
int comline, ignorelist;
{
      char *cp, **argv;
      int i, n, nl, argc;

      n = -1;
      command = skipspace(command);
      internal_status = -2;
      if (!(argc = getargs(command, &argv))) {
            freevar(argv);
            return(-1);
      }
      if ((i = checkbuiltin(argv[0])) >= 0) {
            if (comline) {
                  locate(0, n_line - 1);
                  tflush();
            }
            hitkey((comline) ? 1 : -1);
            nl = stdiomode();
            n = execbuiltin(i, argc, argv);
            ttyiomode(nl);
            if (n == RET_SUCCESS) hitkey(3);
            else if (comline) {
                  hideclock = 1;
                  warning(0, ILFNC_K);
            }
      }
      else if (!ignorelist && (i = checkinternal(argv[0])) >= 0) {
            if (comline) {
                  locate(0, n_line - 1);
                  tflush();
            }
            nl = stdiomode();
            n = execinternal(i, argc, argv);
            ttyiomode(nl);
            if (n == RET_SUCCESS) /*EMPTY*/;
            else if (comline) {
                  hideclock = 1;
                  warning(0, ILFNC_K);
            }
      }
# if  FD >= 2
      else if ((i = checkuserfunc(argc, argv)) != -1) {
            if (comline) {
                  locate(0, n_line - 1);
                  tflush();
            }
            nl = stdiomode();
            n = setuserfunc(i, argv);
            n = (n < 0) ? RET_NOTICE : RET_SUCCESS;
            ttyiomode(nl);
            if (n == RET_SUCCESS);
            else if (comline) {
                  hideclock = 1;
                  warning(0, ILFNC_K);
            }
      }
# endif
      else if (isidentchar(*command)) {
            i = argc;
            if ((cp = getenvval(&i, argv)) != (char *)-1 && i == argc) {
                  if (setenv2(argv[0], cp, 0) < 0) error(argv[0]);
                  evalenv();
                  if (cp) free(cp);
                  n = RET_SUCCESS;
            }
      }

      freevar(argv);
      return(n);
}
#endif      /* _NOORIGSHELL */

#ifndef     _NOCOMPLETE
int completebuiltin(com, len, argc, argvp)
char *com;
int len, argc;
char ***argvp;
{
      int i;

      for (i = 0; i < BUILTINSIZ; i++) {
            if (strncommcmp(com, builtinlist[i].ident, len)
            || finddupl(builtinlist[i].ident, argc, *argvp))
                  continue;
            *argvp = (char **)realloc2(*argvp,
                  (argc + 1) * sizeof(char *));
            (*argvp)[argc++] = strdup2(builtinlist[i].ident);
      }
      return(argc);
}

int completeinternal(com, len, argc, argvp)
char *com;
int len, argc;
char ***argvp;
{
      int i;

      for (i = 0; i < FUNCLISTSIZ; i++) {
            if (strncommcmp(com, funclist[i].ident, len)
            || finddupl(funclist[i].ident, argc, *argvp))
                  continue;
            *argvp = (char **)realloc2(*argvp,
                  (argc + 1) * sizeof(char *));
            (*argvp)[argc++] = strdup2(funclist[i].ident);
      }
      return(argc);
}
#endif

#ifdef      DEBUG
VOID freedefine(VOID_A)
{
      int i;

# ifndef    _NOARCHIVE
      for (i = 0; i < maxlaunch; i++) freelaunch(&(launchlist[i]));
      for (i = 0; i < maxarchive; i++) freearch(&(archivelist[i]));
# endif     /* !_NOARCHIVE */
      for (i = 0; i < maxmacro; i++) free(macrolist[i]);
# ifdef     _NOORIGSHELL
      for (i = 0; i < maxalias; i++) {
            free(aliaslist[i].alias);
            free(aliaslist[i].comm);
      }
      for (i = 0; i < maxuserfunc; i++) {
            int j;

            free(userfunclist[i].func);
            for (j = 0; userfunclist[i].comm[j]; j++)
                  free(userfunclist[i].comm[j]);
            free(userfunclist[i].comm);
      }
# endif     /* _NOORIGSHELL */
# ifdef     _USEDOSEMU
      for (i = 0; fdtype[i].name; i++) free(fdtype[i].name);
# endif
      for (i = 0; i < 10; i++) free(helpindex[i]);
}
#endif

Generated by  Doxygen 1.6.0   Back to index