home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / builtin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  103.5 KB  |  4,917 lines

  1. /*
  2.  *
  3.  * builtin.c - builtin commands
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #include "zsh.h"
  22. #include <errno.h>
  23.  
  24. #define makecond() allocnode(N_COND)
  25.  
  26. /* builtin flags */
  27.  
  28. #define BINF_PLUSOPTS    1    /* +xyz legal */
  29. #define BINF_R        2    /* this is r (fc -e -) */
  30. #define BINF_PRINTOPTS    4
  31. #define BINF_SETOPTS    8
  32. #define BINF_FCOPTS    16
  33. #define BINF_TYPEOPT    32
  34. #define BINF_TYPEOPTS    (BINF_TYPEOPT|BINF_PLUSOPTS)
  35. #define BINF_ECHOPTS    64
  36.  
  37. /* builtin funcs */
  38.  
  39. #define BIN_TYPESET 0
  40. #define BIN_BG 1
  41. #define BIN_FG 2
  42. #define BIN_JOBS 3
  43. #define BIN_WAIT 4
  44. #define BIN_DISOWN 5
  45. #define BIN_BREAK 6
  46. #define BIN_CONTINUE 7
  47. #define BIN_EXIT 8
  48. #define BIN_RETURN 9
  49. #define BIN_SHIFT 10
  50. #define BIN_CD 11
  51. #define BIN_POPD 12
  52. #define BIN_PUSHD 13
  53. #define BIN_PRINT 14
  54. #define BIN_EVAL 15
  55. #define BIN_SCHED 16
  56. #define BIN_FC 17
  57. #define BIN_PUSHLINE 18
  58. #define BIN_LOGOUT 19
  59. #define BIN_BUILTIN 20
  60. #define BIN_TEST 21
  61. #define BIN_BRACKET 22
  62. #define BIN_EXPORT 23
  63. #define BIN_TRUE 24
  64. #define BIN_FALSE 25
  65. #define BIN_ECHO 26
  66.  
  67. struct bincmd {
  68.     char *name;
  69.     int (*handlerfunc) DCLPROTO((char *, char **, char *, int));
  70.     int minargs;    /* min # of args */
  71.     int maxargs;    /* max # of args, or -1 for no limit */
  72.     int flags;        /* BINF_flags (see above) */
  73.     int funcid;        /* xbins (see above) for overloaded handlerfuncs */
  74.     char *optstr;    /* string of legal options */
  75.     char *defopts;    /* options set by default for overloaded handlerfuncs */
  76. };
  77.  
  78. static char *auxdata;
  79. static int auxlen;
  80. static int showflag = 0, showflag2 = 0;
  81.  
  82. #define NULLBINCMD ((int (*) DCLPROTO((char *,char **,char *,int))) 0)
  83.  
  84. struct bincmd builtins[] =
  85. {
  86.     {"[", bin_test, 0, -1, 0, BIN_BRACKET, NULL, NULL},
  87.     {".", bin_dot, 1, -1, 0, 0, NULL, NULL},
  88.     {":", bin_colon, 0, -1, 0, BIN_TRUE, NULL, NULL},
  89.     {"alias", bin_alias, 0, -1, 0, 0, "gamr", NULL},
  90.     {"autoload", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "txv", "fu"},
  91.     {"bg", bin_fg, 0, -1, 0, BIN_BG, NULL, NULL},
  92.     {"bindkey", bin_bindkey, 0, -1, 0, 0, "asvemdr", NULL},
  93.     {"break", bin_break, 0, 1, 0, BIN_BREAK, NULL, NULL},
  94.     {"builtin", NULLBINCMD, 0, 0, 0, BIN_BUILTIN, NULL, NULL},
  95.     {"bye", bin_break, 0, 1, 0, BIN_EXIT, NULL, NULL},
  96.     {"cd", bin_cd, 0, 2, 0, BIN_CD, NULL, NULL},
  97.     {"chdir", bin_cd, 0, 2, 0, BIN_CD, NULL, NULL},
  98.     {"compctl", bin_compctl, 0, -1, 0, 0, NULL, NULL},
  99.     {"continue", bin_break, 0, 1, 0, BIN_CONTINUE, NULL, NULL},
  100.     {"declare", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "LRZfilrtux", NULL},
  101.     {"dirs", bin_dirs, 0, -1, 0, 0, "v", NULL},
  102.     {"disable", bin_disable, 0, -1, 0, 0, "-m", NULL},
  103.     {"disown", bin_fg, 1, -1, 0, BIN_DISOWN, NULL, NULL},
  104.     {"echo", bin_print, 0, -1, BINF_PRINTOPTS | BINF_ECHOPTS, BIN_ECHO, "n", "-"},
  105.     {"echotc", bin_echotc, 1, -1, 0, 0, NULL, NULL},
  106.     {"enable", bin_enable, 0, -1, 0, 0, "m", NULL},
  107.     {"eval", bin_eval, 0, -1, 0, BIN_EVAL, NULL, NULL},
  108.     {"exit", bin_break, 0, 1, 0, BIN_EXIT, NULL, NULL},
  109.     {"export", bin_typeset, 0, -1, BINF_TYPEOPTS, BIN_EXPORT, "LRZfilrtu", "x"},
  110.     {"false", bin_colon, 0, -1, 0, BIN_FALSE, NULL, NULL},
  111.     {"fc", bin_fc, 0, -1, BINF_FCOPTS, BIN_FC, "nlreIRWAdDfEm", NULL},
  112.     {"fg", bin_fg, 0, -1, 0, BIN_FG, NULL, NULL},
  113.     {"functions", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "tum", "f"},
  114.     {"getln", bin_read, 0, -1, 0, 0, "ecnAlE", "zr"},
  115.     {"getopts", bin_getopts, 2, -1, 0, 0, NULL, NULL},
  116.     {"hash", bin_hash, 2, 2, 0, 0, NULL, NULL},
  117.     {"history", bin_fc, 0, -1, 0, BIN_FC, "nrdDfEm", "l"},
  118.     {"integer", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "lrtux", "i"},
  119.     {"jobs", bin_fg, 0, -1, 0, BIN_JOBS, "lpZrs", NULL},
  120.     {"kill", bin_kill, 0, -1, 0, 0, NULL, NULL},
  121.     {"let", bin_let, 1, -1, 0, 0, NULL, NULL},
  122.     {"limit", bin_limit, 0, -1, 0, 0, "sh", NULL},
  123.     {"local", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "LRZilrtu", NULL},
  124.     {"log", bin_log, 0, 0, 0, 0, NULL, NULL},
  125.     {"logout", bin_break, 0, 1, 0, BIN_LOGOUT, NULL, NULL},
  126.  
  127. #if defined(MEM_DEBUG) && defined(USE_ZSH_MALLOC)
  128.     {"mem", bin_mem, 0, 0, 0, 0, "v", NULL},
  129. #endif
  130.  
  131.     {"popd", bin_cd, 0, 2, 0, BIN_POPD, NULL, NULL},
  132.     {"print", bin_print, 0, -1, BINF_PRINTOPTS, BIN_PRINT, "RDPnrslzNu0123456789pioOc-", NULL},
  133.     {"pushd", bin_cd, 0, 2, 0, BIN_PUSHD, NULL, NULL},
  134.     {"pushln", bin_print, 0, -1, BINF_PRINTOPTS, BIN_PRINT, NULL, "-nz"},
  135.     {"pwd", bin_pwd, 0, 0, 0, 0, NULL, NULL},
  136.     {"r", bin_fc, 0, -1, BINF_R, BIN_FC, "nrl", NULL},
  137.     {"read", bin_read, 0, -1, 0, 0, "rzu0123456789pkqecnAlE", NULL},
  138.     {"readonly", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "LRZfiltux", "r"},
  139.     {"rehash", bin_rehash, 0, 0, 0, 0, "f", NULL},
  140.     {"return", bin_break, 0, 1, 0, BIN_RETURN, NULL, NULL},
  141.     {"sched", bin_sched, 0, -1, 0, 0, NULL, NULL},
  142.     {"set", bin_set, 0, -1, BINF_SETOPTS | BINF_PLUSOPTS, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZaefghjklmnosuvwxy", NULL},
  143.     {"setopt", bin_setopt, 0, -1, BINF_PLUSOPTS, 0, "0123456789BCDEFGHIJKLMNOPQRSTUVWXYZaefghjklmnosuvwxy", NULL},
  144.     {"shift", bin_break, 0, -1, 0, BIN_SHIFT, NULL, NULL},
  145.     {"source", bin_dot, 1, -1, 0, 0, NULL, NULL},
  146.     {"suspend", bin_suspend, 0, 0, 0, 0, "f", NULL},
  147.     {"test", bin_test, 0, -1, 0, BIN_TEST, NULL, NULL},
  148.     {"ttyctl", bin_ttyctl, 0, 0, 0, 0, "fu", NULL},
  149.     {"times", bin_times, 0, 0, 0, 0, NULL, NULL},
  150.     {"trap", bin_trap, 0, -1, 0, 0, NULL, NULL},
  151.     {"true", bin_colon, 0, -1, 0, BIN_TRUE, NULL, NULL},
  152.     {"type", bin_whence, 0, -1, 0, 0, "pfam", "v"},
  153.     {"typeset", bin_typeset, 0, -1, BINF_TYPEOPTS, 0, "LRZfilrtuxm", NULL},
  154.     {"ulimit", bin_ulimit, 0, 1, 0, 0, "Hacdflmnopstv", NULL},
  155.     {"umask", bin_umask, 0, 1, 0, 0, NULL, NULL},
  156.     {"unalias", bin_unalias, 1, -1, 0, 0, "m", NULL},
  157.     {"unfunction", bin_unhash, 1, -1, 0, 0, "m", NULL},
  158.     {"unhash", bin_unhash, 1, -1, 0, 0, "m", NULL},
  159.     {"unlimit", bin_unlimit, 0, -1, 0, 0, "h", NULL},
  160.     {"unset", bin_unset, 1, -1, 0, 0, "m", NULL},
  161.     {"unsetopt", bin_setopt, 0, -1, BINF_PLUSOPTS, 1, "0123456789BCDEFGHIJKLMNOPQRSTUWXYZabefghjklmnosuvwxy", NULL},
  162.     {"vared", bin_vared, 1, 6, 0, 0, NULL, NULL},
  163.     {"wait", bin_fg, 0, -1, 0, BIN_WAIT, NULL, NULL},
  164.     {"whence", bin_whence, 0, -1, 0, 0, "pvcfam", NULL},
  165.     {"which", bin_whence, 0, -1, 0, 0, "pam", "c"},
  166.     {NULL, NULLBINCMD, 0, 0, 0, 0, NULL, NULL}
  167. };
  168.  
  169. /* print options */
  170.  
  171. SPROTO(void prtopt, (int set));
  172.  
  173. static void prtopt(set)
  174. int set;
  175. {
  176.     struct option *opp;
  177.  
  178.     if (isset(KSHOPTIONPRINT)) {
  179.     printf("Current option settings\n");
  180.     for (opp = optns; opp->name; opp++)
  181.         printf("%-20s%s\n", opp->name, isset(opp->id) ? "on" : "off");
  182.     } else
  183.     for (opp = optns; opp->name; opp++)
  184.         if ((!set) == (!isset(opp->id)))
  185.         puts(opp->name);
  186. }
  187.  
  188. /* add builtins to the command hash table */
  189.  
  190. void addbuiltins()
  191. {                /**/
  192.     struct cmdnam *c;
  193.     struct bincmd *b;
  194.     int t0;
  195.  
  196.     for (t0 = 0, b = builtins; b->name; b++, t0++) {
  197.     c = (Cmdnam) zcalloc(sizeof *c);
  198.     c->flags = BUILTIN;
  199.     c->u.binnum = t0;
  200.     addhnode(ztrdup(b->name), c, cmdnamtab, freecmdnam);
  201.     }
  202. }
  203.  
  204. /* enable */
  205.  
  206. int bin_enable(name, argv, ops, whocares)    /**/
  207. char *name;
  208. char **argv;
  209. char *ops;
  210. int whocares;
  211. {
  212.     struct cmdnam *c;
  213.     struct bincmd *b;
  214.     int t0, ret = 0;
  215.     Comp com;
  216.  
  217.     if (!*argv) {
  218.     listhtable(cmdnamtab, (HFunc) penabledcmd);
  219.     return 0;
  220.     }
  221.     for (; *argv; argv++) {
  222.     if (ops['m']) {
  223.         tokenize(*argv);
  224.         if (!(com = parsereg(*argv))) {
  225.         ret = 1;
  226.         untokenize(*argv);
  227.         zwarnnam(name, "bad pattern : %s", *argv, 0);
  228.         continue;
  229.         }
  230.         for (t0 = 0, b = builtins; b->name; b++, t0++)
  231.         if (domatch(b->name, com, 0)) {
  232.             c = (Cmdnam) zcalloc(sizeof *c);
  233.             c->flags = BUILTIN;
  234.             c->u.binnum = t0;
  235.             addhnode(ztrdup(b->name), c, cmdnamtab, freecmdnam);
  236.         }
  237.     } else {
  238.         for (t0 = 0, b = builtins; b->name; b++, t0++)
  239.         if (!strcmp(*argv, b->name))
  240.             break;
  241.         if (!b->name) {
  242.         zerrnam(name, "no such builtin: %s", *argv, 0);
  243.         ret = 1;
  244.         } else {
  245.         c = (Cmdnam) zcalloc(sizeof *c);
  246.         c->flags = BUILTIN;
  247.         c->u.binnum = t0;
  248.         addhnode(ztrdup(b->name), c, cmdnamtab, freecmdnam);
  249.         }
  250.     }
  251.     }
  252.     return ret;
  253. }
  254.  
  255. /* :, true, false */
  256.  
  257. int bin_colon(name, argv, ops, func)    /**/
  258. char *name;
  259. char **argv;
  260. char *ops;
  261. int func;
  262. {
  263.     return (func == BIN_FALSE);
  264. }
  265.  
  266. /* break, bye, continue, exit, logout, return, shift */
  267.  
  268. int bin_break(name, argv, ops, func)    /**/
  269. char *name;
  270. char **argv;
  271. char *ops;
  272. int func;
  273. {
  274.     int num = lastval, nump = 0;
  275.  
  276.     if (*argv && (**argv == '-' || idigit(**argv))) {
  277.     num = matheval(*argv++);
  278.     nump = 1;
  279.     }
  280.     if ((func == BIN_BREAK || func == BIN_CONTINUE) && !loops) {
  281.     if (func == BIN_CONTINUE)
  282.         zerrnam(name, "not in loop", NULL, 0);
  283.     return 1;
  284.     }
  285.     switch (func) {
  286.     case BIN_CONTINUE:
  287.     contflag = 1;
  288.     case BIN_BREAK:
  289.     breaks = nump ? num : 1;
  290.     if (breaks > loops)
  291.         breaks = loops;
  292.     break;
  293.     case BIN_RETURN:
  294.     if (isset(INTERACTIVE) || locallevel || sourcelevel) {
  295.         retflag = 1;
  296.         breaks = loops;
  297.         lastval = num;
  298.         if (trapreturn)
  299.         trapreturn = lastval;
  300.         return lastval;
  301.     } /* else fall through */
  302.     case BIN_LOGOUT:
  303.     if (func == BIN_LOGOUT && !islogin) {
  304.         zerrnam(name, "not login shell", NULL, 0);
  305.         return 1;
  306.     }
  307.     case BIN_EXIT:
  308.     zexit(num);
  309.     break;
  310.     case BIN_SHIFT:
  311.     {
  312.         char **s;
  313.         int l;
  314.  
  315.         if (!nump)
  316.         num = 1;
  317.         if (num < 0) {
  318.         zerrnam(name, "bad number", NULL, 0);
  319.         return 1;
  320.         }
  321.         if (*argv) {
  322.         for (; *argv; argv++)
  323.             if ((s = getaparam(*argv))) {
  324.             if (num < (l = arrlen(s)))
  325.                 l = num;
  326.             permalloc();
  327.             s = arrdup(s + l);
  328.             heapalloc();
  329.             setaparam(*argv, s);
  330.             }
  331.         } else {
  332.         if (num > arrlen(pparams))
  333.             num = arrlen(pparams);
  334.         permalloc();
  335.         s = arrdup(pparams + num);
  336.         heapalloc();
  337.         freearray(pparams);
  338.         pparams = s;
  339.         }
  340.         break;
  341.     }
  342.     }
  343.     return 0;
  344. }
  345.  
  346. /* bg, disown, fg, jobs, wait */
  347.  
  348. int bin_fg(name, argv, ops, func)    /**/
  349. char *name;
  350. char **argv;
  351. char *ops;
  352. int func;
  353. {
  354.     int job, lng, firstjob = -1, retval = 0;
  355.  
  356.     if (ops['Z']) {
  357.     if (*argv)
  358.         strcpy(hackzero, *argv);
  359.     return 0;
  360.     }
  361.     lng = (ops['l']) ? 1 : (ops['p']) ? 2 : 0;
  362.     if ((func == BIN_FG || func == BIN_BG) && !jobbing) {
  363.     zwarnnam(name, "no job control in this shell.", NULL, 0);
  364.     return 1;
  365.     }
  366.     if (unset(NOTIFY))
  367.     scanjobs();
  368.     if (curjob != -1 && !(jobtab[curjob].stat & STAT_INUSE)) {
  369.     curjob = prevjob;
  370.     setprevjob();
  371.     if (curjob != -1 && !(jobtab[curjob].stat & STAT_INUSE))
  372.         curjob = prevjob;
  373.     setprevjob();
  374.     }
  375.     if (func == BIN_JOBS)
  376.     stopmsg = 2;
  377.     if (!*argv)
  378.     if (func == BIN_FG || func == BIN_BG) {
  379.         if (curjob == -1 || curjob == thisjob) {
  380.         zwarnnam(name, "no current job", NULL, 0);
  381.         return 1;
  382.         }
  383.         firstjob = curjob;
  384.     } else if (func == BIN_JOBS) {
  385.         for (job = 0; job != MAXJOB; job++)
  386.         if (job != thisjob && jobtab[job].stat) {
  387.             if ((!ops['r'] && !ops['s']) ||
  388.             (ops['r'] && ops['s']) ||
  389.             (ops['r'] && !(jobtab[job].stat & STAT_STOPPED)) ||
  390.             (ops['s'] && jobtab[job].stat & STAT_STOPPED))
  391.             printjob(job + jobtab, lng);
  392.         }
  393.         return 0;
  394.     } else {
  395.         for (job = 0; job != MAXJOB; job++)
  396.         if (job != thisjob && jobtab[job].stat)
  397.             waitjob(job);
  398.         return lastval;
  399.     }
  400.     for (; (firstjob != -1) || *argv; (void)(*argv && argv++)) {
  401.     int stopped, ocj = thisjob;
  402.  
  403.     if (func == BIN_WAIT && isanum(*argv)) {
  404.         waitforpid((long)atoi(*argv));
  405.         retval = lastval;
  406.         thisjob = ocj;
  407.         continue;
  408.     }
  409.     job = (*argv) ? getjob(*argv, name) : firstjob;
  410.     firstjob = -1;
  411.     if (job == -1)
  412.         break;
  413.     if (!(jobtab[job].stat & STAT_INUSE)) {
  414.         zwarnnam(name, "no such job: %d", 0, job);
  415.         return 1;
  416.     }
  417.     switch (func) {
  418.     case BIN_FG:
  419.     case BIN_BG:
  420.     case BIN_WAIT:
  421.         if ((stopped = (jobtab[job].stat & STAT_STOPPED)))
  422.         makerunning(jobtab + job);
  423.         else if (func == BIN_BG) {
  424.         zwarnnam(name, "job already in background", NULL, 0);
  425.         thisjob = ocj;
  426.         return 1;
  427.         }
  428.         if (curjob == job) {
  429.         curjob = prevjob;
  430.         prevjob = (func == BIN_BG) ? -1 : job;
  431.         }
  432.         if (prevjob == job)
  433.         prevjob = -1;
  434.         if (prevjob == -1)
  435.         setprevjob();
  436.         if (curjob == -1) {
  437.         curjob = prevjob;
  438.         setprevjob();
  439.         }
  440.         if (func != BIN_WAIT)
  441.         printjob(jobtab + job, (stopped) ? -1 : 0);
  442.         if (func != BIN_BG) {
  443.         thisjob = job;
  444.         if (strcmp(jobtab[job].pwd, pwd)) {
  445.             printf("(pwd : ");
  446.             printdir(jobtab[job].pwd);
  447.             printf(")\n");
  448.         }
  449.         fflush(stdout);
  450.         attachtty(jobtab[job].gleader);
  451.         }
  452.         if (stopped) {
  453.         if (func != BIN_BG && jobtab[job].ty)
  454.             settyinfo(jobtab[job].ty);
  455.         killpg(jobtab[job].gleader, SIGCONT);
  456.         }
  457.         if (func != BIN_BG) {
  458.         waitjobs();
  459.         retval = lastval;
  460.         }
  461.         break;
  462.     case BIN_JOBS:
  463.         printjob(job + jobtab, lng);
  464.         break;
  465.     case BIN_DISOWN:
  466.         {
  467.         static struct job zero;
  468.  
  469.         jobtab[job] = zero;
  470.         break;
  471.         }
  472.     }
  473.     thisjob = ocj;
  474.     }
  475.     return retval;
  476. }
  477.  
  478. /* let */
  479.  
  480. int bin_let(name, argv, ops, func)    /**/
  481. char *name;
  482. char **argv;
  483. char *ops;
  484. int func;
  485. {
  486.     long val = 0;
  487.  
  488.     while (*argv)
  489.     val = matheval(*argv++);
  490.     return !val;
  491. }
  492.  
  493. /* print the directory stack */
  494.  
  495. SPROTO(void pdstack, (void));
  496.  
  497. static void pdstack()
  498. {
  499.     Lknode node;
  500.  
  501.     printdir(pwd);
  502.     for (node = firstnode(dirstack); node; incnode(node)) {
  503.     putchar(' ');
  504.     printdir(getdata(node));
  505.     }
  506.     putchar('\n');
  507. }
  508.  
  509. /* exit the shell */
  510.  
  511. void zexit(val)            /**/
  512. int val;
  513. {
  514.     if (isset(MONITOR))
  515.     if (!stopmsg) {
  516.         checkjobs();
  517.         if (stopmsg) {
  518.         stopmsg = 2;
  519.         return;
  520.         }
  521.     } else
  522.         killrunjobs();
  523.     if (unset(NORCS) && interact) {
  524.     if (isset(APPENDHISTORY))
  525.         savehistfile(getsparam("HISTFILE"), 1, 3);
  526.     else
  527.         savehistfile(getsparam("HISTFILE"), 1, 0);
  528.     if (islogin)
  529.         sourcehome(".zlogout");
  530.     }
  531.     if (sigtrapped[SIGEXIT])
  532.     dotrap(SIGEXIT);
  533.     exit(val);
  534. }
  535.  
  536. /* identify an option name */
  537.  
  538. int optlookup(s)        /**/
  539. char *s;
  540. {
  541.     char *t;
  542.     struct option *o;
  543.  
  544.     t = s = dupstring(s);
  545.     while (*t)
  546.     if (*t == '_')
  547.         chuck(t);
  548.     else {
  549.         *t = tulower(*t);
  550.         t++;
  551.     }
  552.     for (o = optns; o->name; o++)
  553.     if (!strcmp(o->name, s))
  554.         return (int) o->id;
  555.     return -1;
  556. }
  557.  
  558. /* setopt, unsetopt */
  559.  
  560. int bin_setopt(nam, args, ops, isun)    /**/
  561. char *nam;
  562. char **args;
  563. char *ops;
  564. int isun;
  565. {
  566.     struct option *opp;
  567.     int c, match;
  568.  
  569.     match = ops[(int)'m'];
  570.     ops['m'] = 0;
  571.     if (!ops['@'] && !*args) {
  572.     prtopt(!isun);
  573.     return 0;
  574.     }
  575.     for (opp = optns; opp->name; opp++)
  576.     if (ops[opp->id] == 1 + isun)
  577.         opts[(int)opp->id] = OPT_SET;
  578.     else if (ops[(int)opp->id] == 2 - isun)
  579.         opts[(int)opp->id] = OPT_UNSET;
  580.     if (!match)
  581.     while (*args) {
  582.         c = optlookup(*args++);
  583.         if (c != -1) {
  584.         if (c == INTERACTIVE)
  585.             zwarnnam(nam, "can't change option: %s", args[-1], 0);
  586.         else
  587.             opts[c] = (isun) ? OPT_UNSET : OPT_SET;
  588.         } else {
  589.         zwarnnam(nam, "no such option: %s", args[-1], 0);
  590.         return 1;
  591.         }
  592.     } else {
  593.     Comp com;
  594.     struct option *o;
  595.  
  596.     while (*args) {
  597.         tokenize(*args);
  598.         if (!(com = parsereg(*args))) {
  599.         untokenize(*args);
  600.         zwarnnam(nam, "bad pattern : %s", *args, 0);
  601.         continue;
  602.         }
  603.         for (o = optns; o->name; o++)
  604.         if (o->id != INTERACTIVE && o->id != MONITOR &&
  605.             domatch(o->name, com, 0))
  606.             opts[(int)o->id] = (isun) ? OPT_UNSET : OPT_SET;
  607.         args++;
  608.     }
  609.     }
  610.     return 0;
  611. }
  612.  
  613. /* execute func on each member of the hash table ht */
  614.  
  615. static hnamcmp DCLPROTO((struct hashnode ** a, struct hashnode ** b));
  616. static int hnamcmp(a, b)
  617. struct hashnode **a;
  618. struct hashnode **b;
  619. {
  620.     return forstrcmp(&((*a)->nam), &((*b)->nam));
  621. }
  622.  
  623. void listhtable(ht, func)    /**/
  624. Hashtab ht;
  625. HFunc func;
  626. {
  627.     int t0;
  628.     struct hashnode *hn;
  629.  
  630. #ifndef HASHORDER
  631.  
  632.     int nhash;
  633.     struct hashnode **hnsorttab, **htp;
  634.  
  635.     hnsorttab = (struct hashnode **)zalloc(ht->ct * sizeof(struct hashnode *));
  636.  
  637.     for (htp = hnsorttab, t0 = ht->hsize - 1; t0 >= 0; t0--)
  638.     for (hn = ht->nodes[t0]; hn; hn = hn->next)
  639.         *htp++ = hn;
  640.  
  641.     qsort((vptr) & hnsorttab[0], ht->ct, sizeof(struct hashnode *),
  642.                (int (*)DCLPROTO((const void *, const void *)))hnamcmp);
  643.  
  644.     for (htp = hnsorttab, nhash = 0; nhash < ht->ct; nhash++, htp++)
  645.     func((*htp)->nam, (char *)(*htp));
  646.  
  647.     free(hnsorttab);
  648.  
  649. #else
  650.  
  651.     for (t0 = ht->hsize - 1; t0 >= 0; t0--)
  652.     for (hn = ht->nodes[t0]; hn; hn = hn->next)
  653.         func(hn->nam, (char *)hn);
  654.  
  655. #endif
  656. }
  657.  
  658. /* print a shell function (used with listhtable) */
  659.  
  660. void pshfunc(s, cc)        /**/
  661. char *s;
  662. Cmdnam cc;
  663. {
  664.     char *t;
  665.  
  666.     if (!(cc->flags & SHFUNC))
  667.     return;
  668.     if (showflag && (cc->flags & showflag2) != showflag2)
  669.     return;
  670.     if (cc->flags & PMFLAG_u)
  671.     printf("undefined ");
  672.     if (cc->flags & PMFLAG_t)
  673.     printf("traced ");
  674.     if (!cc->u.list || !showflag) {
  675.     printf("%s ()\n", s);
  676.     return;
  677.     }
  678.     t = getpermtext((vptr) dupstruct((vptr) cc->u.list));
  679.     printf("%s () {\n\t%s\n}\n", s, t);
  680.     zsfree(t);
  681. }
  682.  
  683. void penabledcmd(s, cc)        /**/
  684. char *s;
  685. Cmdnam cc;
  686. {
  687.     if (cc->flags & BUILTIN)
  688.     printf("%s\n", s);
  689. }
  690.  
  691. void pdisabledcmd(s, cc)    /**/
  692. char *s;
  693. Cmdnam cc;
  694. {
  695.     if (cc->flags & DISABLED)
  696.     printf("%s\n", s);
  697. }
  698.  
  699. void niceprintf(s, f)        /**/
  700. char *s;
  701. FILE *f;
  702. {
  703.     for (; *s; s++) {
  704.     if (isprint(*s))
  705.         fputc(*s, f);
  706.     else if (*s == '\n') {
  707.         putc('\\', f);
  708.         putc('n', f);
  709.     } else {
  710.         putc('^', f);
  711.         fputc(*s | 0x40, f);
  712.     }
  713.     }
  714. }
  715.  
  716. int bin_umask(nam, args, ops, func)    /**/
  717. char *nam;
  718. char **args;
  719. char *ops;
  720. int func;
  721. {
  722.     int um;
  723.     char *s = *args;
  724.  
  725.     um = umask(0);
  726.     umask(um);
  727.     if (!s) {
  728.     printf("%03o\n", (unsigned) um);
  729.     return 0;
  730.     }
  731.     if (idigit(*s)) {
  732.     um = zstrtol(s, &s, 8);
  733.     if (*s) {
  734.         zwarnnam(nam, "bad umask", NULL, 0);
  735.         return 1;
  736.     }
  737.     } else {
  738.     int whomask, umaskop, mask;
  739.  
  740.     for (;;) {
  741.         whomask = 0;
  742.         while (*s == 'u' || *s == 'g' || *s == 'o')
  743.         if (*s == 'u')
  744.             s++, whomask |= 0100;
  745.         else if (*s == 'g')
  746.             s++, whomask |= 0010;
  747.         else if (*s == 'o')
  748.             s++, whomask |= 0001;
  749.         if (!whomask)
  750.         whomask = 0111;
  751.         umaskop = (int) *s;
  752.         if (!(umaskop == '+' || umaskop == '-' || umaskop == '=')) {
  753.         zwarnnam(nam, "bad symbolic mode operator: %c", NULL, umaskop);
  754.         return 1;
  755.         }
  756.         mask = 0;
  757.         while (*++s && *s != ',')
  758.         if (*s == 'r')
  759.             mask |= 04 * whomask;
  760.         else if (*s == 'w')
  761.             mask |= 02 * whomask;
  762.         else if (*s == 'x')
  763.             mask |= whomask;
  764.         else {
  765.             zwarnnam(nam, "bad symbolic mode permission: %c",
  766.                  NULL, *s);
  767.             return 1;
  768.         }
  769.         if (umaskop == '+')
  770.         um &= ~mask;
  771.         else if (umaskop == '-')
  772.         um |= mask;
  773.         else        /* umaskop == '=' */
  774.         um = (um | (whomask * 07)) & ~mask;
  775.         if (*s == ',')
  776.         s++;
  777.         else
  778.         break;
  779.     }
  780.     if (*s) {
  781.         zwarnnam(nam, "bad character in symbolic mode: %c", NULL, *s);
  782.         return 1;
  783.     }
  784.     }
  785.     umask(um);
  786.     return 0;
  787. }
  788.  
  789. /* type, whence, which */
  790.  
  791. int bin_whence(nam, argv, ops, func)    /**/
  792. char *nam;
  793. char **argv;
  794. char *ops;
  795. int func;
  796. {
  797.     struct cmdnam *chn;
  798.     struct alias *a;
  799.     int retval = 0;
  800.     int csh = ops[(int)'c'], all = ops[(int)'a'];
  801.     int v = ops['v'] || csh;
  802.     char *cnam;
  803.     int informed;
  804.  
  805.     for (; *argv; argv++) {
  806.     if (ops['m']) {
  807.         int i, n;
  808.         Comp com;
  809.  
  810.         tokenize(*argv);
  811.         if (!(com = parsereg(*argv))) {
  812.         retval = 1;
  813.         untokenize(*argv);
  814.         zwarnnam(nam, "bad pattern : %s", *argv, 0);
  815.         continue;
  816.         }
  817.         if (!ops['p']) {
  818.         n = aliastab->hsize;
  819.         for (i = 0; i < n; i++) {
  820.             for (a = (struct alias *)aliastab->nodes[i]; a;
  821.              a = (struct alias *)a->next) {
  822.             if (a->nam && domatch(a->nam, com, 0)) {
  823.                 if (a->cmd < 0)
  824.                 printf((csh) ? "%s: shell reserved word\n" :
  825.                        (v) ? "%s is a reserved word\n" : "%s\n", a->nam);
  826.                 else if (!v)
  827.                 puts(a->text);
  828.                 else if (a->cmd)
  829.                 printf((csh) ? "%s: aliased to %s\n" :
  830.                        "%s is an alias for %s\n", a->nam, a->text);
  831.                 else
  832.                 printf((csh) ? "%s: globally aliased to %s\n" :
  833.                        "%s is a global alias for %s\n", a->nam, a->text);
  834.             }
  835.             }
  836.         }
  837.         n = cmdnamtab->hsize;
  838.         for (i = 0; i < n; i++) {
  839.             for (chn = (struct cmdnam *)cmdnamtab->nodes[i]; chn;
  840.              chn = (struct cmdnam *)chn->next) {
  841.             if (chn->nam &&
  842.                 (chn->flags & (SHFUNC | BUILTIN)) &&
  843.                 !(chn->flags & EXCMD) &&
  844.                 domatch(chn->nam, com, 0)) {
  845.                 if (chn->flags & SHFUNC) {
  846.                 if (csh || ops['f']) {
  847.                     showflag = 1;
  848.                     showflag2 = 0;
  849.                     pshfunc(chn->nam, chn);
  850.                 } else {
  851.                     printf((v) ? "%s is a function\n" : "%s\n", chn->nam);
  852.                 }
  853.                 } else
  854.                 printf((csh) ? "%s: shell built-in command\n" :
  855.                        (v) ? "%s is a shell builtin\n" : "%s\n", chn->nam);
  856.             }
  857.             }
  858.         }
  859.         }
  860.         fullhash();
  861.         n = cmdnamtab->hsize;
  862.         for (i = 0; i < n; i++) {
  863.         for (chn = (struct cmdnam *)cmdnamtab->nodes[i]; chn;
  864.              chn = (struct cmdnam *)chn->next) {
  865.             if (chn->nam && (chn->flags & EXCMD) &&
  866.             domatch(chn->nam, com, 0)) {
  867.             if (chn->flags & BUILTIN)
  868.                 printf("%s is hashed to %s\n", chn->nam, 
  869.                    chn->u.cmd);
  870.             else if (v && !csh)
  871.                 printf("%s is %s/%s\n", chn->nam,
  872.                    chn->u.name ? *(chn->u.name) : "", 
  873.                    chn->nam);
  874.             else
  875.                 printf("%s/%s\n", chn->u.name ? *(chn->u.name) : "",
  876.                    chn->nam);
  877.             }
  878.         }
  879.         }
  880.  
  881.     } else {
  882.         informed = 0;
  883.         if (!ops['p'] && (a = (Alias) gethnode(*argv, aliastab))) {
  884.         if (a->cmd < 0)
  885.             printf((csh) ? "%s: shell reserved word\n" :
  886.                (v) ? "%s is a reserved word\n" : "%s\n", *argv);
  887.         else if (!v)
  888.             puts(a->text);
  889.         else if (a->cmd)
  890.             printf((csh) ? "%s: aliased to %s\n" :
  891.                "%s is an alias for %s\n", *argv, a->text);
  892.         else
  893.             printf((csh) ? "%s: globally aliased to %s\n" :
  894.                "%s is a global alias for %s\n", *argv, a->text);
  895.         if (!all)
  896.             continue;
  897.         informed = 1;
  898.         }
  899.         if (!ops['p'] && (chn = (Cmdnam) gethnode(*argv, cmdnamtab)) &&
  900.         (chn->flags & (SHFUNC | BUILTIN))) {
  901.         if (chn->flags & EXCMD)
  902.             printf("%s is hashed to %s\n", chn->nam, chn->u.cmd);
  903.         else if (chn->flags & SHFUNC) {
  904.             if (csh || ops['f']) {
  905.             showflag = 1;
  906.             showflag2 = 0;
  907.             pshfunc(*argv, chn);
  908.             } else {
  909.             printf((v) ? "%s is a function\n" : "%s\n", *argv);
  910.             }
  911.         } else
  912.             printf((csh) ? "%s: shell built-in command\n" :
  913.                (v) ? "%s is a shell builtin\n" : "%s\n", *argv);
  914.         if (!all)
  915.             continue;
  916.         informed = 1;
  917.         }
  918.         if (all) {
  919.         char **pp, buf[MAXPATHLEN], *z;
  920.  
  921.         for (pp = path; *pp; pp++) {
  922.             z = buf;
  923.             strucpy(&z, *pp);
  924.             *z++ = '/';
  925.             strcpy(z, *argv);
  926.             if (iscom(buf)) {
  927.             if (v && !csh)
  928.                 printf("%s is %s\n", *argv, buf);
  929.             else
  930.                 puts(buf);
  931.             informed = 1;
  932.             }
  933.         }
  934.         if (!informed && v) {
  935.             printf("%s not found\n", *argv);
  936.             retval = 1;
  937.         }
  938.         } else if (!(cnam = findcmd(*argv))) {
  939.         if (v)
  940.             printf("%s not found\n", *argv);
  941.         retval = 1;
  942.         } else {
  943.         if (v && !csh)
  944.             printf("%s is %s\n", *argv, cnam);
  945.         else
  946.             puts(cnam);
  947.         zsfree(cnam);
  948.         }
  949.     }
  950.     }
  951.     return retval;
  952. }
  953.  
  954. /* cd, chdir, pushd, popd */
  955.  
  956. int doprintdir = 0; /* set in exec.c (for autocd) */
  957.  
  958. int bin_cd(nam, argv, ops, func)/**/
  959. char *nam;
  960. char **argv;
  961. char *ops;
  962. int func;
  963. {
  964.     char *dest, *dir;
  965.  
  966.     doprintdir = (doprintdir == -1);
  967.  
  968.     if (func == BIN_CD && isset(AUTOPUSHD))
  969.     func = BIN_PUSHD;
  970.     dir = dest = cd_get_dest(nam, argv, ops, func);
  971.     if (!dest)
  972.     return 1;
  973.     dest = cd_do_chdir(nam, dest);
  974.     if (dest != dir)
  975.     zsfree(dir);
  976.     if (!dest)
  977.     return 1;
  978.     cd_new_pwd(func, dest);
  979.     zsfree(dest);
  980.     return 0;
  981. }
  982.  
  983. char *cd_get_dest(nam, argv, ops, func)    /**/
  984. char *nam;
  985. char **argv;
  986. char *ops;
  987. int func;
  988. {
  989.     char *dest = NULL;
  990.  
  991.     if (!argv[0])
  992.     if (func == BIN_CD || ((func == BIN_PUSHD && isset(PUSHDTOHOME))
  993.                    || empty(dirstack)))
  994.         dest = ztrdup(home);
  995.     else
  996.         dest = ztrdup(getnode(dirstack));
  997.     else if (!argv[1]) {
  998.     Lknode n;
  999.     int dd;
  1000.     char *end;
  1001.  
  1002.     doprintdir++;
  1003.     if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '-' : '+')) {
  1004.         dd = zstrtol(argv[0] + 1, &end, 10) - 1;
  1005.         if (dd >= 0 && *end == '\0') {
  1006.         for (n = firstnode(dirstack); n && dd; dd--, incnode(n));
  1007.         if (!n) {
  1008.             zwarnnam(nam, "no such entry in dir stack", NULL, 0);
  1009.             return NULL;
  1010.         }
  1011.         dest = (char *)remnode(dirstack, n);
  1012.         }
  1013.     } else if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '+' : '-')) {
  1014.         dd = zstrtol(argv[0] + 1, &end, 10);
  1015.         if (*end == '\0') {
  1016.         for (n = lastnode(dirstack); n != (Lknode) dirstack && dd;
  1017.              dd--, n = prevnode(n));
  1018.         if (n == (Lknode) dirstack) {
  1019.             zwarnnam(nam, "no such entry in dir stack", NULL, 0);
  1020.             return NULL;
  1021.         }
  1022.         dest = (char *)remnode(dirstack, n);
  1023.         }
  1024.     }
  1025.     if (!dest)
  1026.         dest = ztrdup(strcmp(argv[0], "-") ? (doprintdir--, argv[0]) :
  1027.               oldpwd);              
  1028.     } else {
  1029.     char *u;
  1030.     int len1, len2, len3;
  1031.  
  1032.     if (!(u = ztrstr(pwd, argv[0]))) {
  1033.         zwarnnam(nam, "string not in pwd: %s", argv[0], 0);
  1034.         return NULL;
  1035.     }
  1036.     len1 = strlen(argv[0]);
  1037.     len2 = strlen(argv[1]);
  1038.     len3 = u - pwd;
  1039.     dest = (char *)zalloc(len3 + len2 + strlen(u + len1) + 1);
  1040.     strncpy(dest, pwd, len3);
  1041.     strcpy(dest + len3, argv[1]);
  1042.     strcat(dest, u + len1);
  1043.     doprintdir++;
  1044.     }
  1045.     return dest;
  1046. }
  1047.  
  1048. char *cd_do_chdir(cnam, dest)    /**/
  1049. char *cnam;
  1050. char *dest;
  1051. {
  1052.     int hasdot = 0, eno = ENOENT;
  1053.     int nocdpath = dest[0] == '.' &&
  1054.     (dest[1] == '/' || !dest[1] || (dest[1] == '.' &&
  1055.                     (dest[2] == '/' || !dest[1])));
  1056.     char **pp, *ret;
  1057.  
  1058.     if (*dest == '/') {
  1059.     if ((ret = cd_try_chdir(NULL, dest)))
  1060.         return ret;
  1061.     zwarnnam(cnam, "%e: %s", dest, errno);
  1062.     return NULL;
  1063.     }
  1064.     if (!nocdpath)
  1065.     for (pp = cdpath; *pp; pp++)
  1066.         if ((*pp)[0] == '.' && (*pp)[1] == '\0')
  1067.         hasdot = 1;
  1068.     if (!hasdot || nocdpath) {
  1069.     if ((ret = cd_try_chdir(NULL, dest)))
  1070.         return ret;
  1071.     if (errno != ENOENT)
  1072.         eno = errno;
  1073.     }
  1074.     if (!nocdpath)
  1075.     for (pp = cdpath; *pp; pp++) {
  1076.         if ((ret = cd_try_chdir(*pp, dest))) {
  1077.         if (strcmp(*pp, ".")) {
  1078.             doprintdir++;
  1079.         }
  1080.         return ret;
  1081.         }
  1082.         if (errno != ENOENT)
  1083.         eno = errno;
  1084.     }
  1085.     if ((ret = cd_able_vars(dest))) {
  1086.     if ((ret = cd_try_chdir(NULL, ret))) {
  1087.         doprintdir++;
  1088.         return ret;
  1089.     }
  1090.     if (errno != ENOENT)
  1091.         eno = errno;
  1092.     }
  1093.     zwarnnam(cnam, "%e: %s", dest, eno);
  1094.     return NULL;
  1095. }
  1096.  
  1097. char *cd_able_vars(s)  /**/
  1098. char *s;
  1099. {
  1100.     char *rest;
  1101.  
  1102.     if (isset(CDABLEVARS)) {
  1103.     for (rest = s; *rest && *rest != '/'; rest++)
  1104.         ;
  1105.     s = getnamedir(s, rest-s);
  1106.  
  1107.     if (s && *rest)
  1108.         s = dyncat(s, rest);
  1109.  
  1110.     return s;
  1111.     }
  1112.     return NULL;
  1113. }
  1114.  
  1115. char *cd_try_chdir(pfix, dest)    /**/
  1116. char *pfix;
  1117. char *dest;
  1118. {
  1119.     char buf[MAXPATHLEN], buf2[MAXPATHLEN];
  1120.     char *s;
  1121.     int dotsct;
  1122.  
  1123.     if (pfix)
  1124.     sprintf(buf, "%s/%s", (!strcmp("/", pfix)) ? "" : pfix, dest);
  1125.     else
  1126.     strcpy(buf, dest);
  1127.     dotsct = fixdir(buf2, buf);
  1128.     if (buf2[0] == '/')
  1129.     return (chdir(buf) == -1) ? NULL : ztrdup(buf2);
  1130.     if (!dotsct) {
  1131.     if (chdir(buf) == -1)
  1132.         return NULL;
  1133.     if (*buf2)
  1134.         sprintf(buf, "%s/%s", (!strcmp("/", pwd)) ? "" : pwd, buf2);
  1135.     else
  1136.         strcpy(buf, pwd);
  1137.     return ztrdup(buf);
  1138.     }
  1139.     strcpy(buf, pwd);
  1140.     s = buf + strlen(buf) - 1;
  1141.     while (dotsct--)
  1142.     while (s != buf)
  1143.         if (*--s == '/')
  1144.         break;
  1145.     if (s == buf || *buf2)
  1146.     s++;
  1147.     strcpy(s, buf2);
  1148.     if (chdir(buf) != -1 || chdir(dest) != -1)
  1149.     return ztrdup(buf);
  1150.     return NULL;
  1151. }
  1152.  
  1153. int fixdir(d, s)        /**/
  1154. char *d;
  1155. char *s;
  1156. {
  1157.     int ct = 0;
  1158.     char *d0 = d;
  1159.  
  1160. #ifdef HAS_RFS
  1161.     while (*s == '/' && s[1] == '.' && s[2] == '.') {
  1162.     *d++ = '/';
  1163.     *d++ = '.';
  1164.     *d++ = '.';
  1165.     s += 3;
  1166.     }
  1167. #endif
  1168. #ifdef apollo
  1169.     if (*s == '/')
  1170.     *d++ = *s++;        /*added RBC 18/05/92 */
  1171. #endif
  1172.     for (;;) {
  1173.     if (*s == '/') {
  1174.         *d++ = *s++;
  1175.         while (*s == '/')
  1176.         s++;
  1177.     }
  1178.     if (!*s) {
  1179.         while (d > d0 + 1 && d[-1] == '/')
  1180.         d--;
  1181.         *d = '\0';
  1182.         return ct;
  1183.     }
  1184.     if (s[0] == '.' && s[1] == '.' && (s[2] == '\0' || s[2] == '/')) {
  1185.         if (d > d0 + 1) {
  1186.         for (d--; d > d0 + 1 && d[-1] != '/'; d--);
  1187.         if (d[-1] != '/')
  1188.             d--;
  1189.         } else
  1190.         ct++;
  1191.         s += 2;
  1192.         if (*s)
  1193.         s++;
  1194.     } else if (s[0] == '.' && (s[1] == '/' || s[1] == '\0')) {
  1195.         s++;
  1196.         if (*s)
  1197.         s++;
  1198.     } else {
  1199.         while (*s != '/' && *s != '\0')
  1200.         *d++ = *s++;
  1201.     }
  1202.     }
  1203. }
  1204.  
  1205. void cd_new_pwd(func, s)    /**/
  1206. int func;
  1207. char *s;
  1208. {
  1209.     Param pm;
  1210.     List l;
  1211.     char *new_pwd;
  1212.  
  1213.     if (isset(CHASELINKS))
  1214.     new_pwd = findpwd(s);
  1215.     else
  1216.     new_pwd = ztrdup(s);
  1217.     if (!strcmp(new_pwd, pwd) &&
  1218.     (func != BIN_PUSHD || isset(PUSHDIGNOREDUPS))) {
  1219.     zsfree(new_pwd);
  1220. #ifdef ALWAYS_DO_CD_PROCESSING
  1221.     if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
  1222.         pdstack();
  1223.     if (l = getshfunc("chpwd")) {
  1224.         fflush(stdout);
  1225.         fflush(stderr);
  1226.         doshfuncnoval(dupstruct(l), NULL, 0);
  1227.     }
  1228. #endif
  1229.     return;
  1230.     }
  1231.     zsfree(oldpwd);
  1232.     oldpwd = pwd;
  1233.     pwd = new_pwd;
  1234.     if ((pm = (Param) gethnode("PWD", paramtab)) &&
  1235.     (pm->flags & PMFLAG_x) && pm->env)
  1236.     pm->env = replenv(pm->env, pwd);
  1237.     if ((pm = (Param) gethnode("OLDPWD", paramtab)) &&
  1238.     (pm->flags & PMFLAG_x) && pm->env)
  1239.     pm->env = replenv(pm->env, oldpwd);
  1240.     if (func == BIN_PUSHD) {
  1241.     permalloc();
  1242.     if (isset(PUSHDIGNOREDUPS)) {
  1243.         Lknode n;
  1244.         char *nodedata;
  1245.  
  1246.         for (n = firstnode(dirstack); n; incnode(n)) {
  1247.         nodedata = (char *)getdata(n);
  1248.         if (!strcmp(oldpwd, nodedata) || !strcmp(pwd, nodedata)) {
  1249.             free(remnode(dirstack, n));
  1250.             break;
  1251.         }
  1252.         }
  1253.     }
  1254.     pushnode(dirstack, ztrdup(oldpwd));
  1255.     heapalloc();
  1256.     }
  1257.     if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
  1258.     pdstack();
  1259.     else if (doprintdir)
  1260.     printdircr(pwd);
  1261.     if ((l = getshfunc("chpwd"))) {
  1262.     fflush(stdout);
  1263.     fflush(stderr);
  1264.     doshfuncnoval(dupstruct(l), NULL, 0);
  1265.     }
  1266.     if (dirstacksize != -1 && countnodes(dirstack) >= dirstacksize) {
  1267.     if (dirstacksize < 2)
  1268.         dirstacksize = 2;
  1269.     else
  1270.         free(remnode(dirstack, lastnode(dirstack)));
  1271.     }
  1272. }
  1273.  
  1274. int bin_rehash(name, argv, ops, func)    /**/
  1275. char *name;
  1276. char **argv;
  1277. char *ops;
  1278. int func;
  1279. {
  1280.     newcmdnamtab();
  1281.     if (ops['f'])
  1282.     fullhash();
  1283.     return 0;
  1284. }
  1285.  
  1286. int bin_hash(name, argv, ops, func)    /**/
  1287. char *name;
  1288. char **argv;
  1289. char *ops;
  1290. int func;
  1291. {
  1292.     struct cmdnam *chn;
  1293.  
  1294.     chn = (Cmdnam) zcalloc(sizeof *chn);
  1295.     chn->flags = HASHCMD;
  1296.     chn->u.cmd = ztrdup(argv[1]);
  1297.     addhnode(ztrdup(argv[0]), chn, cmdnamtab, freecmdnam);
  1298.     return 0;
  1299. }
  1300.  
  1301. /* convert %%, %1, %foo, %?bar? to a job number */
  1302.  
  1303. int getjob(s, prog)        /**/
  1304. char *s;
  1305. char *prog;
  1306. {
  1307.     int t0, retval;
  1308.  
  1309.     if (*s != '%')
  1310.     goto jump;
  1311.     s++;
  1312.     if (*s == '%' || *s == '+' || !*s) {
  1313.     if (curjob == -1) {
  1314.         zwarnnam(prog, "no current job", NULL, 0);
  1315.         retval = -1;
  1316.         goto done;
  1317.     }
  1318.     retval = curjob;
  1319.     goto done;
  1320.     }
  1321.     if (*s == '-') {
  1322.     if (prevjob == -1) {
  1323.         zwarnnam(prog, "no previous job", NULL, 0);
  1324.         retval = -1;
  1325.         goto done;
  1326.     }
  1327.     retval = prevjob;
  1328.     goto done;
  1329.     }
  1330.     if (idigit(*s)) {
  1331.     t0 = atoi(s);
  1332.     if (t0 && t0 < MAXJOB && jobtab[t0].stat && t0 != thisjob) {
  1333.         retval = t0;
  1334.         goto done;
  1335.     }
  1336.     zwarnnam(prog, "no such job", NULL, 0);
  1337.     retval = -1;
  1338.     goto done;
  1339.     }
  1340.     if (*s == '?') {
  1341.     struct process *pn;
  1342.  
  1343.     for (t0 = MAXJOB - 1; t0 >= 0; t0--)
  1344.         if (jobtab[t0].stat && t0 != thisjob)
  1345.         for (pn = jobtab[t0].procs; pn; pn = pn->next)
  1346.             if (ztrstr(pn->text, s + 1)) {
  1347.             retval = t0;
  1348.             goto done;
  1349.             }
  1350.     zwarnnam(prog, "job not found: %s", s, 0);
  1351.     retval = -1;
  1352.     goto done;
  1353.     }
  1354.   jump:
  1355.     if ((t0 = findjobnam(s)) != -1) {
  1356.     retval = t0;
  1357.     goto done;
  1358.     }
  1359.     zwarnnam(prog, "job not found: %s", s, 0);
  1360.     retval = -1;
  1361.   done:
  1362.     return retval;
  1363. }
  1364.  
  1365. /* find a job named s */
  1366.  
  1367. int findjobnam(s)        /**/
  1368. char *s;
  1369. {
  1370.     int t0;
  1371.  
  1372.     for (t0 = MAXJOB - 1; t0 >= 0; t0--)
  1373.     if (jobtab[t0].stat && jobtab[t0].procs && t0 != thisjob &&
  1374.         jobtab[t0].procs->text && strpfx(s, jobtab[t0].procs->text))
  1375.         return t0;
  1376.     return -1;
  1377. }
  1378.  
  1379. int isanum(s)            /**/
  1380. char *s;
  1381. {
  1382.     while (*s == '-' || idigit(*s))
  1383.     s++;
  1384.     return *s == '\0';
  1385. }
  1386.  
  1387. int bin_kill(nam, argv, ops, func)    /**/
  1388. char *nam;
  1389. char **argv;
  1390. char *ops;
  1391. int func;
  1392. {
  1393.     int sig = SIGTERM;
  1394.     int retval = 0;
  1395.  
  1396.     if (*argv && **argv == '-') {
  1397.     if (idigit((*argv)[1]))
  1398.         sig = atoi(*argv + 1);
  1399.     else {
  1400.         if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
  1401.         printf("%s", sigs[1]);
  1402.         for (sig = 2; sig <= SIGCOUNT; sig++)
  1403.             printf(" %s", sigs[sig]);
  1404.         putchar('\n');
  1405.         return 0;
  1406.         }
  1407.         for (sig = 1; sig <= SIGCOUNT; sig++)
  1408.         if (!strcmp(sigs[sig], *argv + 1))
  1409.             break;
  1410.         if (sig > SIGCOUNT) {
  1411.         zwarnnam(nam, "unknown signal: SIG%s", *argv + 1, 0);
  1412.         zwarnnam(nam, "type kill -l for a List of signals", NULL, 0);
  1413.         return 1;
  1414.         }
  1415.     }
  1416.     argv++;
  1417.     }
  1418.     for (; *argv; argv++) {
  1419.     if (**argv == '%') {
  1420.         int p = getjob(*argv, "kill");
  1421.  
  1422.         if (p == -1) {
  1423.         retval = 1;
  1424.         continue;
  1425.         }
  1426.         if (killjb(jobtab + p, sig) == -1) {
  1427.         zwarnnam("kill", "kill failed: %e", NULL, errno);
  1428.         retval = 1;
  1429.         continue;
  1430.         }
  1431.         if (jobtab[p].stat & STAT_STOPPED) {
  1432.         if (sig == SIGCONT)
  1433.             jobtab[p].stat &= ~STAT_STOPPED;
  1434.         if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP
  1435.             && sig != SIGTTOU && sig != SIGTTIN && sig != SIGSTOP)
  1436.             killjb(jobtab + p, SIGCONT);
  1437.         }
  1438.     } else if (!isanum(*argv)) {
  1439.         zwarnnam("kill", "illegal pid: %s", *argv, 0);
  1440.         retval = 1;
  1441.     } else if (kill(atoi(*argv), sig) == -1) {
  1442.         zwarnnam("kill", "kill failed: %e", NULL, errno);
  1443.         retval = 1;
  1444.     }
  1445.     }
  1446.     return retval;
  1447. }
  1448.  
  1449. #ifdef RLIM_INFINITY
  1450. static char *recs[] =
  1451. {
  1452.     "cputime", "filesize", "datasize", "stacksize", "coredumpsize",
  1453. #ifdef RLIMIT_RSS
  1454. #ifdef RLIMIT_MEMLOCK
  1455.     "memoryuse",
  1456. #else
  1457.     "resident",
  1458. #endif                /* RLIMIT_MEMLOCK */
  1459. #endif                /* RLIMIT_RSS */
  1460. #ifdef RLIMIT_MEMLOCK
  1461.     "memorylocked",
  1462. #endif
  1463. #ifdef RLIMIT_NPROC
  1464.     "maxproc",
  1465. #endif
  1466. #ifdef RLIMIT_OFILE
  1467.     "openfiles",
  1468. #endif
  1469. #ifdef RLIMIT_NOFILE
  1470.     "descriptors",
  1471. #endif
  1472. #ifdef RLIMIT_VMEM
  1473.     "vmemorysize"
  1474. #endif
  1475. };
  1476. #endif
  1477.  
  1478. int bin_limit(nam, argv, ops, func)    /**/
  1479. char *nam;
  1480. char **argv;
  1481. char *ops;
  1482. int func;
  1483. {
  1484. #ifndef RLIM_INFINITY
  1485.     zwarnnam(nam, "not available on this system", NULL, 0);
  1486.     return 1;
  1487. #else
  1488.     char *s;
  1489.     int hard = ops['h'], t0, lim;
  1490.     long val;
  1491.  
  1492.     if (ops['s']) {
  1493.     if (*argv)
  1494.         zwarnnam(nam, "arguments after -s ignored", NULL, 0);
  1495.     for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1496.         if (setrlimit(t0, limits + t0) < 0)
  1497.         zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
  1498.     return 0;
  1499.     }
  1500.     if (!*argv) {
  1501.     showlimits(hard, -1);
  1502.     return 0;
  1503.     }
  1504.     while ((s = *argv++)) {
  1505.     for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1506.         if (!strncmp(recs[t0], s, strlen(s))) {
  1507.         if (lim != -1)
  1508.             lim = -2;
  1509.         else
  1510.             lim = t0;
  1511.         }
  1512.     if (lim < 0) {
  1513.         zwarnnam("limit",
  1514.             (lim == -2) ? "ambiguous resource specification: %s"
  1515.             : "no such resource: %s", s, 0);
  1516.         return 1;
  1517.     }
  1518.     if (!(s = *argv++)) {
  1519.         showlimits(hard, lim);
  1520.         return 0;
  1521.     }
  1522.     if (!lim) {
  1523.         val = zstrtol(s, &s, 10);
  1524.         if (*s)
  1525.         if ((*s == 'h' || *s == 'H') && !s[1])
  1526.             val *= 3600L;
  1527.         else if ((*s == 'm' || *s == 'M') && !s[1])
  1528.             val *= 60L;
  1529.         else if (*s == ':')
  1530.             val = val * 60 + zstrtol(s + 1, &s, 10);
  1531.         else {
  1532.             zwarnnam("limit", "unknown scaling factor: %s", s, 0);
  1533.             return 1;
  1534.         }
  1535.     }
  1536. #ifdef RLIMIT_NPROC
  1537.     else if (lim == RLIMIT_NPROC)
  1538.         val = zstrtol(s, &s, 10);
  1539. #endif
  1540. #ifdef RLIMIT_OFILE
  1541.     else if (lim == RLIMIT_OFILE)
  1542.         val = zstrtol(s, &s, 10);
  1543. #endif
  1544. #ifdef RLIMIT_NOFILE
  1545.     else if (lim == RLIMIT_NOFILE)
  1546.         val = zstrtol(s, &s, 10);
  1547. #endif
  1548.     else {
  1549.         val = zstrtol(s, &s, 10);
  1550.         if (!*s || ((*s == 'k' || *s == 'K') && !s[1]))
  1551.         val *= 1024L;
  1552.         else if ((*s == 'M' || *s == 'm') && !s[1])
  1553.         val *= 1024L * 1024;
  1554.         else {
  1555.         zwarnnam("limit", "unknown scaling factor: %s", s, 0);
  1556.         return 1;
  1557.         }
  1558.     }
  1559.     if (hard)
  1560.         if (val > limits[lim].rlim_max && geteuid()) {
  1561.         zwarnnam("limit", "can't raise hard limits", NULL, 0);
  1562.         return 1;
  1563.         } else {
  1564.         limits[lim].rlim_max = val;
  1565.         if (limits[lim].rlim_max < limits[lim].rlim_cur)
  1566.             limits[lim].rlim_cur = limits[lim].rlim_max;
  1567.     } else if (val > limits[lim].rlim_max) {
  1568.         zwarnnam("limit", "limit exceeds hard limit", NULL, 0);
  1569.         return 1;
  1570.     } else
  1571.         limits[lim].rlim_cur = val;
  1572.     }
  1573.     return 0;
  1574. #endif
  1575. }
  1576.  
  1577. int bin_unlimit(nam, argv, ops, func)    /**/
  1578. char *nam;
  1579. char **argv;
  1580. char *ops;
  1581. int func;
  1582. {
  1583. #ifndef RLIM_INFINITY
  1584.     zwarnnam(nam, "not available on this system", NULL, 0);
  1585.     return 1;
  1586. #else
  1587.     int hard = ops['h'], t0, lim;
  1588.  
  1589.     if (hard && geteuid()) {
  1590.     zwarnnam(nam, "can't remove hard limits", NULL, 0);
  1591.     return 1;
  1592.     }
  1593.     if (!*argv) {
  1594.     for (t0 = 0; t0 != RLIM_NLIMITS; t0++) {
  1595.         if (hard)
  1596.         limits[t0].rlim_max = RLIM_INFINITY;
  1597.         else
  1598.         limits[t0].rlim_cur = limits[t0].rlim_max;
  1599.     }
  1600.     return 0;
  1601.     }
  1602.     for (; *argv; argv++) {
  1603.     for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1604.         if (!strncmp(recs[t0], *argv, strlen(*argv))) {
  1605.         if (lim != -1)
  1606.             lim = -2;
  1607.         else
  1608.             lim = t0;
  1609.         }
  1610.     if (lim < 0) {
  1611.         zwarnnam(nam,
  1612.             (lim == -2) ? "ambiguous resource specification: %s"
  1613.             : "no such resource: %s", *argv, 0);
  1614.         return 1;
  1615.     }
  1616.     if (hard)
  1617.         limits[lim].rlim_max = RLIM_INFINITY;
  1618.     else
  1619.         limits[lim].rlim_cur = limits[lim].rlim_max;
  1620.     }
  1621.     return 0;
  1622. #endif
  1623. }
  1624.  
  1625. #ifdef RLIM_INFINITY
  1626. void showlimits(hard, lim)    /**/
  1627. int hard;
  1628. int lim;
  1629. {
  1630.     int t0;
  1631.     long val;
  1632.  
  1633.     for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1634.     if (t0 == lim || lim == -1) {
  1635.         printf("%-16s", recs[t0]);
  1636.         val = (hard) ? limits[t0].rlim_max : limits[t0].rlim_cur;
  1637.         if (val == RLIM_INFINITY)
  1638.         printf("unlimited\n");
  1639.         else if (!t0)
  1640.         printf("%d:%02d:%02d\n", (int)(val / 3600),
  1641.                (int)(val / 60) % 60, (int)(val % 60));
  1642. #ifdef RLIMIT_NPROC
  1643.         else if (t0 == RLIMIT_NPROC)
  1644.         printf("%d\n", (int)val);
  1645. #endif
  1646. #ifdef RLIMIT_OFILE
  1647.         else if (t0 == RLIMIT_OFILE)
  1648.         printf("%d\n", (int)val);
  1649. #endif
  1650. #ifdef RLIMIT_NOFILE
  1651.         else if (t0 == RLIMIT_NOFILE)
  1652.         printf("%d\n", (int)val);
  1653. #endif
  1654.         else if (val >= 1024L * 1024L)
  1655.         printf("%ldMb\n", val / (1024L * 1024L));
  1656.         else
  1657.         printf("%ldKb\n", val / 1024L);
  1658.     }
  1659. }
  1660. #endif
  1661.  
  1662. int bin_sched(nam, argv, ops, func)    /**/
  1663. char *nam;
  1664. char **argv;
  1665. char *ops;
  1666. int func;
  1667. {
  1668.     char *s = *argv++;
  1669.     time_t t;
  1670.     long h, m;
  1671.     struct tm *tm;
  1672.     struct schedcmd *sch, *sch2, *schl;
  1673.     int t0;
  1674.  
  1675.     if (s && *s == '-') {
  1676.     t0 = atoi(s + 1);
  1677.  
  1678.     if (!t0) {
  1679.         zwarnnam("sched", "usage for delete: sched -<item#>.", NULL, 0);
  1680.         return 1;
  1681.     }
  1682.     for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds, t0--;
  1683.          sch && t0; sch = (schl = sch)->next, t0--);
  1684.     if (!sch) {
  1685.         zwarnnam("sched", "not that many entries", NULL, 0);
  1686.         return 1;
  1687.     }
  1688.     schl->next = sch->next;
  1689.     zsfree(sch->cmd);
  1690.     zfree(sch, sizeof(struct schedcmd));
  1691.     return 0;
  1692.     }
  1693.     if (!s) {
  1694.     char tbuf[40];
  1695.  
  1696.     for (t0 = 1, sch = schedcmds; sch; sch = sch->next, t0++) {
  1697.         t = sch->time;
  1698.         tm = localtime(&t);
  1699.         ztrftime(tbuf, 20, "%a %b %e %k:%M:%S", tm);
  1700.         printf("%3d %s %s\n", t0, tbuf, sch->cmd);
  1701.     }
  1702.     return 0;
  1703.     } else if (!*argv) {
  1704.     zwarnnam("sched", "not enough arguments", NULL, 0);
  1705.     return 1;
  1706.     }
  1707.     if (*s == '+') {
  1708.     h = zstrtol(s + 1, &s, 10);
  1709.     if (*s != ':') {
  1710.         zwarnnam("sched", "bad time specifier", NULL, 0);
  1711.         return 1;
  1712.     }
  1713.     m = zstrtol(s + 1, &s, 10);
  1714.     if (*s) {
  1715.         zwarnnam("sched", "bad time specifier", NULL, 0);
  1716.         return 1;
  1717.     }
  1718.     t = time(NULL) + h * 3600 + m * 60;
  1719.     } else {
  1720.     h = zstrtol(s, &s, 10);
  1721.     if (*s != ':') {
  1722.         zwarnnam("sched", "bad time specifier", NULL, 0);
  1723.         return 1;
  1724.     }
  1725.     m = zstrtol(s + 1, &s, 10);
  1726.     if (*s && *s != 'a' && *s != 'p') {
  1727.         zwarnnam("sched", "bad time specifier", NULL, 0);
  1728.         return 1;
  1729.     }
  1730.     t = time(NULL);
  1731.     tm = localtime(&t);
  1732.     t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600;
  1733.     if (*s == 'p')
  1734.         h += 12;
  1735.     t += h * 3600 + m * 60;
  1736.     if (t < time(NULL))
  1737.         t += 3600 * 24;
  1738.     }
  1739.     sch = (struct schedcmd *)zcalloc(sizeof *sch);
  1740.     sch->time = t;
  1741.     sch->cmd = ztrdup(spacejoin(argv));
  1742.     sch->next = NULL;
  1743.     for (sch2 = (struct schedcmd *)&schedcmds; sch2->next; sch2 = sch2->next);
  1744.     sch2->next = sch;
  1745.     return 0;
  1746. }
  1747.  
  1748. int bin_eval(nam, argv, ops, func)    /**/
  1749. char *nam;
  1750. char **argv;
  1751. char *ops;
  1752. int func;
  1753. {
  1754.     char *s = ztrdup(spacejoin(argv));
  1755.     List list;
  1756.  
  1757.     hungets(s);
  1758.     zsfree(s);
  1759.     strinbeg();
  1760.     if (!(list = parse_list())) {
  1761.     hflush();
  1762.     strinend();
  1763.     return 1;
  1764.     }
  1765.     strinend();
  1766.     runlist(list);
  1767.     return lastval;
  1768. }
  1769.  
  1770. /* get the history event associated with s */
  1771.  
  1772. int fcgetcomm(s)        /**/
  1773. char *s;
  1774. {
  1775.     int cmd;
  1776.  
  1777.     if ((cmd = atoi(s))) {
  1778.     if (cmd < 0)
  1779.         cmd = curhist + cmd + 1;
  1780.     return cmd;
  1781.     }
  1782.     cmd = hcomsearch(s);
  1783.     if (cmd == -1)
  1784.     zwarnnam("fc", "event not found: %s", s, 0);
  1785.     return cmd;
  1786. }
  1787.  
  1788. /* perform old=new substituion */
  1789.  
  1790. int fcsubs(sp, sub)        /**/
  1791. char **sp;
  1792. struct asgment *sub;
  1793. {
  1794.     char *s1, *s2, *s3, *s4, *s = *sp, *s5;
  1795.     int subbed = 0;
  1796.  
  1797.     while (sub) {
  1798.     s1 = sub->name;
  1799.     s2 = sub->value;
  1800.     sub = sub->next;
  1801.     s5 = s;
  1802.     while ((s3 = (char *)ztrstr(s5, s1))) {
  1803.         s4 = (char *)
  1804.         alloc(1 + (s3 - s) + strlen(s2) + strlen(s3 + strlen(s1)));
  1805.         ztrncpy(s4, s, s3 - s);
  1806.         strcat(s4, s2);
  1807.         s5 = s4 + strlen(s4);
  1808.         strcat(s4, s3 + strlen(s1));
  1809.         s = s4;
  1810.         subbed = 1;
  1811.     }
  1812.     }
  1813.     *sp = s;
  1814.     return subbed;
  1815. }
  1816.  
  1817. /* print a series of history events to a file */
  1818.  
  1819. int fclist(f, n, r, D, d, first, last, subs, com)    /**/
  1820. FILE *f;
  1821. int n;
  1822. int r;
  1823. int D;
  1824. int d;
  1825. int first;
  1826. int last;
  1827. struct asgment *subs;
  1828. Comp com;
  1829. {
  1830.     int fclistdone = 0;
  1831.     char *s, *hs;
  1832.     Histent ent;
  1833.  
  1834.     if (r) {
  1835.     r = last;
  1836.     last = first;
  1837.     first = r;
  1838.     }
  1839.     if (!subs)
  1840.     fclistdone = 1;
  1841.     for (;;) {
  1842.     hs = quietgetevent(first);
  1843.     if (!hs) {
  1844.         zwarnnam("fc", "no such event: %d", NULL, first);
  1845.         return 1;
  1846.     }
  1847.     s = makehstr(hs);
  1848.     if (!com || domatch(s, com, 0)) {
  1849.         fclistdone |= fcsubs(&s, subs);
  1850.         if (n)
  1851.         fprintf(f, "%5d  ", first);
  1852.         ent = NULL;
  1853.         if (d) {
  1854.         struct tm *ltm;
  1855.  
  1856.         if (!ent)
  1857.             ent = gethistent(first);
  1858.         ltm = localtime(&ent->stim);
  1859.         if (d >= 2) {
  1860.             if (d >= 4) {
  1861.             fprintf(f, "%d.%d.%d ",
  1862.                 ltm->tm_mday, ltm->tm_mon + 1,
  1863.                 ltm->tm_year + 1900);
  1864.             } else {
  1865.             fprintf(f, "%d/%d/%d ",
  1866.                 ltm->tm_mon + 1,
  1867.                 ltm->tm_mday,
  1868.                 ltm->tm_year + 1900);
  1869.             }
  1870.         }
  1871.         fprintf(f, "%02d:%02d  ", ltm->tm_hour, ltm->tm_min);
  1872.         }
  1873.         if (D) {
  1874.         long diff;
  1875.  
  1876.         if (!ent)
  1877.             ent = gethistent(first);
  1878.         diff = (ent->ftim) ? ent->ftim - ent->stim : 0;
  1879.         fprintf(f, "%ld:%02ld  ", diff / 60, diff % 60);
  1880.         }
  1881.         if (f == stdout) {
  1882.         niceprintf(s, f);
  1883.         putc('\n', f);
  1884.         } else
  1885.         fprintf(f, "%s\n", s);
  1886.     }
  1887.     if (first == last)
  1888.         break;
  1889.     else if (first > last)
  1890.         first--;
  1891.     else
  1892.         first++;
  1893.     }
  1894.     if (f != stdout)
  1895.     fclose(f);
  1896.     if (!fclistdone) {
  1897.     zwarnnam("fc", "no substitutions performed", NULL, 0);
  1898.     return 1;
  1899.     }
  1900.     return 0;
  1901. }
  1902.  
  1903. int fcedit(ename, fn)        /**/
  1904. char *ename;
  1905. char *fn;
  1906. {
  1907.     if (!strcmp(ename, "-"))
  1908.     return 1;
  1909.     return !zyztem(ename, fn);
  1910. }
  1911.  
  1912. /* fc, history, r */
  1913.  
  1914. int bin_fc(nam, argv, ops, func)/**/
  1915. char *nam;
  1916. char **argv;
  1917. char *ops;
  1918. int func;
  1919. {
  1920.     int first = -1, last = -1, retval, delayrem, minflag = 0;
  1921.     char *s;
  1922.     struct asgment *asgf = NULL, *asgl = NULL;
  1923.     Comp com = NULL;
  1924.  
  1925.     if (!interact) {
  1926.     zwarnnam(nam, "not interactive shell", NULL, 0);
  1927.     return 1;
  1928.     }
  1929.     if (*argv && ops['m']) {
  1930.     tokenize(*argv);
  1931.     if (!(com = parsereg(*argv++))) {
  1932.         zwarnnam(nam, "invalid match pattern", NULL, 0);
  1933.         return 1;
  1934.     }
  1935.     }
  1936.     delayrem = !strcmp(nam, "r");
  1937.     if (!delayrem && !(ops['l'] && unset(HISTNOSTORE)) &&
  1938.     (ops['R'] || ops['W'] || ops['A']))
  1939.     remhist();
  1940.     if (ops['R']) {
  1941.     readhistfile(*argv ? *argv : getsparam("HISTFILE"), 1);
  1942.     return 0;
  1943.     }
  1944.     if (ops['W']) {
  1945.     savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1,
  1946.              (ops['I'] ? 2 : 0));
  1947.     return 0;
  1948.     }
  1949.     if (ops['A']) {
  1950.     savehistfile(*argv ? *argv : getsparam("HISTFILE"), 1,
  1951.              (ops['I'] ? 3 : 1));
  1952.     return 0;
  1953.     }
  1954.     while (*argv && equalsplit(*argv, &s)) {
  1955.     struct asgment *a = (struct asgment *)alloc(sizeof *a);
  1956.  
  1957.     if (!asgf)
  1958.         asgf = asgl = a;
  1959.     else {
  1960.         asgl->next = a;
  1961.         asgl = a;
  1962.     }
  1963.     a->name = *argv;
  1964.     a->value = s;
  1965.     argv++;
  1966.     }
  1967.     if (*argv) {
  1968.     minflag = **argv == '-';
  1969.     first = fcgetcomm(*argv);
  1970.     if (first == -1)
  1971.         return 1;
  1972.     argv++;
  1973.     }
  1974.     if (*argv) {
  1975.     last = fcgetcomm(*argv);
  1976.     if (last == -1)
  1977.         return 1;
  1978.     argv++;
  1979.     }
  1980.     if (*argv) {
  1981.     zwarnnam("fc", "too many arguments", NULL, 0);
  1982.     return 1;
  1983.     }
  1984.     if (first == -1)
  1985.     first = (ops['l']) ? curhist - 16 : curhist - 1;
  1986.     if (last == -1)
  1987.     last = (ops['l']) ? curhist : first;
  1988.     if (first < firsthist())
  1989.     first = firsthist();
  1990.     if (last == -1)
  1991.     last = (minflag) ? curhist : first;
  1992.     if (ops['l'])
  1993.     retval = fclist(stdout, !ops['n'], ops['r'], ops['D'],
  1994.             ops['d'] + ops['f'] * 2 + ops['E'] * 4,
  1995.             first, last, asgf, com);
  1996.     else {
  1997.     FILE *out;
  1998.     char *fil = gettemp();
  1999.  
  2000.     retval = 1;
  2001.     out = fopen(fil, "w");
  2002.     if (!out)
  2003.         zwarnnam("fc", "can't open temp file: %e", NULL, errno);
  2004.     else {
  2005.         if (!fclist(out, 0, ops['r'], 0, 0, first, last, asgf, com))
  2006.         if (fcedit(auxdata ? auxdata : fceditparam, fil))
  2007.             if (stuff(fil))
  2008.             zwarnnam("fc", "%e: %s", s, errno);
  2009.             else
  2010.             retval = 0;
  2011.     }
  2012.     unlink(fil);
  2013.     }
  2014.     if (delayrem)
  2015.     remhist();
  2016.     return retval;
  2017. }
  2018.  
  2019. int bin_suspend(name, argv, ops, func)    /**/
  2020. char *name;
  2021. char **argv;
  2022. char *ops;
  2023. int func;
  2024. {
  2025.     if (islogin && !ops['f']) {
  2026.     zerrnam(name, "can't suspend login shell", NULL, 0);
  2027.     return 1;
  2028.     }
  2029.     if (jobbing) {
  2030.     sig_default(SIGPIPE);
  2031.     sig_default(SIGTTIN);
  2032.     sig_default(SIGTSTP);
  2033.     sig_default(SIGTTOU);
  2034.     }
  2035.     kill(0, SIGTSTP);
  2036.     if (jobbing) {
  2037.     while (gettygrp() != mypgrp) {
  2038.         sleep(1);
  2039.         if (gettygrp() != mypgrp)
  2040.         kill(0, SIGTTIN);
  2041.     }
  2042.     sig_ignore(SIGTTOU);
  2043.     sig_ignore(SIGTSTP);
  2044.     sig_ignore(SIGTTIN);
  2045.     sig_ignore(SIGPIPE);
  2046.     }
  2047.     return 0;
  2048. }
  2049.  
  2050. int bin_alias(name, argv, ops, func)    /**/
  2051. char *name;
  2052. char **argv;
  2053. char *ops;
  2054. int func;
  2055. {
  2056.     struct alias *an;
  2057.     struct asgment *asg;
  2058.     int incm = !(ops['a'] || ops['g']), ret = 0;
  2059.  
  2060.     if (ops['r'])
  2061.     showflag = 2;
  2062.     else
  2063.     showflag = !incm;
  2064.     if (!*argv)
  2065.     listhtable(aliastab, (HFunc) printalias);
  2066.     else
  2067.     while ((asg = getasg(*argv++))) {
  2068.         if (asg->value)
  2069.         addhnode(ztrdup(asg->name), mkanode(ztrdup(asg->value), incm),
  2070.              aliastab, freeanode);
  2071.         else if (ops['m']) {
  2072.         int n, i;
  2073.         struct alias *a;
  2074.         Comp com;
  2075.  
  2076.         tokenize(argv[-1]);
  2077.         if (!(com = parsereg(argv[-1]))) {
  2078.             ret = 1;
  2079.             untokenize(argv[-1]);
  2080.             zerrnam(name, "bad pattern : %s", argv[-1], 0);
  2081.             continue;
  2082.         }
  2083.         n = aliastab->hsize;
  2084.         for (i = 0; i < n; i++) {
  2085.             for (a = (struct alias *)aliastab->nodes[i]; a;
  2086.              a = (struct alias *)a->next) {
  2087.             if (a->nam && domatch(a->nam, com, 0))
  2088.                 printalias(a->nam, a), ret = 0;
  2089.             }
  2090.         }
  2091.         } else if ((an = (Alias) gethnode(asg->name, aliastab))) {
  2092.         if ((!ops['r'] || an->cmd == 1) &&
  2093.             (!ops['g'] || !an->cmd))
  2094.             printalias(asg->name, an);
  2095.         } else
  2096.         ret = 1;
  2097.     }
  2098.     return ret;
  2099. }
  2100.  
  2101. /* print an alias; used with listhtable */
  2102.  
  2103. void printalias(s, a)        /**/
  2104. char *s;
  2105. struct alias *a;
  2106. {
  2107.     char *ptr;
  2108.     int special = 0;
  2109.  
  2110.     if (a->cmd >= 0 && (!showflag ||
  2111.             (showflag == 1 && !a->cmd) ||
  2112.             (showflag == 2 && a->cmd)))
  2113.       /*!(showflag && a->cmd))*/ {
  2114.     for (ptr = a->text; *ptr; ptr++)
  2115.       if (ispecial(*ptr))
  2116.         special++;
  2117.     if (special) {
  2118.       printf("%s=\'",s);
  2119.       for (ptr = a->text; *ptr; ptr++)
  2120.         if (*ptr == '\'')
  2121.           printf("\'\\\'\'");
  2122.         else
  2123.           putchar(*ptr);
  2124.       printf("\'\n");
  2125.     } else
  2126.       printf("%s=%s\n", s, a->text);
  2127.       }
  2128. }
  2129.  
  2130. /* print a param; used with listhtable */
  2131.  
  2132. void printparam(s, p)        /**/
  2133. char *s;
  2134. Param p;
  2135. {
  2136.     if ((showflag > 0 && !(p->flags & showflag)) || (p->flags & PMFLAG_UNSET))
  2137.     return;
  2138.     if (!showflag) {
  2139.     int fgs = p->flags;
  2140.  
  2141.     if (fgs & PMFLAG_i)
  2142.         printf("integer ");
  2143.     if (fgs & PMFLAG_A)
  2144.         printf("array ");
  2145.     if (fgs & PMFLAG_L)
  2146.         printf("left justified %d ", p->ct);
  2147.     if (fgs & PMFLAG_R)
  2148.         printf("right justified %d ", p->ct);
  2149.     if (fgs & PMFLAG_Z)
  2150.         printf("zero filled %d ", p->ct);
  2151.     if (fgs & PMFLAG_l)
  2152.         printf("lowercase ");
  2153.     if (fgs & PMFLAG_u)
  2154.         printf("uppercase ");
  2155.     if (fgs & PMFLAG_r)
  2156.         printf("readonly ");
  2157.     if (fgs & PMFLAG_t)
  2158.         printf("tagged ");
  2159.     if (fgs & PMFLAG_x)
  2160.         printf("exported ");
  2161.     }
  2162.     if (showflag2)
  2163.     printf("%s\n", s);
  2164.     else {
  2165.     char *t, **u;
  2166.  
  2167.     printf("%s=", s);
  2168.     switch (p->flags & PMTYPE) {
  2169.     case PMFLAG_s:
  2170.         if (p->gets.cfn && (t = p->gets.cfn(p)))
  2171.         puts(t);
  2172.         else
  2173.         putchar('\n');
  2174.         break;
  2175.     case PMFLAG_i:
  2176.         printf("%ld\n", p->gets.ifn(p));
  2177.         break;
  2178.     case PMFLAG_A:
  2179.         putchar('(');
  2180.         u = p->gets.afn(p);
  2181.         if (!*u)
  2182.         printf(")\n");
  2183.         else {
  2184.         while (u[1])
  2185.             printf("%s ", *u++);
  2186.         printf("%s)\n", *u);
  2187.         }
  2188.         break;
  2189.     }
  2190.     }
  2191. }
  2192.  
  2193. /* autoload, declare, export, functions, integer, local, readonly, typeset */
  2194.  
  2195. int bin_typeset(name, argv, ops, func)    /**/
  2196. char *name;
  2197. char **argv;
  2198. char *ops;
  2199. int func;
  2200. {
  2201.     int on = 0, off = 0, roff, bit = 1, retcode = 0, initon, initoff;
  2202.     char *optstr = "LRZilurtx";
  2203.     struct param *pm;
  2204.     struct asgment *asg;
  2205.  
  2206.     for (; *optstr; optstr++, bit <<= 1)
  2207.     if (ops[*optstr] == 1)
  2208.         on |= bit;
  2209.     else if (ops[*optstr] == 2)
  2210.         off |= bit;
  2211.     roff = off;
  2212.     if (ops['f']) {
  2213.     on &= PMFLAG_t | PMFLAG_u;
  2214.     off &= PMFLAG_t | PMFLAG_u;
  2215.     showflag = (ops['f'] == 1);
  2216.     if (ops['@'] && ((off & ~PMFLAG_t) || (on & ~(PMFLAG_u | PMFLAG_t)))) {
  2217.         zerrnam(name, "invalid option(s)", NULL, 0);
  2218.         return 1;
  2219.     }
  2220.     showflag2 = 0;
  2221.     if (!*argv) {
  2222.         showflag2 = off | on;
  2223.         listhtable(cmdnamtab, (HFunc) pshfunc);
  2224.     } else if (ops['m']) {
  2225.         Comp com;
  2226.         int i, n;
  2227.         struct cmdnam *chn;
  2228.  
  2229.         on &= ~512;
  2230.         for (; *argv; argv++) {
  2231.         tokenize(*argv);
  2232.         if (!(com = parsereg(*argv))) {
  2233.             retcode = 1;
  2234.             untokenize(*argv);
  2235.             zerrnam(name, "bad pattern : %s", *argv, 0);
  2236.             continue;
  2237.         }
  2238.         n = cmdnamtab->hsize;
  2239.         for (i = 0; i < n; i++)
  2240.             for (chn = (struct cmdnam *)cmdnamtab->nodes[i]; chn;
  2241.              chn = (struct cmdnam *)chn->next)
  2242.             if ((chn->flags & SHFUNC) && 
  2243.                 domatch(chn->nam, com, 0)) {
  2244.                 if (on | off)
  2245.                 chn->flags = (chn->flags | on) & (~off);
  2246.                 else
  2247.                 pshfunc(chn->nam, chn);
  2248.             }
  2249.         }
  2250.     } else
  2251.         for (; *argv; argv++) {
  2252.         Cmdnam cc;
  2253.  
  2254.         if ((cc = (Cmdnam) gethnode(*argv, cmdnamtab)) && 
  2255.             (cc->flags & SHFUNC))
  2256.             if (on | off)
  2257.             cc->flags = (cc->flags | on) & (~off);
  2258.             else
  2259.             pshfunc(*argv, cc);
  2260.         else if (on & PMFLAG_u) {
  2261.             cc = (Cmdnam) zcalloc(sizeof *cc);
  2262.             cc->flags = SHFUNC | on;
  2263.             addhnode(ztrdup(*argv), cc, cmdnamtab, freecmdnam);
  2264.         } else
  2265.             retcode = 1;
  2266.         }
  2267.     return retcode;
  2268.     }
  2269.     if ((on | off) & PMFLAG_x)
  2270.     func = BIN_EXPORT;
  2271.     if (on & PMFLAG_i)
  2272.     off |= PMFLAG_R | PMFLAG_L | PMFLAG_Z | PMFLAG_u | PMFLAG_A;
  2273.     if (on & PMFLAG_L)
  2274.     off |= PMFLAG_R | PMFLAG_i;
  2275.     if (on & PMFLAG_R)
  2276.     off |= PMFLAG_L | PMFLAG_i;
  2277.     if (on & PMFLAG_Z)
  2278.     off |= PMFLAG_i;
  2279.     if (on & PMFLAG_u)
  2280.     off |= PMFLAG_l;
  2281.     if (on & PMFLAG_l)
  2282.     off |= PMFLAG_u;
  2283.     on &= ~off;
  2284.     showflag = showflag2 = 0;
  2285.     initon = on;
  2286.     initoff = off;
  2287.     if (!*argv) {
  2288.     showflag = on | roff;
  2289.     showflag2 = roff || ops['+'];
  2290.     listhtable(paramtab, (HFunc) printparam);
  2291.     } else
  2292.     while ((asg = getasg(*argv++))) {
  2293.         on = initon;
  2294.         off = initoff;
  2295.         if (ops['m']) {
  2296.         Comp com;
  2297.         int i, n;
  2298.  
  2299.         on &= ~512;
  2300.         tokenize(asg->name);
  2301.         if (!(com = parsereg(asg->name))) {
  2302.             untokenize(asg->name);
  2303.             zerrnam(name, "bad pattern : %s", argv[-1], 0);
  2304.             continue;
  2305.         }
  2306.         n = paramtab->hsize;
  2307.         for (i = 0; i < n; i++)
  2308.             for (pm = (struct param *)paramtab->nodes[i]; pm;
  2309.              pm = (struct param *)pm->next)
  2310.             if (domatch(pm->nam, com, 0)) {
  2311.                 if (!on && !roff && !asg->value) {
  2312.                 printparam(pm->nam, pm);
  2313.                 continue;
  2314.                 }
  2315.                 pm->flags = (pm->flags | on) & ~off;
  2316.                 if ((on & (PMFLAG_L | PMFLAG_R | PMFLAG_Z | PMFLAG_i))
  2317.                 && (pmtype(pm) != PMFLAG_A))
  2318.                 pm->ct = auxlen;
  2319.                 if (pmtype(pm) != PMFLAG_A) {
  2320.                 if (pm->flags & PMFLAG_x) {
  2321.                     if (!pm->env)
  2322.                     pm->env = addenv(pm->nam,
  2323.                              (asg->value) ? asg->value : getsparam(pm->nam));
  2324.                 } else if (pm->env) {
  2325.                     delenv(pm->env);
  2326.                     zsfree(pm->env);
  2327.                     pm->env = NULL;
  2328.                 }
  2329.                 if (asg->value)
  2330.                     setsparam(pm->nam, ztrdup(asg->value));
  2331.                 }
  2332.             }
  2333.         } else {
  2334.         if (!isident(asg->name)) {
  2335.             zerr("not an identifier: %s", asg->name, 0);
  2336.             continue;
  2337.         }
  2338.         pm = (Param) gethnode(asg->name, paramtab);
  2339.         if (pm && (pm->flags & PMFLAG_SPECIAL)) {
  2340.             func = 0;
  2341.             on = (pmtype(pm) == PMFLAG_i) ?
  2342.             (on &= ~(PMFLAG_L | PMFLAG_R | PMFLAG_Z | PMFLAG_u)) :
  2343.             (on & ~PMFLAG_i);
  2344.             off &= ~PMFLAG_i;
  2345.         }
  2346.         if (pm && pm->level)
  2347.             on &= ~PMFLAG_x;
  2348.         bit = 0;    /* flag for switching int<->not-int */
  2349.         if (pm && !(pm->flags & PMFLAG_UNSET) &&
  2350.             ((((locallevel == pm->level) || func == BIN_EXPORT)
  2351.               && !(bit = ((off & pm->flags) | (on & ~pm->flags)) & PMFLAG_i)) ||
  2352.              (pm->flags & PMFLAG_SPECIAL))) {
  2353.             if (!on && !roff && !asg->value) {
  2354.             printparam(asg->name, pm);
  2355.             continue;
  2356.             }
  2357.             pm->flags = (pm->flags | on) & ~off;
  2358.             if (on & (PMFLAG_L | PMFLAG_R | PMFLAG_Z | PMFLAG_i))
  2359.             pm->ct = auxlen;
  2360.             if (pmtype(pm) != PMFLAG_A) {
  2361.             if (pm->flags & PMFLAG_x) {
  2362.                 if (!pm->env)
  2363.                 pm->env = addenv(asg->name,
  2364.                          (asg->value) ? asg->value : getsparam(asg->name));
  2365.             } else if (pm->env) {
  2366.                 delenv(pm->env);
  2367.                 zsfree(pm->env);
  2368.                 pm->env = NULL;
  2369.             }
  2370.             if (asg->value)
  2371.                 setsparam(asg->name, ztrdup(asg->value));
  2372.             }
  2373.         } else {
  2374.             int readonly = on & PMFLAG_r;
  2375.             if (bit) {
  2376.             if (!asg->value)
  2377.                 asg->value = dupstring(getsparam(asg->name));
  2378.             unsetparam(asg->name);
  2379.             } else if (locallist && func != BIN_EXPORT) {
  2380.             permalloc();
  2381.             addnode(locallist, ztrdup(asg->name));
  2382.             heapalloc();
  2383.             }
  2384.             pm = createparam(ztrdup(asg->name), on & ~PMFLAG_r);
  2385.             pm->ct = auxlen;
  2386.             if (func != BIN_EXPORT)
  2387.             pm->level = locallevel;
  2388.             if (asg->value)
  2389.             setsparam(asg->name, ztrdup(asg->value));
  2390.             pm->flags |= readonly;
  2391.         }
  2392.         }
  2393.     }
  2394.     return 0;
  2395. }
  2396.  
  2397. /* Check whether a command is a bin_typeset. */
  2398.  
  2399. int istypeset(c, nam)        /**/
  2400. Cmdnam c;
  2401. char *nam;
  2402. {
  2403.     struct bincmd *b;
  2404.  
  2405.     if (c)
  2406.     if ((c->flags & BUILTIN) && !(c->flags & EXCMD))
  2407.         return (builtins[c->u.binnum].handlerfunc == bin_typeset);
  2408.     else
  2409.         nam = c->nam;
  2410.     if (nam)
  2411.     for (b = builtins; b->name; b++)
  2412.         if (!strcmp(nam, b->name) && b->handlerfunc == bin_typeset)
  2413.         return 1;
  2414.     return 0;
  2415. }
  2416.  
  2417. /* echo, print, pushln */
  2418.  
  2419. int bin_print(name, args, ops, func)    /**/
  2420. char *name;
  2421. char **args;
  2422. char *ops;
  2423. int func;
  2424. {
  2425.     int nnl = 0, fd;
  2426.     Histent ent;
  2427.     FILE *fout = stdout;
  2428.  
  2429.     if (ops['z']) {
  2430.     permalloc();
  2431.     pushnode(bufstack, ztrdup(spacejoin(args)));
  2432.     heapalloc();
  2433.     return 0;
  2434.     }
  2435.     if (ops['s']) {
  2436.     permalloc();
  2437.     ent = gethistent(++curhist);
  2438.     zsfree(ent->lex);
  2439.     zsfree(ent->lit);
  2440.     ent->lex = ztrdup(join(args, HISTSPACE));
  2441.     ent->lit = ztrdup(join(args, ' '));
  2442.     ent->stim = ent->ftim = time(NULL);
  2443.     ent->flags = 0;
  2444.     heapalloc();
  2445.     return 0;
  2446.     }
  2447.     if (ops['R'])
  2448.     ops['r'] = 1;
  2449.     if (ops['u'] || ops['p']) {
  2450.     if (ops['u']) {
  2451.         for (fd = 0; fd < 10; fd++)
  2452.         if (ops[fd + '0'])
  2453.             break;
  2454.         if (fd == 10)
  2455.         fd = 0;
  2456.     } else
  2457.         fd = coprocout;
  2458.     if ((fd = dup(fd)) < 0) {
  2459.         zwarnnam(name, "bad file number", NULL, 0);
  2460.         return 1;
  2461.     }
  2462.     if ((fout = fdopen(fd, "w")) == 0) {
  2463.         zwarnnam(name, "bad mode on fd", NULL, 0);
  2464.         return 1;
  2465.     }
  2466.     }
  2467.     if (ops['o']) {
  2468.     if (ops['i'])
  2469.         qsort(args, arrlen(args), sizeof(char *), cstrpcmp);
  2470.  
  2471.     else
  2472.         qsort(args, arrlen(args), sizeof(char *), strpcmp);
  2473.     } else if (ops['O']) {
  2474.     if (ops['i'])
  2475.         qsort(args, arrlen(args), sizeof(char *), invcstrpcmp);
  2476.  
  2477.     else
  2478.         qsort(args, arrlen(args), sizeof(char *), invstrpcmp);
  2479.     }
  2480.     if (ops['c']) {
  2481.     int l, nc, nr, sc, n, t, i;
  2482.     char **ap;
  2483.  
  2484.     for (n = l = 0, ap = args; *ap; ap++, n++)
  2485.         if (l < (t = strlen(*ap)))
  2486.         l = t;
  2487.  
  2488.     nc = (columns - 1) / (l + 2);
  2489.     sc = 0;
  2490.     if (nc)
  2491.         sc = (columns - 1) / nc;
  2492.     else
  2493.         nc = 1;
  2494.     nr = (n + nc - 1) / nc;
  2495.  
  2496.     for (i = 0; i < nr; i++) {
  2497.         ap = args + i;
  2498.         do {
  2499.         l = strlen(*ap);
  2500.         fprintf(fout, "%s", *ap);
  2501.         for (; l < sc; l++)
  2502.             fputc(' ', fout);
  2503.         for (t = nr; t && *ap; t--, ap++);
  2504.         }
  2505.         while (*ap);
  2506.         fputc(ops['N'] ? '\0' : '\n', fout);
  2507.     }
  2508.     if (fout != stdout)
  2509.         fclose(fout);
  2510.     return 0;
  2511.     }
  2512.     for (; *args; args++) {
  2513.     char *arg = *args;
  2514.     int len = -1;
  2515.     if (!ops['r'])
  2516.         arg = getkeystring(arg, &len, func != BIN_ECHO , &nnl);
  2517.     if (ops['D'])
  2518.         fprintdir(arg, fout);
  2519.     else { 
  2520.     if (ops['P'])
  2521.         arg=putprompt(arg, &len, -1);
  2522.     fwrite(arg, 1, len == -1 ? strlen(arg) : len, fout);
  2523.     }
  2524.  
  2525.     if (args[1])
  2526.         fputc(ops['l'] ? '\n' : ops['0'] ? '\0' : ' ', fout);
  2527.     }
  2528.     if (!(ops['n'] || nnl))
  2529.     fputc(ops['N'] ? '\0' : '\n', fout);
  2530.     if (fout != stdout)
  2531.     fclose(fout);
  2532.     return 0;
  2533. }
  2534.  
  2535. int bin_dirs(name, argv, ops, func)    /**/
  2536. char *name;
  2537. char **argv;
  2538. char *ops;
  2539. int func;
  2540. {
  2541.     Lklist l;
  2542.  
  2543.     if (ops['v']) {
  2544.     Lknode node;
  2545.     int t0 = 1;
  2546.  
  2547.     printf("0\t");
  2548.     printdir(pwd);
  2549.     for (node = firstnode(dirstack); node; incnode(node)) {
  2550.         printf("\n%d\t", t0++);
  2551.         printdir(getdata(node));
  2552.     }
  2553.     putchar('\n');
  2554.     return 0;
  2555.     }
  2556.     if (!*argv) {
  2557.     pdstack();
  2558.     return 0;
  2559.     }
  2560.     permalloc();
  2561.     l = newlist();
  2562.     if (!*argv) {
  2563.     heapalloc();
  2564.     return 0;
  2565.     }
  2566.     while (*argv)
  2567.     addnode(l, ztrdup(*argv++));
  2568.     freetable(dirstack, freestr);
  2569.     dirstack = l;
  2570.     heapalloc();
  2571.     return 0;
  2572. }
  2573.  
  2574. int bin_unalias(name, argv, ops, func)    /**/
  2575. char *name;
  2576. char **argv;
  2577. char *ops;
  2578. int func;
  2579. {
  2580.     int ret = 0;
  2581.     Alias dat;
  2582.  
  2583.     while (*argv)
  2584.     if (ops['m']) {
  2585.         int n, i, match = 0;
  2586.         Alias a;
  2587.         Comp com;
  2588.  
  2589.         tokenize(*argv++);
  2590.         if (!(com = parsereg(argv[-1]))) {
  2591.         ret = 1;
  2592.         untokenize(argv[-1]);
  2593.         zwarnnam(name, "bad pattern : %s", argv[-1], 0);
  2594.         continue;
  2595.         }
  2596.         n = aliastab->hsize;
  2597.         for (i = 0; i < n; i++) {
  2598.         for (a = (Alias)aliastab->nodes[i]; a; a = dat) {
  2599.             dat = (Alias)a->next;
  2600.             if (a->nam && a->cmd >= 0 && domatch(a->nam, com, 0))
  2601.             freeanode(remhnode(a->nam, aliastab)), match++;
  2602.         }
  2603.         }
  2604.         if (!ret)
  2605.         ret = !match;
  2606.     } else {
  2607.         if ((dat = (Alias)gethnode(*argv++, aliastab)) && dat->cmd >= 0)
  2608.         freeanode(remhnode(dat->nam, aliastab));
  2609.         else
  2610.         ret = 1;
  2611.     }
  2612.     return ret;
  2613. }
  2614.  
  2615. int bin_disable(name, argv, ops, func)    /**/
  2616. char *name;
  2617. char **argv;
  2618. char *ops;
  2619. int func;
  2620. {
  2621.     Cmdnam chn, chn2, nchn;
  2622.     Comp com;
  2623.  
  2624.     if (!*argv) {
  2625.     listhtable(cmdnamtab, (HFunc) pdisabledcmd);
  2626.     return 0;
  2627.     }
  2628.     if (ops['m']) {
  2629.     for (; *argv; argv++) {
  2630.         tokenize(*argv);
  2631.         if (!(com = parsereg(*argv))) {
  2632.         untokenize(*argv);
  2633.         zwarnnam(name, "bad pattern : %s", *argv, 0);
  2634.         continue;
  2635.         }
  2636.         if (!strncmp(*argv, "TRAP", 4)) {
  2637.         char trapname[20];
  2638.         int t;
  2639.  
  2640.         strncpy(trapname, "TRAP", sizeof(trapname));
  2641.         for (t = 0; t < VSIGCOUNT; t++) {
  2642.             strncpy(trapname + 4, sigs[t], sizeof(trapname) - 5);
  2643.             if (domatch(trapname, com, 0)) {
  2644.             unsettrap(t);
  2645.             chn = (Cmdnam) zcalloc(sizeof *chn);
  2646.             chn->flags |= DISABLED;
  2647.             addhnode(ztrdup(trapname), chn, cmdnamtab, freecmdnam);
  2648.             }
  2649.         }
  2650.         } else {
  2651.         int t, n;
  2652.  
  2653.         n = cmdnamtab->hsize;
  2654.         for (t = 0; t < n; t++)
  2655.             for (chn = (Cmdnam)cmdnamtab->nodes[t]; chn; chn = nchn) {
  2656.                   nchn = (Cmdnam)chn->next;
  2657.             if (domatch(chn->nam, com, 0)) {
  2658.                 chn2 = (Cmdnam) zcalloc(sizeof *chn2);
  2659.                 chn2->flags |= DISABLED;
  2660.                 addhnode(ztrdup(chn->nam), chn2, cmdnamtab,
  2661.                      freecmdnam);
  2662.             }
  2663.             }
  2664.         }
  2665.     }
  2666.     } else {
  2667.     char **p, buf[MAXPATHLEN];
  2668.  
  2669.     while (*argv) {
  2670.         if (!strncmp(*argv, "TRAP", 4))
  2671.         unsettrap(getsignum(*argv + 4));
  2672.         chn = (Cmdnam) zcalloc(sizeof *chn);
  2673.         for (p = path; *p; p++) {
  2674.         strcpy(buf, *path);
  2675.         strcat(buf, "/");
  2676.         strcat(buf, *argv);
  2677.         if (iscom(buf)) {
  2678.             chn->u.name = path;
  2679.             break;
  2680.         }
  2681.         }
  2682.         chn->flags |= p ? EXCMD : DISABLED;
  2683.         addhnode(ztrdup(*argv++), chn, cmdnamtab, freecmdnam);
  2684.     }
  2685.     }
  2686.     return 0;
  2687. }
  2688.  
  2689. int bin_unhash(name, argv, ops, func)    /**/
  2690. char *name;
  2691. char **argv;
  2692. char *ops;
  2693. int func;
  2694. {
  2695.     vptr dat;
  2696.     Comp com;
  2697.  
  2698.     if (ops['m']) {
  2699.     for (; *argv; argv++) {
  2700.         tokenize(*argv);
  2701.         if (!(com = parsereg(*argv))) {
  2702.         untokenize(*argv);
  2703.         zwarnnam(name, "bad pattern : %s", *argv, 0);
  2704.         continue;
  2705.         }
  2706.         if (!strncmp(*argv, "TRAP", 4)) {
  2707.         char trapname[20];
  2708.         int t;
  2709.  
  2710.         strncpy(trapname, "TRAP", sizeof(trapname));
  2711.         for (t = 0; t < VSIGCOUNT; t++) {
  2712.             strncpy(trapname + 4, sigs[t], sizeof(trapname) - 5);
  2713.             if (domatch(trapname, com, 0))
  2714.             unsettrap(t);
  2715.         }
  2716.         } else {
  2717.         Cmdnam chn, nchn;
  2718.         int t, n;
  2719.  
  2720.         n = cmdnamtab->hsize;
  2721.         for (t = 0; t < n; t++)
  2722.             for (chn = (Cmdnam)cmdnamtab->nodes[t]; chn; chn = nchn) {
  2723.                   nchn = (Cmdnam)chn->next;
  2724.             if (domatch(chn->nam, com, 0))
  2725.                 freecmdnam(remhnode(chn->nam, cmdnamtab));
  2726.             }
  2727.         }
  2728.     }
  2729.     } else {
  2730.     while (*argv) {
  2731.         if (!strncmp(*argv, "TRAP", 4))
  2732.         unsettrap(getsignum(*argv + 4));
  2733.         if ((dat = remhnode(*argv++, cmdnamtab)))
  2734.         freecmdnam(dat);
  2735.     }
  2736.     }
  2737.     return 0;
  2738. }
  2739.  
  2740. int bin_unset(name, argv, ops, func)    /**/
  2741. char *name;
  2742. char **argv;
  2743. char *ops;
  2744. int func;
  2745. {
  2746.     int retval = 0;
  2747.     char *s;
  2748.  
  2749.     while ((s = *argv++))
  2750.     if (ops['m']) {
  2751.         int i, n;
  2752.         Comp com;
  2753.         struct param *par, *next;
  2754.  
  2755.         tokenize(s);
  2756.         if (!(com = parsereg(s))) {
  2757.         retval = 1;
  2758.         untokenize(s);
  2759.         zwarnnam(name, "bad pattern : %s", s, 0);
  2760.         continue;
  2761.         }
  2762.         n = paramtab->hsize;
  2763.         for (i = 0; i < n; i++)
  2764.         for (par = (struct param *)paramtab->nodes[i]; par;
  2765.              par = next) {
  2766.             next = (struct param *)par->next;
  2767.             if (domatch(par->nam, com, 0))
  2768.             unsetparam(par->nam);
  2769.         }
  2770.     } else {
  2771.         if (gethnode(s, paramtab))
  2772.         unsetparam(s);
  2773.         else
  2774.         retval = 1;
  2775.     }
  2776.     return retval;
  2777. }
  2778.  
  2779. static char *zbuf;
  2780. static int readfd;
  2781.  
  2782. int zread()
  2783. {                /**/
  2784.     char cc;
  2785.  
  2786.     if (zbuf)
  2787.     return (*zbuf) ? *zbuf++ : EOF;
  2788.     if (read(readfd, &cc, 1) != 1)
  2789.     return EOF;
  2790.     return (int) cc;
  2791. }
  2792.  
  2793. extern int cs;
  2794.  
  2795. int bin_read(name, args, ops, func)    /**/
  2796. char *name;
  2797. char **args;
  2798. char *ops;
  2799. int func;
  2800. {
  2801.     char *reply = "REPLY", *readpmpt;
  2802.     int bsiz, c = 0, gotnl = 0, al = 0;
  2803.     char *buf, *bptr, *firstarg = *args, *zbuforig;
  2804.     Lklist readll = newlist();
  2805.  
  2806.     if (ops['k']) {
  2807.     int nchars, val;
  2808.     char cc, d;
  2809.     int haso = 0, isem = !strcmp(term, "emacs");
  2810.  
  2811.     if (SHTTY == -1) {
  2812.         SHTTY = open("/dev/tty", O_RDWR);
  2813.         haso = 1;
  2814.     }
  2815.  
  2816.     if (SHTTY == -1) {
  2817.         fprintf(stderr, "not interactive and can't open terminal\n");
  2818.         fflush(stderr);
  2819.         return 1;
  2820.     }
  2821.     if (*args && idigit(**args)) {
  2822.         if (!(nchars = atoi(*args)))
  2823.         nchars = 1;
  2824.         args++;
  2825.     } else
  2826.         nchars = 1;
  2827.  
  2828.     if (*args && **args == '/') {
  2829.         fprintf(stderr, "%s", putprompt(*args + 1, &c, 0));
  2830.         fflush(stderr);
  2831.         args++;
  2832.     }
  2833.         
  2834.     if (*args) reply = *args++;
  2835.  
  2836.     bptr = buf = (char *) zalloc(nchars + 1);
  2837.     buf[nchars] = '\0';
  2838.  
  2839.     attachtty(mypgrp);
  2840.     if (!isem)
  2841.         setcbreak();
  2842.  
  2843.     for (bptr = buf; nchars;) {
  2844. #ifdef FIONREAD
  2845.         ioctl(SHTTY, FIONREAD, (char *) &val);
  2846.         if (val) {
  2847.         if (!isem)
  2848.             settyinfo(&shttyinfo);
  2849.         if (ops['e'] || ops['E']) {
  2850.             printf("%s\n", buf);
  2851.             if (ops['e']) zsfree(buf);
  2852.         }
  2853.         if (!ops['e'])
  2854.             setsparam(reply, buf);
  2855.  
  2856.         if (haso) {
  2857.             close(SHTTY);
  2858.             SHTTY = -1;
  2859.         }
  2860.         return 1;
  2861.         }
  2862. #endif
  2863.         if (read(SHTTY, &cc, 1) == 1)
  2864.         nchars--, *bptr++ = cc;
  2865.     }
  2866.     if (isem)
  2867.         while (read(SHTTY, &d, 1) == 1 && d != '\n');
  2868.     else
  2869.         settyinfo(&shttyinfo);
  2870.  
  2871.     if (haso) {
  2872.         close(SHTTY);
  2873.         SHTTY = -1;
  2874.     }
  2875.  
  2876.     if (ops['e'] || ops['E']) {
  2877.         printf("%s\n", buf);
  2878.         if (ops['e']) zsfree(buf);
  2879.     }
  2880.     if (!ops['e'])
  2881.         setsparam(reply, buf);
  2882.     return 0;
  2883.     }
  2884.     if (ops['l']) {
  2885.     if (!inzlefunc) {
  2886.         zwarnnam(name, "option valid only in functions called from zle",
  2887.             NULL, 0);
  2888.         errflag = 0;
  2889.         return 1;
  2890.     }
  2891.     if (ops['n']) {
  2892.         char nbuf[14];
  2893.  
  2894.         if (ops['e'] || ops['E'])
  2895.         printf("%d\n", cs + 1);
  2896.         if (!ops['e']) {
  2897.         sprintf(nbuf, "%d", cs + 1);
  2898.         setsparam(*args ? *args : "REPLY", ztrdup(nbuf));
  2899.         }
  2900.         return 0;
  2901.     }
  2902.     if (ops['e'] || ops['E'])
  2903.         printf("%s\n", (char *) line);
  2904.     if (!ops['e'])
  2905.         setsparam(*args ? *args : "REPLY", ztrdup((char *) line));
  2906.     return 0;
  2907.     }
  2908.     if (ops['c']) {
  2909.     if (!inzlefunc) {
  2910.         zwarnnam(name, "option valid only in functions called from zle",
  2911.             NULL, 0);
  2912.         errflag = 0;
  2913.         return 1;
  2914.     }
  2915.     if (ops['n']) {
  2916.         char nbuf[14];
  2917.  
  2918.         if (ops['e'] || ops['E'])
  2919.         printf("%d\n", clwpos + 1);
  2920.         if (!ops['e']) {
  2921.         sprintf(nbuf, "%d", clwpos + 1);
  2922.         setsparam(*args ? *args : "REPLY", ztrdup(nbuf));
  2923.         }
  2924.         return 0;
  2925.     }
  2926.     if (ops['A'] && !ops['e']) {
  2927.         char **p, **b = (char **) zcalloc((clwnum + 1) * sizeof(char *));
  2928.         int i;
  2929.  
  2930.         for (i = 0, p = b; i < clwnum; p++, i++)
  2931.         *p = ztrdup(clwords[i]);
  2932.  
  2933.         setaparam(*args ? *args : "reply", b);
  2934.         return 0;
  2935.     }
  2936.     if (ops['e'] || ops['E']) {
  2937.         int i;
  2938.  
  2939.         for (i = 0; i < clwnum; i++)
  2940.         printf("%s\n", clwords[i]);
  2941.  
  2942.         if (ops['e']) return 0;
  2943.     }
  2944.     if (*args) {
  2945.         int i = 0;
  2946.  
  2947.         for (; i < clwnum && *args; args++, i++)
  2948.         setsparam(*args, ztrdup(clwords[i]));
  2949.     }
  2950.     else
  2951.         setsparam("REPLY", ztrdup(clwords[clwpos]));
  2952.  
  2953.     return 0;
  2954.     }
  2955.     if (ops['q']) {
  2956.     char *readbuf;
  2957.     int haso = 0;
  2958.  
  2959.     if (SHTTY == -1)
  2960.         SHTTY = open("/dev/tty", O_RDWR), haso = 1;
  2961.  
  2962.     if (SHTTY == -1) {
  2963.         fprintf(stderr, "not interactive and can't open terminal\n");
  2964.         fflush(stderr);
  2965.         return 1;
  2966.     }
  2967.  
  2968.     readbuf = (char *) zalloc(2);
  2969.     readbuf[1] = '\0';
  2970.  
  2971.     if (*args && **args == '/') {
  2972.         fprintf(stderr, "%s", putprompt(*args + 1, &c, 0));
  2973.         fflush(stderr);
  2974.         args++;
  2975.     }
  2976.     reply = (*args) ? *args++ : "REPLY";
  2977.  
  2978.     readbuf[0] = ((char)getquery()) == 'y' ? 'y' : 'n';
  2979.  
  2980.     if (haso) {
  2981.         close(SHTTY);
  2982.         SHTTY = -1;
  2983.     }
  2984.  
  2985.      if (ops['e'] || ops['E']) {
  2986.          printf("%s\n", readbuf);
  2987.          if (ops['e']) free(readbuf);
  2988.      }
  2989.      if (!ops['e'])
  2990.         setsparam(reply, readbuf);
  2991.  
  2992.     return readbuf[0] == 'n';
  2993.     }
  2994.     if (*args && **args == '?')
  2995.     args++;
  2996.     reply = *args ? *args++ : ops['A'] ? "reply" : "REPLY";
  2997.     if (ops['A'] && *args) {
  2998.     zwarnnam(name, "only one array argument allowed", NULL, 0);
  2999.     return 1;
  3000.     }
  3001.  
  3002.     if (ops['u'] && !ops['p']) {
  3003.     for (readfd = 0; readfd < 10; ++readfd)
  3004.         if (ops[readfd + '0'])
  3005.         break;
  3006.     if (readfd == 10)
  3007.         readfd = 0;
  3008.     } else if (ops['p'])
  3009.     readfd = coprocin;
  3010.     else {
  3011.     attachtty((jobtab[thisjob].gleader) ? jobtab[thisjob].gleader : mypgrp);
  3012.     readfd = 0;
  3013.     if (firstarg) {
  3014.         for (readpmpt = firstarg;
  3015.          *readpmpt && *readpmpt != '?'; readpmpt++);
  3016.         if (*readpmpt++) {
  3017.         if (isatty(0))
  3018.             write(2, readpmpt, strlen(readpmpt));
  3019.         readpmpt[-1] = '\0';
  3020.         }
  3021.     }
  3022. #if 0
  3023.     else if (isset(SHINSTDIN) && unset(INTERACTIVE)) {
  3024.         if (isatty(1))
  3025.         readfd = 1;
  3026.         else if (isatty(2))
  3027.         readfd = 2;
  3028.     }
  3029. #endif
  3030.     }
  3031.  
  3032.     zbuforig = zbuf = (!ops['z']) ? NULL :
  3033.     (full(bufstack)) ? (char *)getnode(bufstack) : ztrdup("");
  3034.     while (*args || (ops['A'] && !gotnl)) {
  3035.     buf = bptr = (char *)zalloc(bsiz = 64);
  3036.     for (;;) {
  3037.         if (gotnl)
  3038.         break;
  3039.         c = zread();
  3040.         if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
  3041.         bptr--;
  3042.         continue;
  3043.         }
  3044.         if (c == EOF || (isep(c) && bptr != buf) || c == '\n')
  3045.         break;
  3046.         if (isep(c))
  3047.         continue;
  3048.         *bptr++ = c;
  3049.         if (bptr == buf + bsiz) {
  3050.         buf = realloc(buf, bsiz *= 2);
  3051.         bptr = buf + (bsiz / 2);
  3052.         }
  3053.     }
  3054.     if (c == EOF) {
  3055.         if (readfd == coprocin) {
  3056.         close(coprocin);
  3057.         close(coprocout);
  3058.         coprocin = coprocout = -1;
  3059.         }
  3060.         return 1;
  3061.     }
  3062.     if (c == '\n')
  3063.         gotnl = 1;
  3064.     *bptr = '\0';
  3065.     if (ops['e'] || ops['E']) {
  3066.         printf("%s\n", buf);
  3067.         if (ops['e']) free(buf);
  3068.     }
  3069.     if (!ops['e']) {
  3070.         if (ops['A']) {
  3071.         addnode(readll, buf);
  3072.         al++;
  3073.         }
  3074.         else
  3075.         setsparam(reply, buf);
  3076.     }
  3077.     if (!ops['A'])
  3078.         reply = *args++;
  3079.     }
  3080.     if (ops['A']) {
  3081.     char **pp, **p = NULL;
  3082.     Lknode n;
  3083.     
  3084.     p = (ops['e'] ? (char **) NULL
  3085.          : (char **) zcalloc((al + 1) * sizeof(char *)));
  3086.     for (pp = p, n = firstnode(readll); n; incnode(n)) {
  3087.         if (ops['e'] || ops['E']) {
  3088.         printf("%s\n", (char *)getdata(n));
  3089.         if (p) zsfree(getdata(n));
  3090.         }
  3091.         else
  3092.         *pp++ = (char *) getdata(n);
  3093.     }
  3094.     if (p)
  3095.         setaparam(reply, p);
  3096.     return 0;
  3097.     }
  3098.     buf = bptr = (char *)zalloc(bsiz = 64);
  3099.     if (!gotnl)
  3100.     for (;;) {
  3101.         c = zread();
  3102.         if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
  3103.         bptr--;
  3104.         continue;
  3105.         }
  3106.         if (c == EOF || (c == '\n' && !zbuf))
  3107.         break;
  3108.         if (isep(c) && bptr == buf)
  3109.         continue;
  3110.         *bptr++ = c;
  3111.         if (bptr == buf + bsiz) {
  3112.         buf = realloc(buf, bsiz *= 2);
  3113.         bptr = buf + (bsiz / 2);
  3114.         }
  3115.     }
  3116.     while (bptr > buf && isep(bptr[-1]))
  3117.     bptr--;
  3118.     *bptr = '\0';
  3119.     if (ops['e'] || ops['E']) {
  3120.     printf("%s\n", buf);
  3121.     if (ops['e']) zsfree(buf);
  3122.     }
  3123.     if (!ops['e'])
  3124.     setsparam(reply, buf);
  3125.     if (zbuforig) {
  3126.     char first = *zbuforig;
  3127.     zsfree(zbuforig);
  3128.     if (!first)
  3129.         return 1;
  3130.     } else if (c == EOF) {
  3131.     if (readfd == coprocin) {
  3132.         close(coprocin);
  3133.         close(coprocout);
  3134.         coprocin = coprocout = -1;
  3135.     }
  3136.     return 1;
  3137.     }
  3138.     return 0;
  3139. }
  3140.  
  3141. int bin_vared(name, args, ops, func)    /**/
  3142. char *name;
  3143. char **args;
  3144. char *ops;
  3145. int func;
  3146. {
  3147.     char *s;
  3148.     char *t;
  3149.     struct param *pm;
  3150.     int create = 0, pl1, pl2;
  3151.     char *p1 = NULL, *p2 = NULL;
  3152.  
  3153.     while (*args && **args == '-') {
  3154.     while (*++(*args))
  3155.         switch (**args) {
  3156.         case 'c':
  3157.         create = 1;
  3158.         break;
  3159.         case 'p':
  3160.         if ((*args)[1])
  3161.             p1 = *args + 1, *args = "" - 1;
  3162.         else if (args[1])
  3163.             p1 = *(++args), *args = "" - 1;
  3164.         else {
  3165.             zwarnnam(name, "prompt string expected after -p", NULL, 0);
  3166.             return 1;
  3167.         }
  3168.         break;
  3169.         case 'r':
  3170.         if ((*args)[1])
  3171.             p2 = *args + 1, *args = "" - 1;
  3172.         else if (args[1])
  3173.             p2 = *(++args), *args = "" - 1;
  3174.         else {
  3175.             zwarnnam(name, "prompt string expected after -r", NULL, 0);
  3176.             return 1;
  3177.         }
  3178.         break;
  3179.         default:
  3180.         zwarnnam(name, "unknown option: %s", *args, 0);
  3181.         return 1;
  3182.         }
  3183.     args++;
  3184.     }
  3185.  
  3186.     if (!*args) {
  3187.     zwarnnam(name, "missing variable", NULL, 0);
  3188.     return 1;
  3189.     }
  3190.     if (!(s = getsparam(args[0]))) {
  3191.     if (create)
  3192.         createparam(args[0], PMFLAG_s);
  3193.     else {
  3194.         zwarnnam(name, "no such variable: %s", args[0], 0);
  3195.         return 1;
  3196.     }
  3197.     }
  3198.     permalloc();
  3199.     pushnode(bufstack, ztrdup(s));
  3200.     heapalloc();
  3201.     if (p1)
  3202.     p1 = putprompt(p1, &pl1, 0);
  3203.     else
  3204.     pl1 = 0;
  3205.     if (p2)
  3206.     p2 = putprompt(p2, &pl2, 0);
  3207.     t = (char *)zleread((unsigned char *)p1, (unsigned char *)p2, pl1, pl2);
  3208.     if (!t || errflag)
  3209.     return 1;
  3210.     if (t[strlen(t) - 1] == '\n')
  3211.     t[strlen(t) - 1] = '\0';
  3212.     pm = (struct param *) gethnode(args[0], paramtab);
  3213.     if (pmtype(pm) == PMFLAG_A)
  3214.     setaparam(args[0], spacesplit(t));
  3215.     else
  3216.     setsparam(args[0], t);
  3217.     return 0;
  3218. }
  3219.  
  3220. #define fset(X) (flags & X)
  3221.  
  3222. /* execute a builtin handler function after parsing the arguments */
  3223.  
  3224. int execbin(args, cnode)    /**/
  3225. Lklist args;
  3226. Cmdnam cnode;
  3227. {
  3228.     struct bincmd *b;
  3229.     char ops[128], *arg, *pp, *name, **argv, **oargv, *optstr;
  3230.     int t0, flags, sense, argc = 0, execop;
  3231.     Lknode n;
  3232.     char *oxarg, *xarg = NULL;
  3233.  
  3234.     auxdata = NULL;
  3235.     auxlen = 0;
  3236.     for (t0 = 0; t0 != 128; t0++)
  3237.     ops[t0] = 0;
  3238.     name = (char *)ugetnode(args);
  3239.     b = builtins + cnode->u.binnum;
  3240.  
  3241. /* the 'builtin' builtin is handled specially */
  3242.  
  3243.     if (b->funcid == BIN_BUILTIN) {
  3244.     Cmdnam cname;
  3245.  
  3246.     if (!(name = (char *)ugetnode(args))) {
  3247.         zerrnam("builtin", "command name expected", NULL, 0);
  3248.         return 1;
  3249.     }
  3250.     if ((cname = (Cmdnam) gethnode(name, cmdnamtab)) &&
  3251.         (cname->flags & BUILTIN) &&
  3252.         !(cname->flags & EXCMD))
  3253.         b = builtins + cname->u.binnum;
  3254.     else
  3255.         for (b = builtins; b->name; b++)
  3256.         if (!strcmp(name, b->name))
  3257.             break;
  3258.     if (!b->name) {
  3259.         zerrnam("builtin", "no such builtin: %s", name, 0);
  3260.         return 1;
  3261.     }
  3262.     }
  3263.     flags = b->flags;
  3264.     arg = (char *)ugetnode(args);
  3265.     optstr = b->optstr;
  3266.     if (flags & BINF_ECHOPTS && arg && strcmp(arg, "-n"))
  3267.     optstr = NULL;
  3268.     if (optstr)
  3269.     while (arg &&
  3270.            ((sense = *arg == '-') || (fset(BINF_PLUSOPTS) && *arg == '+')) &&
  3271.            (fset(BINF_PLUSOPTS) || !atoi(arg))) {
  3272.         if (xarg) {
  3273.         oxarg = tricat(xarg, " ", arg);
  3274.         zsfree(xarg);
  3275.         xarg = oxarg;
  3276.         } else
  3277.         xarg = ztrdup(arg);
  3278.         if (arg[1] == '-')
  3279.         arg++;
  3280.         if (!arg[1]) {
  3281.         ops['-'] = 1;
  3282.         if (!sense)
  3283.             ops['+'] = 1;
  3284.         } else
  3285.         ops['@'] = 1;
  3286.         execop = -1;
  3287.         while (*++arg)
  3288.         if (strchr(b->optstr, execop = (int) *arg))
  3289.             ops[(int)*arg] = (sense) ? 1 : 2;
  3290.         else
  3291.             break;
  3292.         if (*arg) {
  3293.         zerr("bad option: %c", NULL, *arg);
  3294.         zsfree(xarg);
  3295.         return 1;
  3296.         }
  3297.         arg = (char *)ugetnode(args);
  3298.         if (fset(BINF_SETOPTS) && execop == 'o') {
  3299.         int c;
  3300.  
  3301.         if (!arg)
  3302.             prtopt(0);
  3303.         else {
  3304.             c = optlookup(arg);
  3305.             if (c == -1) {
  3306.             zerr("bad option: %s", arg, 0);
  3307.             zsfree(xarg);
  3308.             return 1;
  3309.             } else {
  3310.             if (c == INTERACTIVE)
  3311.                 zerr("can't change option: %s", arg, 0);
  3312.             else
  3313.                 ops[c] = ops['o'];
  3314.             arg = (char *)ugetnode(args);
  3315.             }
  3316.         }
  3317.         }
  3318.         if ((fset(BINF_PRINTOPTS) && ops['R']) || ops['-'])
  3319.         break;
  3320.         if (fset(BINF_SETOPTS) && ops['A']) {
  3321.         auxdata = arg;
  3322.         arg = (char *)ugetnode(args);
  3323.         break;
  3324.         }
  3325.         if (fset(BINF_FCOPTS) && execop == 'e') {
  3326.         auxdata = arg;
  3327.         arg = (char *)ugetnode(args);
  3328.         }
  3329.         if (fset(BINF_TYPEOPT) && (execop == 'L' || execop == 'R' ||
  3330.                        execop == 'Z' || execop == 'i') && arg && idigit(*arg)) {
  3331.         auxlen = atoi(arg);
  3332.         arg = (char *)ugetnode(args);
  3333.         }
  3334.     }
  3335.     if (fset(BINF_R))
  3336.     auxdata = "-";
  3337.     if ((pp = b->defopts))
  3338.     while (*pp)
  3339.         ops[(int)*pp++] = 1;
  3340.     if (arg) {
  3341.     argc = 1;
  3342.     n = firstnode(args);
  3343.     while (n)
  3344.         argc++, incnode(n);
  3345.     }
  3346.     oargv = argv = (char **)ncalloc(sizeof(char **) * (argc + 1));
  3347.  
  3348.     if ((*argv++ = arg))
  3349.     while ((*argv++ = (char *)ugetnode(args)));
  3350.     argv = oargv;
  3351.     if (errflag) {
  3352.     zsfree(xarg);
  3353.     return 1;
  3354.     }
  3355.     if (argc < b->minargs || (argc > b->maxargs && b->maxargs != -1)) {
  3356.     zerrnam(name, (argc < b->minargs)
  3357.         ? "not enough arguments" : "too many arguments", NULL, 0);
  3358.     zsfree(xarg);
  3359.     return 1;
  3360.     }
  3361.     if (isset(XTRACE)) {
  3362.     char **execpp = argv;
  3363.  
  3364.     fprintf(stderr, "%s%s", (prompt4) ? prompt4 : "", name);
  3365.     if (xarg)
  3366.         fprintf(stderr, " %s", xarg);
  3367.     while (*execpp)
  3368.         fprintf(stderr, " %s", *execpp++);
  3369.     fputc('\n', stderr);
  3370.     fflush(stderr);
  3371.     }
  3372.     zsfree(xarg);
  3373.     return (*(b->handlerfunc)) (name, argv, ops, b->funcid);
  3374. }
  3375.  
  3376. struct asgment *getasg(s)    /**/
  3377. char *s;
  3378. {
  3379.     static struct asgment asg;
  3380.  
  3381.     if (!s)
  3382.     return NULL;
  3383.     if (*s == '=') {
  3384.     zerr("bad assignment", NULL, 0);
  3385.     return NULL;
  3386.     }
  3387.     asg.name = s;
  3388.     for (; *s && *s != '='; s++);
  3389.     if (*s) {
  3390.     *s = '\0';
  3391.     asg.value = s + 1;
  3392.     } else
  3393.     asg.value = NULL;
  3394.     return &asg;
  3395. }
  3396.  
  3397. /* ., source */
  3398.  
  3399. int bin_dot(name, argv, ops, func)    /**/
  3400. char *name;
  3401. char **argv;
  3402. char *ops;
  3403. int func;
  3404. {
  3405.     char **old, *old0;
  3406.     int ret, diddot = 0, dotdot = 0;
  3407.     char buf[MAXPATHLEN];
  3408.     char *s, **t, *enam;
  3409.  
  3410.     if (!*argv)
  3411.     return 0;
  3412.     old = pparams;
  3413.     old0 = argzero;
  3414.     if (argv[1]) {
  3415.     permalloc();
  3416.     pparams = arrdup(argv + 1);
  3417.     heapalloc();
  3418.     }
  3419.     enam = argzero = ztrdup(*argv);
  3420.     errno = ENOENT;
  3421.     ret = 1;
  3422.     if (*name != '.' && access(argzero, F_OK) == 0) {
  3423.     diddot = 1;
  3424.     ret = source(enam = argzero);
  3425.     }
  3426.     if (ret) {
  3427.     for (s = argzero; *s; s++)
  3428.         if (*s == '/') {
  3429.         if (*argzero == '.') {
  3430.             if (argzero + 1 == s)
  3431.             ++diddot;
  3432.             else if (argzero[1] == '.' && argzero + 2 == s)
  3433.             ++dotdot;
  3434.         }
  3435.         ret = source(argzero);
  3436.         break;
  3437.         }
  3438.     if (!*s || (ret && isset(PATHDIRS) && diddot < 2 && dotdot == 0)) {
  3439.         for (t = path; *t; t++) {
  3440.         if ((*t)[0] == '.' && !(*t)[1]) {
  3441.             if (diddot)
  3442.             continue;
  3443.             diddot = 1;
  3444.             strcpy(buf, argzero);
  3445.         } else
  3446.             sprintf(buf, "%s/%s", *t, argzero);
  3447.         if (access(buf, F_OK) == 0) {
  3448.             ret = source(enam = buf);
  3449.             break;
  3450.         }
  3451.         }
  3452.     }
  3453.     }
  3454.     if (argv[1]) {
  3455.     freearray(pparams);
  3456.     pparams = old;
  3457.     }
  3458.     if (ret)
  3459.     zerrnam(name, "%e: %s", enam, errno);
  3460.     zsfree(argzero);
  3461.     argzero = old0;
  3462.     return ret ? ret : lastval;
  3463. }
  3464.  
  3465. int bin_set(name, argv, ops, func)    /**/
  3466. char *name;
  3467. char **argv;
  3468. char *ops;
  3469. int func;
  3470. {
  3471.     struct option *opp;
  3472.     char **x;
  3473.  
  3474.     if (((ops['+'] && ops['-']) || !ops['-']) && !ops['@'] && !*argv) {
  3475.     showflag = ~0;
  3476.     showflag2 = ops[(int)'+'];
  3477.     listhtable(paramtab, (HFunc) printparam);
  3478.     }
  3479.     for (opp = optns; opp->name; opp++)
  3480.     if (ops[(int)opp->id] == 1)
  3481.         opts[(int)opp->id] = OPT_SET;
  3482.     else if (ops[(int)opp->id] == 2)
  3483.         opts[(int)opp->id] = OPT_UNSET;
  3484.     if (ops['A'] && !auxdata) {
  3485.     showflag = PMFLAG_A;
  3486.     showflag2 = ops[(int)'+'];
  3487.     listhtable(paramtab, (HFunc) printparam);
  3488.     }
  3489.     if (!*argv && !ops['-'])
  3490.     return 0;
  3491.     permalloc();
  3492.     x = arrdup(argv);
  3493.     heapalloc();
  3494.     if (ops['A'])
  3495.     setaparam(auxdata, x);
  3496.     else {
  3497.     freearray(pparams);
  3498.     pparams = x;
  3499.     }
  3500.     return 0;
  3501. }
  3502.  
  3503. #define pttime(X) printf("%ldm%lds",((long) (X))/3600,((long) (X))/60%60)
  3504.  
  3505. int bin_times(name, argv, ops, func)    /**/
  3506. char *name;
  3507. char **argv;
  3508. char *ops;
  3509. int func;
  3510. {
  3511.     struct tms buf;
  3512.  
  3513.     if (times(&buf) == -1)
  3514.     return 1;
  3515.     pttime(buf.tms_utime);
  3516.     putchar(' ');
  3517.     pttime(buf.tms_stime);
  3518.     putchar('\n');
  3519.     pttime(buf.tms_cutime);
  3520.     putchar(' ');
  3521.     pttime(buf.tms_cstime);
  3522.     putchar('\n');
  3523.     return 0;
  3524. }
  3525.  
  3526. int bin_getopts(name, argv, ops, func)    /**/
  3527. char *name;
  3528. char **argv;
  3529. char *ops;
  3530. int func;
  3531. {
  3532.     char *optstr = *argv++, *var = *argv++;
  3533.     char **args = (*argv) ? argv : pparams;
  3534.     static int optcind = 1, quiet;
  3535.     char *str, optbuf[3], *opch = optbuf + 1;
  3536.     int oldzoptind = zoptind;
  3537.  
  3538.     if (zoptind < 1)
  3539.     zoptind = 1;
  3540.     if (zoptind == 1)
  3541.     quiet = 0;
  3542.     optbuf[0] = '+';
  3543.     optbuf[1] = optbuf[2] = '\0';
  3544.     zsfree(zoptarg);
  3545.     zoptarg = ztrdup("");
  3546.     setsparam(var, ztrdup(""));
  3547.     if (*optstr == ':') {
  3548.     quiet = 1;
  3549.     optstr++;
  3550.     }
  3551.     if (zoptind > arrlen(args))
  3552.     return 1;
  3553.     str = args[zoptind - 1];
  3554.     if ((*str != '+' && *str != '-') || optcind >= (int) strlen(str) ||
  3555.     !strcmp("--", str)) {
  3556.     if (*str == '+' || *str == '-')
  3557.         zoptind++;
  3558.     optcind = 0;
  3559.     return 1;
  3560.     }
  3561.     if (!optcind)
  3562.     optcind = 1;
  3563.     *opch = str[optcind++];
  3564.     if (!args[zoptind - 1][optcind]) {
  3565.     zoptind++;
  3566.     optcind = 0;
  3567.     }
  3568.     for (; *optstr; optstr++)
  3569.     if (*opch == *optstr)
  3570.         break;
  3571.     if (!*optstr) {
  3572.     setsparam(var, ztrdup("?"));
  3573.     zoptind = oldzoptind;
  3574.     if (quiet) {
  3575.         zsfree(zoptarg);
  3576.         zoptarg = ztrdup(opch);
  3577.         return 0;
  3578.     }
  3579.     zerr("bad option: %c", NULL, *opch);
  3580.     errflag = 0;
  3581.     return 0;
  3582.     }
  3583.     setsparam(var, ztrdup(opch - (*str == '+')));
  3584.     if (optstr[1] == ':') {
  3585.     if (!args[zoptind - 1]) {
  3586.         if (quiet) {
  3587.         zsfree(zoptarg);
  3588.         zoptarg = ztrdup(opch);
  3589.         setsparam(var, ztrdup(":"));
  3590.         return 0;
  3591.         }
  3592.         setsparam(var, ztrdup("?"));
  3593.         zerr("argument expected after %c option", NULL, *opch);
  3594.         errflag = 0;
  3595.         return 0;
  3596.     }
  3597.     zsfree(zoptarg);
  3598.     zoptarg = ztrdup(args[zoptind - 1] + optcind);
  3599.     zoptind++;
  3600.     optcind = 0;
  3601.     }
  3602.     return 0;
  3603. }
  3604.  
  3605. /* get a signal number from a string */
  3606.  
  3607. int getsignum(s)        /**/
  3608. char *s;
  3609. {
  3610.     int x = atoi(s), t0;
  3611.  
  3612.     if (idigit(*s) && x >= 0 && x < VSIGCOUNT)
  3613.     return x;
  3614.     for (t0 = 0; t0 != VSIGCOUNT; t0++)
  3615.     if (!strcmp(s, sigs[t0]))
  3616.         return t0;
  3617.     return -1;
  3618. }
  3619.  
  3620. int bin_trap(name, argv, ops, func)    /**/
  3621. char *name;
  3622. char **argv;
  3623. char *ops;
  3624. int func;
  3625. {
  3626.     List l;
  3627.     char *arg;
  3628.  
  3629.     if (!*argv) {
  3630.     int t0;
  3631.  
  3632.     for (t0 = 0; t0 != VSIGCOUNT; t0++)
  3633.         if (sigtrapped[t0])
  3634.         if (!sigfuncs[t0])
  3635.             printf("TRAP%s () {}\n", sigs[t0]);
  3636.         else {
  3637.             char *s =
  3638.             getpermtext((vptr) dupstruct((vptr) sigfuncs[t0]));
  3639.  
  3640.             printf("TRAP%s () {\n\t%s\n}\n", sigs[t0], s);
  3641.             zsfree(s);
  3642.         }
  3643.     return 0;
  3644.     }
  3645.     if ((getsignum(*argv) != -1) || (!strcmp(*argv, "-") && argv++)) {
  3646.     int t0;
  3647.  
  3648.     if (!*argv)
  3649.         for (t0 = 0; t0 != VSIGCOUNT; t0++)
  3650.         unsettrap(t0);
  3651.     else
  3652.         while (*argv)
  3653.         unsettrap(getsignum(*argv++));
  3654.     return 0;
  3655.     }
  3656.     arg = *argv++;
  3657.     if (!*arg)
  3658.     l = NULL;
  3659.     else if (!(l = parselstring(arg))) {
  3660.     zerrnam(name, "couldn't parse trap command", NULL, 0);
  3661.     return 1;
  3662.     }
  3663.     for (; *argv; argv++) {
  3664.     int sg = getsignum(*argv);
  3665.  
  3666.     if (sg == -1) {
  3667.         zerrnam(name, "undefined signal: %s", *argv, 0);
  3668.         break;
  3669.     }
  3670.     settrap(sg, l);
  3671.     }
  3672.     if (l)
  3673.     popheap();
  3674.     return errflag;
  3675. }
  3676.  
  3677. #ifdef RLIM_INFINITY
  3678. void printulimit(lim, hard)    /**/
  3679. int lim;
  3680. int hard;
  3681. {
  3682.     long t0;
  3683.  
  3684.     t0 = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
  3685.     switch (lim) {
  3686.     case RLIMIT_CPU:
  3687.     printf("cpu time (seconds)         ");
  3688.     break;
  3689.     case RLIMIT_FSIZE:
  3690.     printf("file size (blocks)         ");
  3691.     t0 /= 512;
  3692.     break;
  3693.     case RLIMIT_DATA:
  3694.     printf("data seg size (kbytes)     ");
  3695.     t0 /= 1024;
  3696.     break;
  3697.     case RLIMIT_STACK:
  3698.     printf("stack size (kbytes)        ");
  3699.     t0 /= 1024;
  3700.     break;
  3701.     case RLIMIT_CORE:
  3702.     printf("core file size (blocks)    ");
  3703.     t0 /= 512;
  3704.     break;
  3705. #ifdef RLIMIT_RSS
  3706.     case RLIMIT_RSS:
  3707.     printf("resident set size (kbytes) ");
  3708.     t0 /= 1024;
  3709.     break;
  3710. #endif
  3711. #ifdef RLIMIT_MEMLOCK
  3712.     case RLIMIT_MEMLOCK:
  3713.     printf("locked-in-memory size (kb) ");
  3714.     t0 /= 1024;
  3715.     break;
  3716. #endif
  3717. #ifdef RLIMIT_NPROC
  3718.     case RLIMIT_NPROC:
  3719.     printf("processes                  ");
  3720.     break;
  3721. #endif
  3722. #ifdef RLIMIT_OFILE
  3723.     case RLIMIT_OFILE:
  3724.     printf("open files                 ");
  3725.     break;
  3726. #endif
  3727. #ifdef RLIMIT_NOFILE
  3728.     case RLIMIT_NOFILE:
  3729.     printf("file descriptors           ");
  3730.     break;
  3731. #endif
  3732. #ifdef RLIMIT_VMEM
  3733.     case RLIMIT_VMEM:
  3734.     printf("virtual memory size (kb)   ");
  3735.     t0 /= 1024;
  3736.     break;
  3737. #endif
  3738.     }
  3739.     if (t0 == RLIM_INFINITY)
  3740.     printf("unlimited\n");
  3741.     else
  3742.     printf("%ld\n", t0);
  3743. }
  3744. #endif
  3745.  
  3746. int bin_ulimit(name, argv, ops, func)    /**/
  3747. char *name;
  3748. char **argv;
  3749. char *ops;
  3750. int func;
  3751. {
  3752. #ifndef RLIM_INFINITY
  3753.     zwarnnam(name, "not available on this system", NULL, 0);
  3754.     return 1;
  3755. #else
  3756.     int res, hard;
  3757.  
  3758.     hard = ops['H'];
  3759.     if (ops['a'] || !ops['@'])
  3760.     res = -1;
  3761.     else if (ops['t'])
  3762.     res = RLIMIT_CPU;
  3763.     else if (ops['f'])
  3764.     res = RLIMIT_FSIZE;
  3765.     else if (ops['d'])
  3766.     res = RLIMIT_DATA;
  3767.     else if (ops['s'])
  3768.     res = RLIMIT_STACK;
  3769.     else if (ops['c'])
  3770.     res = RLIMIT_CORE;
  3771. #ifdef RLIMIT_MEMLOCK
  3772.     else if (ops['l'])
  3773.     res = RLIMIT_MEMLOCK;
  3774. #endif
  3775. #ifdef RLIMIT_RSS
  3776.     else if (ops['m'])
  3777.     res = RLIMIT_RSS;
  3778. #endif
  3779. #ifdef RLIMIT_NOFILE
  3780.     else if (ops['n'])
  3781.     res = RLIMIT_NOFILE;
  3782. #endif
  3783. #ifdef RLIMIT_OFILE
  3784.     else if (ops['o'])
  3785.     res = RLIMIT_OFILE;
  3786. #endif
  3787. #ifdef RLIMIT_NPROC
  3788.     else if (ops['p'])
  3789.     res = RLIMIT_NPROC;
  3790. #endif
  3791. #ifdef RLIMIT_VMEM
  3792.     else if (ops['v'])
  3793.     res = RLIMIT_VMEM;
  3794. #endif
  3795.     else {
  3796.     zwarnnam(name, "no such limit", NULL, 0);
  3797.     return 1;
  3798.     }
  3799.     if (res == -1)
  3800.     if (*argv) {
  3801.         zwarnnam(name, "no arguments required after -a", NULL, 0);
  3802.         return 1;
  3803.     } else {
  3804.         int t0;
  3805.  
  3806.         for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  3807.         printulimit(t0, hard);
  3808.         return 0;
  3809.     }
  3810.     if (!*argv)
  3811.     printulimit(res, hard);
  3812.     else if (strcmp(*argv, "unlimited")) {
  3813.     long t0;
  3814.  
  3815.     t0 = atol(*argv);
  3816.     switch (res) {
  3817.     case RLIMIT_FSIZE:
  3818.     case RLIMIT_CORE:
  3819.         t0 *= 512;
  3820.         break;
  3821.     case RLIMIT_DATA:
  3822.     case RLIMIT_STACK:
  3823. #ifdef RLIMIT_RSS
  3824.     case RLIMIT_RSS:
  3825. #endif
  3826. #ifdef RLIMIT_MEMLOCK
  3827.     case RLIMIT_MEMLOCK:
  3828. #endif
  3829. #ifdef RLIMIT_VMEM
  3830.     case RLIMIT_VMEM:
  3831. #endif
  3832.         t0 *= 1024;
  3833.         break;
  3834.     }
  3835.     if (hard) {
  3836.         if (t0 > limits[res].rlim_max && geteuid()) {
  3837.         zwarnnam(name, "can't raise hard limits", NULL, 0);
  3838.         return 1;
  3839.         }
  3840.         limits[res].rlim_max = t0;
  3841.     } else {
  3842.         if (t0 > limits[res].rlim_max) {
  3843.         if (geteuid()) {
  3844.             zwarnnam(name, "value exceeds hard limit", NULL, 0);
  3845.             return 1;
  3846.         }
  3847.         limits[res].rlim_max = limits[res].rlim_cur = t0;
  3848.         } else
  3849.         limits[res].rlim_cur = t0;
  3850.     }
  3851.     } else {
  3852.     if (hard) {
  3853.         if (geteuid()) {
  3854.         zwarnnam(name, "can't remove hard limits", NULL, 0);
  3855.         return 1;
  3856.         }
  3857.         limits[res].rlim_max = RLIM_INFINITY;
  3858.     } else
  3859.         limits[res].rlim_cur = limits[res].rlim_max;
  3860.     }
  3861.     return 0;
  3862. #endif
  3863. }
  3864.  
  3865. int putraw(c)            /**/
  3866. int c;
  3867. {
  3868.     putchar(c);
  3869.     return 0;
  3870. }
  3871.  
  3872. int bin_echotc(name, argv, ops, func)    /**/
  3873. char *name;
  3874. char **argv;
  3875. char *ops;
  3876. int func;
  3877. {
  3878.     char *s, buf[2048], *t, *u;
  3879.     int num, argct, t0;
  3880.  
  3881.     s = *argv++;
  3882.     if (!termok)
  3883.     return 1;
  3884.     if ((num = tgetnum(s)) != -1) {
  3885.     printf("%d\n", num);
  3886.     return 0;
  3887.     }
  3888.     if (tgetflag(s)) {
  3889.         puts("yes");
  3890.         return(0);
  3891.     }
  3892.     u = buf;
  3893.     t = tgetstr(s, &u);
  3894.     if (!t || !*t) {
  3895.     zwarnnam(name, "no such capability: %s", s, 0);
  3896.     return 1;
  3897.     }
  3898.     for (argct = 0, u = t; *u; u++)
  3899.     if (*u == '%') {
  3900.         if (u++, (*u == 'd' || *u == '2' || *u == '3' || *u == '.' ||
  3901.               *u == '+'))
  3902.         argct++;
  3903.     }
  3904.     if (arrlen(argv) != argct) {
  3905.     zwarnnam(name, (arrlen(argv) < argct) ? "not enough arguments" :
  3906.         "too many arguments", NULL, 0);
  3907.     return 1;
  3908.     }
  3909.     if (!argct)
  3910.     tputs(t, 1, putraw);
  3911.     else {
  3912.     t0 = (argv[1]) ? atoi(argv[1]) : atoi(*argv);
  3913.     tputs(tgoto(t, atoi(*argv), t0), t0, putraw);
  3914.     }
  3915.     return 0;
  3916. }
  3917.  
  3918. int bin_pwd(name, argv, ops, func)    /**/
  3919. char *name;
  3920. char **argv;
  3921. char *ops;
  3922. int func;
  3923. {
  3924.     printf("%s\n", pwd);
  3925.     return 0;
  3926. }
  3927.  
  3928. #define TEST_END 0
  3929. #define TEST_INPAR 1
  3930. #define TEST_OUTPAR 2
  3931. #define TEST_STR 3
  3932. #define TEST_AND 4
  3933. #define TEST_OR 5
  3934. #define TEST_NOT 6
  3935.  
  3936. static char **tsp;
  3937. static int *tip;
  3938.  
  3939. int bin_test(name, argv, ops, func)    /**/
  3940. char *name;
  3941. char **argv;
  3942. char *ops;
  3943. int func;
  3944. {
  3945.     char **s;
  3946.     int cnt, *arr, *ap, last_expr = 0;
  3947.     Cond c;
  3948.  
  3949.     if (func == BIN_BRACKET) {
  3950.     for (s = argv; *s; s++);
  3951.     if (s == argv || strcmp(s[-1], "]")) {
  3952.         zerrnam(name, "']' expected", NULL, 0);
  3953.         return 1;
  3954.     }
  3955.     s[-1] = NULL;
  3956.     }
  3957.     for (s = argv, cnt = 0; *s; s++, cnt++);
  3958.     ap = arr = (int *)alloc((cnt + 1) * sizeof *arr);
  3959.     for (s = argv; *s; s++, ap++)
  3960.     if (!strcmp(*s, "(")) {
  3961.         *ap = TEST_INPAR;
  3962.         last_expr = 0;
  3963.     } else if (!strcmp(*s, ")")) {
  3964.         *ap = TEST_OUTPAR;
  3965.         last_expr = 1;
  3966.     } else if (!strcmp(*s, "=") || !strcmp(*s, "!=")) {
  3967.         zerrnam(name, "argument expected", NULL, 0);
  3968.         return 1;
  3969.     } else if (s[1] && (!strcmp(s[1], "=") || !strcmp(s[1], "!=")
  3970.                 || (s[1][0] == '-' &&
  3971.                 get_cond_num(s[1]+1) > -1))) {
  3972.         if (! s[2] || (!strcmp(s[2], "(") || !strcmp(s[2], ")"))) {
  3973.         zerrnam(name, "argument expected", NULL, 0);
  3974.         return 1;
  3975.         }
  3976.         ap[0] = ap[1] = ap[2] = TEST_STR;
  3977.         ap += 2;
  3978.         s += 2;
  3979.         last_expr = 1;
  3980.     } else if (!strcmp(*s, "-a") && last_expr) {
  3981.         *ap = TEST_AND;
  3982.         last_expr = 0;
  3983.     } else if (!strcmp(*s, "-o") && last_expr) {
  3984.         *ap = TEST_OR;
  3985.         last_expr = 0;
  3986.     } else if (!strcmp(*s, "!") && !last_expr) {
  3987.         *ap = TEST_NOT;
  3988.         last_expr = 0;
  3989.     } else {
  3990.         *ap = TEST_STR;
  3991.         last_expr = 1;
  3992.         if (s[1] && strcmp(s[1], "(") && strcmp(s[1], ")") &&
  3993.         **s == '-') {
  3994.         *++ap = TEST_STR;
  3995.         ++s;
  3996.         }
  3997.     }
  3998.     *ap = TEST_END;
  3999.     tsp = argv;
  4000.     tip = arr;
  4001.     c = partest(0);
  4002.     if (*tip != TEST_END || errflag) {
  4003.     zerrnam(name, "parse error", NULL, 0);
  4004.     return 1;
  4005.     }
  4006.     return (c) ? !evalcond(c) : 1;
  4007. }
  4008.  
  4009. Cond partest(level)        /**/
  4010. int level;
  4011. {
  4012.     Cond a, b;
  4013.  
  4014.     switch (level) {
  4015.     case 0:
  4016.     a = partest(1);
  4017.     if (*tip == TEST_OR) {
  4018.         tip++, tsp++;
  4019.         b = (Cond) makecond();
  4020.         b->left = (vptr) a;
  4021.         b->right = (vptr) partest(0);
  4022.         b->type = COND_OR;
  4023.         return b;
  4024.     }
  4025.     return a;
  4026.     case 1:
  4027.     a = partest(2);
  4028.     if (*tip == TEST_AND) {
  4029.         tip++, tsp++;
  4030.         b = (Cond) makecond();
  4031.         b->left = (vptr) a;
  4032.         b->right = (vptr) partest(1);
  4033.         b->type = COND_AND;
  4034.         return b;
  4035.     }
  4036.     return a;
  4037.     case 2:
  4038.     if (*tip == TEST_NOT) {
  4039.         tip++, tsp++;
  4040.         b = (Cond) makecond();
  4041.         b->left = (vptr) partest(2);
  4042.         b->type = COND_NOT;
  4043.         return b;
  4044.     }
  4045.     case 3:
  4046.     if (*tip == TEST_INPAR) {
  4047.         tip++, tsp++;
  4048.         b = partest(0);
  4049.         if (*tip != TEST_OUTPAR) {
  4050.         zerrnam("test", "parse error", NULL, 0);
  4051.         return NULL;
  4052.         }
  4053.         tip++, tsp++;
  4054.         return b;
  4055.     }
  4056.     if (tip[0] != TEST_STR) {
  4057.         zerrnam("test", "parse error", NULL, 0);
  4058.         return NULL;
  4059.     } else if (tip[1] != TEST_STR) {
  4060.         b = (Cond) makecond();
  4061.         if (!strcmp(*tsp, "-t")) {
  4062.         b->left = (vptr) dupstring("1");
  4063.         b->type = 't';
  4064.         } else {
  4065.         b->left = (vptr) tsp[0];
  4066.         b->type = 'n';
  4067.         }
  4068.         tip++, tsp++;
  4069.         return b;
  4070.     } else if (tip[2] != TEST_STR) {
  4071.         b = par_cond_double(tsp[0], tsp[1]);
  4072.         tip += 2, tsp += 2;
  4073.         return b;
  4074.     } else {
  4075.         b = par_cond_triple(tsp[0], tsp[1], tsp[2]);
  4076.         tip += 3, tsp += 3;
  4077.         return b;
  4078.     }
  4079.     }
  4080.     return NULL;
  4081. }
  4082.  
  4083. int get_xcompctl(name, av, cc, isdef)    /**/
  4084. char *name;
  4085. char ***av;
  4086. Compctl cc;
  4087. int isdef;
  4088. {
  4089.     char **argv = *av, *t, *tt, sav;
  4090.     int n, l = 0, ready = 0, dummy;
  4091.     Compcond m, c, o;
  4092.     Compctl *next = &(cc->ext);
  4093.  
  4094.     while (!ready) {
  4095.     o = m = c = (Compcond) zcalloc(sizeof(*c));
  4096.     for (t = *argv; *t;) {
  4097.         while (*t == ' ')
  4098.         t++;
  4099.         switch (*t) {
  4100.         case 's':
  4101.         c->type = CCT_CURSUF;
  4102.         break;
  4103.         case 'S':
  4104.         c->type = CCT_CURPRE;
  4105.         break;
  4106.         case 'p':
  4107.         c->type = CCT_POS;
  4108.         break;
  4109.         case 'c':
  4110.         c->type = CCT_CURSTR;
  4111.         break;
  4112.         case 'C':
  4113.         c->type = CCT_CURPAT;
  4114.         break;
  4115.         case 'w':
  4116.         c->type = CCT_WORDSTR;
  4117.         break;
  4118.         case 'W':
  4119.         c->type = CCT_WORDPAT;
  4120.         break;
  4121.         case 'n':
  4122.         c->type = CCT_CURSUB;
  4123.         break;
  4124.         case 'N':
  4125.         c->type = CCT_CURSUBC;
  4126.         break;
  4127.         case 'm':
  4128.         c->type = CCT_NUMWORDS;
  4129.         break;
  4130.         case 'r':
  4131.         c->type = CCT_RANGESTR;
  4132.         break;
  4133.         case 'R':
  4134.         c->type = CCT_RANGEPAT;
  4135.         break;
  4136.         default:
  4137.         t[1] = '\0';
  4138.         zerrnam(name, "unknown condition code: %s", t, 0);
  4139.         freecompctl(cc);
  4140.         zfree(m, sizeof(struct compcond));
  4141.         return 1;
  4142.         }
  4143.         if (t[1] != '[') {
  4144.         t[1] = '\0';
  4145.         zerrnam(name, "expected condition after condition code: %s", t, 0);
  4146.         freecompctl(cc);
  4147.         zfree(m, sizeof(struct compcond));
  4148.         return 1;
  4149.         }
  4150.         t++;
  4151.         for (n = 0, tt = t; *tt == '['; n++) {
  4152.         for (l = 1, tt++; *tt && l; tt++)
  4153.             if (*tt == '\\' && tt[1])
  4154.             tt++;
  4155.             else if (*tt == '[')
  4156.             l++;
  4157.             else if (*tt == ']')
  4158.             l--;
  4159.             else if (l == 1 && *tt == ',')
  4160.             *tt = '\201';
  4161.         if (tt[-1] == ']')
  4162.             tt[-1] = '\200';
  4163.         }
  4164.  
  4165.         if (l) {
  4166.         t[1] = '\0';
  4167.         zerrnam(name, "error after condition code: %s", t, 0);
  4168.         freecompctl(cc);
  4169.         zfree(m, sizeof(struct compcond));
  4170.         return 1;
  4171.         }
  4172.         c->n = n;
  4173.  
  4174.         if (c->type == CCT_POS ||
  4175.         c->type == CCT_NUMWORDS) {
  4176.         c->u.r.a = (int *)zcalloc(n * sizeof(int));
  4177.         c->u.r.b = (int *)zcalloc(n * sizeof(int));
  4178.         } else if (c->type == CCT_CURSUF ||
  4179.                c->type == CCT_CURPRE)
  4180.         c->u.s.s = (char **)zcalloc(n * sizeof(char *));
  4181.  
  4182.         else if (c->type == CCT_RANGESTR ||
  4183.              c->type == CCT_RANGEPAT) {
  4184.         c->u.l.a = (char **)zcalloc(n * sizeof(char *));
  4185.         c->u.l.b = (char **)zcalloc(n * sizeof(char *));
  4186.         } else {
  4187.         c->u.s.p = (int *)zcalloc(n * sizeof(int));
  4188.         c->u.s.s = (char **)zcalloc(n * sizeof(char *));
  4189.         }
  4190.         for (l = 0; *t == '['; l++, t++) {
  4191.         for (t++; *t && *t == ' '; t++);
  4192.         tt = t;
  4193.         if (c->type == CCT_POS ||
  4194.             c->type == CCT_NUMWORDS) {
  4195.             for (; *t && *t != '\201' && *t != '\200'; t++);
  4196.             if (!(sav = *t)) {
  4197.             zerrnam(name, "error in condition", NULL, 0);
  4198.             freecompctl(cc);
  4199.             freecompcond(m);
  4200.             return 1;
  4201.             }
  4202.             *t = '\0';
  4203.             c->u.r.a[l] = atoi(tt);
  4204.             if (sav == '\200')
  4205.             c->u.r.b[l] = c->u.r.a[l];
  4206.             else {
  4207.             tt = ++t;
  4208.             for (; *t && *t != '\200'; t++);
  4209.             if (!*t) {
  4210.                 zerrnam(name, "error in condition", NULL, 0);
  4211.                 freecompctl(cc);
  4212.                 freecompcond(m);
  4213.                 return 1;
  4214.             }
  4215.             *t = '\0';
  4216.             c->u.r.b[l] = atoi(tt);
  4217.             }
  4218.         } else if (c->type == CCT_CURSUF ||
  4219.                c->type == CCT_CURPRE) {
  4220.             for (; *t && *t != '\200'; t++)
  4221.             if (*t == '\201')
  4222.                 *t = ',';
  4223.             if (!*t) {
  4224.             zerrnam(name, "error in condition", NULL, 0);
  4225.             freecompctl(cc);
  4226.             freecompcond(m);
  4227.             return 1;
  4228.             }
  4229.             *t = '\0';
  4230.             c->u.s.s[l] = ztrdup(tt);
  4231.         } else if (c->type == CCT_RANGESTR ||
  4232.                c->type == CCT_RANGEPAT) {
  4233.             for (; *t && *t != '\201'; t++);
  4234.             if (!*t) {
  4235.             zerrnam(name, "error in condition", NULL, 0);
  4236.             freecompctl(cc);
  4237.             freecompcond(m);
  4238.             return 1;
  4239.             }
  4240.             *t = '\0';
  4241.             c->u.l.a[l] = ztrdup(tt);
  4242.             tt = ++t;
  4243.             for (; *t && *t != '\200'; t++)
  4244.             if (*t == '\201')
  4245.                 *t = ',';
  4246.             if (!*t) {
  4247.             zerrnam(name, "error in condition", NULL, 0);
  4248.             freecompctl(cc);
  4249.             freecompcond(m);
  4250.             return 1;
  4251.             }
  4252.             *t = '\0';
  4253.             c->u.l.b[l] = ztrdup(tt);
  4254.         } else {
  4255.             for (; *t && *t != '\201'; t++);
  4256.             if (!*t) {
  4257.             zerrnam(name, "error in condition", NULL, 0);
  4258.             freecompctl(cc);
  4259.             freecompcond(m);
  4260.             return 1;
  4261.             }
  4262.             *t = '\0';
  4263.             c->u.s.p[l] = atoi(tt);
  4264.             tt = ++t;
  4265.             for (; *t && *t != '\200'; t++)
  4266.             if (*t == '\201')
  4267.                 *t = ',';
  4268.             if (!*t) {
  4269.             zerrnam(name, "error in condition", NULL, 0);
  4270.             freecompctl(cc);
  4271.             freecompcond(m);
  4272.             return 1;
  4273.             }
  4274.             *t = '\0';
  4275.             c->u.s.s[l] = ztrdup(tt);
  4276.         }
  4277.         }
  4278.         while (*t == ' ')
  4279.         t++;
  4280.         if (*t == ',') {
  4281.         o->or = c = (Compcond) zcalloc(sizeof(*c));
  4282.         o = c;
  4283.         t++;
  4284.         } else if (*t) {
  4285.         c->and = (Compcond) zcalloc(sizeof(*c));
  4286.         c = c->and;
  4287.         }
  4288.     }
  4289.     *next = (Compctl) zcalloc(sizeof(*cc));
  4290.     (*next)->cond = m;
  4291.     argv++;
  4292.     if (get_compctl(name, &argv, *next, &dummy, 0, isdef)) {
  4293.         freecompctl(cc);
  4294.         return 1;
  4295.     }
  4296.     if ((!argv || !*argv) &&
  4297.         (cc == &cc_default || cc == &cc_compos))
  4298.         ready = 1;
  4299.     else {
  4300.         if (!argv || !*argv || **argv != '-' ||
  4301.         ((!argv[0][1] || argv[0][1] == '+') && !argv[1])) {
  4302.         zerrnam(name, "missing command names", NULL, 0);
  4303.         freecompctl(cc);
  4304.         return 1;
  4305.         }
  4306.         if (!strcmp(*argv, "--"))
  4307.         ready = 1;
  4308.         else if (!strcmp(*argv,"-+") && argv[1] && !strcmp(argv[1],"--")) {
  4309.         ready = 1;
  4310.         argv++;
  4311.         }
  4312.         argv++;
  4313.         next = &((*next)->next);
  4314.     }
  4315.     }
  4316.     *av = argv - 1;
  4317.     return 0;
  4318. }
  4319.  
  4320. int get_compctl(name, av, cc, t, first, isdef)    /**/
  4321. char *name;
  4322. char ***av;
  4323. Compctl cc;
  4324. int *t;
  4325. int first;
  4326. int isdef;
  4327. {
  4328.     unsigned long flags = 0;
  4329.     Compctl cc2 = NULL;
  4330.     char **argv = *av, *usrkeys = NULL, *compglob = NULL, *str = NULL;
  4331.     char *funcn = NULL, *explain = NULL, *compprefix = NULL, *suffix = NULL;
  4332.     char *subcmd = NULL, *hpat = NULL;
  4333.     int ready = 0, hnum = 0, hx = 0;
  4334.  
  4335.     for (; !ready && *argv && **argv == '-';) {
  4336.     if (**argv == '-' && !(*argv)[1])
  4337.         (*argv)[1] = '+';
  4338.     while (!ready && *++(*argv))
  4339.         switch (**argv) {
  4340.         case 'f':
  4341.         flags |= CC_FILES;
  4342.         break;
  4343.         case 'c':
  4344.         flags |= CC_COMMPATH;
  4345.         break;
  4346.         case 'o':
  4347.         flags |= CC_OPTIONS;
  4348.         break;
  4349.         case 'v':
  4350.         flags |= CC_VARS;
  4351.         break;
  4352.         case 'b':
  4353.         flags |= CC_BINDINGS;
  4354.         break;
  4355.         case 'A':
  4356.         flags |= CC_ARRAYS;
  4357.         break;
  4358.         case 'I':
  4359.         flags |= CC_INTVARS;
  4360.         break;
  4361.         case 'F':
  4362.         flags |= CC_FUNCS;
  4363.         break;
  4364.         case 'p':
  4365.         flags |= CC_PARAMS;
  4366.         break;
  4367.         case 'E':
  4368.         flags |= CC_ENVVARS;
  4369.         break;
  4370.         case 'j':
  4371.         flags |= CC_JOBS;
  4372.         break;
  4373.         case 'r':
  4374.         flags |= CC_RUNNING;
  4375.         break;
  4376.         case 'z':
  4377.         flags |= CC_STOPPED;
  4378.         break;
  4379.         case 'B':
  4380.         flags |= CC_BUILTINS;
  4381.         break;
  4382.         case 'a':
  4383.         flags |= CC_ALREG | CC_ALGLOB;
  4384.         break;
  4385.         case 'R':
  4386.         flags |= CC_ALREG;
  4387.         break;
  4388.         case 'G':
  4389.         flags |= CC_ALGLOB;
  4390.         break;
  4391.         case 'u':
  4392.         flags |= CC_USERS;
  4393.         break;
  4394.         case 'd':
  4395.         flags |= CC_DISCMDS;
  4396.         break;
  4397.         case 'e':
  4398.         flags |= CC_EXCMDS;
  4399.         break;
  4400.         case 'N':
  4401.         flags |= CC_SCALARS;
  4402.         break;
  4403.         case 'O':
  4404.         flags |= CC_READONLYS;
  4405.         break;
  4406.         case 'Z':
  4407.         flags |= CC_SPECIALS;
  4408.         break;
  4409.         case 'q':
  4410.         flags |= CC_REMOVE;
  4411.         break;
  4412.         case 'U':
  4413.         flags |= CC_DELETE;
  4414.         break;
  4415.         case 'k':
  4416.         if ((*argv)[1]) {
  4417.             usrkeys = (*argv) + 1;
  4418.             *argv = "" - 1;
  4419.         } else if (!argv[1]) {
  4420.             zerrnam(name, "variable name expected after -k", NULL, 0);
  4421.             return 1;
  4422.         } else {
  4423.             usrkeys = *++argv;
  4424.             *argv = "" - 1;
  4425.         }
  4426.         break;
  4427.         case 'K':
  4428.         if ((*argv)[1]) {
  4429.             funcn = (*argv) + 1;
  4430.             *argv = "" - 1;
  4431.         } else if (!argv[1]) {
  4432.             zerrnam(name, "function name expected after -K", NULL, 0);
  4433.             return 1;
  4434.         } else {
  4435.             funcn = *++argv;
  4436.             *argv = "" - 1;
  4437.         }
  4438.         break;
  4439.         case 'X':
  4440.         if ((*argv)[1]) {
  4441.             explain = (*argv) + 1;
  4442.             *argv = "" - 1;
  4443.         } else if (!argv[1]) {
  4444.             zerrnam(name, "string expected after -X", NULL, 0);
  4445.             return 1;
  4446.         } else {
  4447.             explain = *++argv;
  4448.             *argv = "" - 1;
  4449.         }
  4450.         break;
  4451.         case 'P':
  4452.         if (hx) {
  4453.             zerrnam(name, "prefix definition in xor'd completion not allowed",
  4454.                 NULL, 0);
  4455.             return 1;
  4456.         }
  4457.         if ((*argv)[1]) {
  4458.             compprefix = (*argv) + 1;
  4459.             *argv = "" - 1;
  4460.         } else if (!argv[1]) {
  4461.             zerrnam(name, "string expected after -P", NULL, 0);
  4462.             return 1;
  4463.         } else {
  4464.             compprefix = *++argv;
  4465.             *argv = "" - 1;
  4466.         }
  4467.         break;
  4468.         case 'S':
  4469.         if (hx) {
  4470.             zerrnam(name, "suffix definition in xor'd completion not allowed",
  4471.                 NULL, 0);
  4472.             return 1;
  4473.         }
  4474.         if ((*argv)[1]) {
  4475.             suffix = (*argv) + 1;
  4476.             *argv = "" - 1;
  4477.         } else if (!argv[1]) {
  4478.             zerrnam(name, "string expected after -S", NULL, 0);
  4479.             return 1;
  4480.         } else {
  4481.             suffix = *++argv;
  4482.             *argv = "" - 1;
  4483.         }
  4484.         break;
  4485.         case 'g':
  4486.         if ((*argv)[1]) {
  4487.             compglob = (*argv) + 1;
  4488.             *argv = "" - 1;
  4489.         } else if (!argv[1]) {
  4490.             zerrnam(name, "glob pattern expected after -g", NULL, 0);
  4491.             return 1;
  4492.         } else {
  4493.             compglob = *++argv;
  4494.             *argv = "" - 1;
  4495.         }
  4496.         break;
  4497.         case 's':
  4498.         if ((*argv)[1]) {
  4499.             str = (*argv) + 1;
  4500.             *argv = "" - 1;
  4501.         } else if (!argv[1]) {
  4502.             zerrnam(name, "command string expected after -s", NULL, 0);
  4503.             return 1;
  4504.         } else {
  4505.             str = *++argv;
  4506.             *argv = "" - 1;
  4507.         }
  4508.         break;
  4509.         case 'l':
  4510.         if ((*argv)[1]) {
  4511.             subcmd = (*argv) + 1;
  4512.             *argv = "" - 1;
  4513.         } else if (!argv[1]) {
  4514.             zerrnam(name, "command name expected after -s", NULL, 0);
  4515.             return 1;
  4516.         } else {
  4517.             subcmd = *++argv;
  4518.             *argv = "" - 1;
  4519.         }
  4520.         break;
  4521.         case 'H':
  4522.         if ((*argv)[1])
  4523.             hnum = atoi((*argv) + 1);
  4524.         else if (argv[1])
  4525.             hnum = atoi(*++argv);
  4526.         else {
  4527.             zerrnam(name, "number expected after -H", NULL, 0);
  4528.             return 1;
  4529.         }
  4530.         if (!argv[1]) {
  4531.             zerrnam(name, "missing pattern after -H", NULL, 0);
  4532.             return 1;
  4533.         }
  4534.         hpat = *++argv;
  4535.         if (hnum < 1)
  4536.             hnum = 0;
  4537.         if (*hpat == '*' && !hpat[1])
  4538.             hpat = "";
  4539.         *argv = "" - 1;
  4540.         break;
  4541.         case 'C':
  4542.         if (first && !hx) {
  4543.             Compctl c2;
  4544.  
  4545.             cc = cc2 = &cc_compos;
  4546.  
  4547.             c2 = (Compctl) zcalloc(sizeof *cc2);
  4548.             c2->xor = cc2->xor;
  4549.             c2->ext = cc2->ext;
  4550.             c2->refc = 1;
  4551.  
  4552.             freecompctl(c2);
  4553.  
  4554.             cc2->ext = cc2->xor = NULL;
  4555.         }
  4556.         else {
  4557.             zerrnam(name, "misplaced command completion (-C) flag", NULL, 0);
  4558.             return 1;
  4559.         }
  4560.         break;
  4561.         case 'D':
  4562.         if (first && !hx) {
  4563.             Compctl c2;
  4564.  
  4565.             cc = cc2 = &cc_default, isdef = 1;
  4566.             c2 = (Compctl) zcalloc(sizeof *cc2);
  4567.             c2->xor = cc2->xor;
  4568.             c2->ext = cc2->ext;
  4569.             c2->refc = 1;
  4570.  
  4571.             freecompctl(c2);
  4572.  
  4573.             cc2->ext = cc2->xor = NULL;
  4574.         }
  4575.         else {
  4576.             zerrnam(name, "misplaced default completion (-D) flag", NULL, 0);
  4577.             return 1;
  4578.         }
  4579.         break;
  4580.         case 'x':
  4581.         if (!argv[1]) {
  4582.             zerrnam(name, "condition expected after -x", NULL, 0);
  4583.             return 1;
  4584.         }
  4585.         if (first) {
  4586.             argv++;
  4587.             if (get_xcompctl(name, &argv, cc, isdef))
  4588.             return 2;
  4589.             ready = 2;
  4590.         } else {
  4591.             zerrnam(name, "recursive extended completion not allowed",
  4592.                 NULL, 0);
  4593.             return 1;
  4594.         }
  4595.         break;
  4596.         default:
  4597.         if (!first && (**argv == '-' || **argv == '+'))
  4598.             (*argv)--, argv--, ready = 1;
  4599.         else {
  4600.             zerrnam(name, "bad option: %c", NULL, **argv);
  4601.             return 1;
  4602.         }
  4603.         }
  4604.  
  4605.     if (*++argv && (!ready || ready == 2) && **argv == '+' && !argv[0][1]) {
  4606.         hx = 1;
  4607.         ready = 0;
  4608.  
  4609.         if (subcmd &&
  4610.         (usrkeys || compglob || str || funcn || explain || compprefix ||
  4611.          suffix || hpat || flags)) {
  4612.         zerrnam(name, "illegal combination of options", NULL, 0);
  4613.         return 1;
  4614.         }
  4615.         cc->mask = flags;
  4616.         zsfree(cc->keyvar);
  4617.         zsfree(cc->glob);
  4618.         zsfree(cc->str);
  4619.         zsfree(cc->func);
  4620.         zsfree(cc->explain);
  4621.         zsfree(cc->prefix);
  4622.         zsfree(cc->suffix);
  4623.         zsfree(cc->subcmd);
  4624.         zsfree(cc->hpat);
  4625.  
  4626.         cc->mask = flags;
  4627.         cc->keyvar = ztrdup(usrkeys);
  4628.         cc->glob = ztrdup(compglob);
  4629.         cc->str = ztrdup(str);
  4630.         cc->func = ztrdup(funcn);
  4631.         cc->explain = ztrdup(explain);
  4632.         cc->prefix = ztrdup(compprefix);
  4633.         cc->suffix = ztrdup(suffix);
  4634.         cc->subcmd = ztrdup(subcmd);
  4635.         cc->hpat = ztrdup(hpat);
  4636.         cc->hnum = hnum;
  4637.  
  4638.         if (!*++argv || **argv != '-' ||
  4639.         (**argv == '-' && (!argv[0][1] ||
  4640.                    (argv[0][1] == '-' && !argv[0][2])))) {
  4641.         if (isdef) {
  4642.             zerrnam(name, "recursive xor'd default completions not allowed",
  4643.                 NULL, 0);
  4644.             return 1;
  4645.         }
  4646.         cc->xor = &cc_default;
  4647.         if (!*argv || **argv == '-') {
  4648.             if (*argv)
  4649.             (*argv)--;
  4650.             argv--;
  4651.             ready = 1;
  4652.         }
  4653.         } else {
  4654.         cc->xor = (Compctl) zcalloc(sizeof(*cc));
  4655.         cc = cc->xor;
  4656.         flags = 0;
  4657.         usrkeys = NULL;
  4658.         compglob = NULL;
  4659.         str = NULL;
  4660.         funcn = NULL;
  4661.         explain = NULL;
  4662.         compprefix = NULL;
  4663.         suffix = NULL;
  4664.         subcmd = NULL;
  4665.         hpat = NULL;
  4666.         hnum = 0;
  4667.         }
  4668.     }
  4669.     }
  4670.  
  4671.     if (subcmd &&
  4672.     (usrkeys || compglob || str || funcn || explain || compprefix || suffix ||
  4673.      hpat || flags)) {
  4674.     zerrnam(name, "illegal combination of options", NULL, 0);
  4675.     return 1;
  4676.     }
  4677.     if (cc2)
  4678.     *t = 1;
  4679.  
  4680.     cc->mask = flags;
  4681.     zsfree(cc->keyvar);
  4682.     zsfree(cc->glob);
  4683.     zsfree(cc->str);
  4684.     zsfree(cc->func);
  4685.     zsfree(cc->explain);
  4686.     zsfree(cc->prefix);
  4687.     zsfree(cc->suffix);
  4688.     zsfree(cc->subcmd);
  4689.     zsfree(cc->hpat);
  4690.  
  4691.     cc->mask = flags;
  4692.     cc->keyvar = ztrdup(usrkeys);
  4693.     cc->glob = ztrdup(compglob);
  4694.     cc->str = ztrdup(str);
  4695.     cc->func = ztrdup(funcn);
  4696.     cc->explain = ztrdup(explain);
  4697.     cc->prefix = ztrdup(compprefix);
  4698.     cc->suffix = ztrdup(suffix);
  4699.     cc->subcmd = ztrdup(subcmd);
  4700.     cc->hpat = ztrdup(hpat);
  4701.     cc->hnum = hnum;
  4702.     *av = argv;
  4703.  
  4704.     return 0;
  4705. }
  4706.  
  4707. int bin_compctl(name, argv, ops, func)    /**/
  4708. char *name;
  4709. char **argv;
  4710. char *ops;
  4711. int func;
  4712. {
  4713.     Compctl cc = NULL;
  4714.     int t = 0, t2;
  4715.     unsigned long flags = 0;
  4716.  
  4717.     if (*argv) {
  4718.     cc = (Compctl) zcalloc(sizeof(*cc));
  4719.  
  4720.     if ((t2 = get_compctl(name, &argv, cc, &t, 1, 0))) {
  4721.         if (t2 == 1)
  4722.         freecompctl(cc);
  4723.         return 1;
  4724.     }
  4725.     if (*argv)
  4726.         compctl_process_cc(argv, cc);
  4727.  
  4728.     flags = cc->mask;
  4729.  
  4730.     if (!*argv)
  4731.         freecompctl(cc);
  4732.     }
  4733.     if (!*argv && !t) {
  4734.     showflag = flags;
  4735.     listhtable(compctltab, (HFunc) printcompctlp);
  4736.     printcompctl("COMMAND", &cc_compos);
  4737.     printcompctl("DEFAULT", &cc_default);
  4738.     }
  4739.     return 0;
  4740. }
  4741.  
  4742. void printif(str, c)    /**/
  4743. char *str;
  4744. int c;
  4745. {
  4746.     if (str)
  4747.     printf("-%c \"%s\" ", c, str);
  4748. }
  4749.  
  4750. void printcompctlp(s, ccp)    /**/
  4751. char *s;
  4752. Compctlp ccp;
  4753. {
  4754.     printcompctl(s, ccp->cc);
  4755. }
  4756.  
  4757. void printcompctl(s, cc)    /**/
  4758. char *s;
  4759. Compctl cc;
  4760. {
  4761.     char *css = "fcqovbAIFpEjrzBRGudeNOZU";
  4762.     char *mss = " pcCwWsSnNmrR";
  4763.     unsigned long t = 0x7fffffff;
  4764.  
  4765.     if (cc->mask & showflag) {
  4766.     if (s)
  4767.         puts(s);
  4768.     } else if (!showflag) {
  4769.     unsigned long flags = cc->mask;
  4770.  
  4771.     if (s)
  4772.         printf("%s ", s);
  4773.     if (flags & t) {
  4774.         putchar('-');
  4775.         if ((flags & (CC_ALREG | CC_ALGLOB)) == (CC_ALREG | CC_ALGLOB))
  4776.         putchar('a'), flags &= ~(CC_ALREG | CC_ALGLOB);
  4777.         while (*css) {
  4778.         if ((flags & 1) && (t & 1))
  4779.             putchar(*css);
  4780.         css++;
  4781.         flags >>= 1;
  4782.         t >>= 1;
  4783.         }
  4784.         putchar(' ');
  4785.     }
  4786.     flags = cc->mask;
  4787.     if (cc->keyvar)
  4788.         printf(*cc->keyvar == '(' ? "-k \"%s\" " : "-k %s ", cc->keyvar);
  4789.     printif(cc->func, 'K');
  4790.     printif(cc->explain, 'X');
  4791.     printif(cc->prefix, 'P');
  4792.     printif(cc->suffix, 'S');
  4793.     printif(cc->glob, 'g');
  4794.     printif(cc->str, 's');
  4795.     printif(cc->subcmd, 'l');
  4796.     if (cc->hpat)
  4797.         printf("-H %d \"%s\" ", cc->hnum, cc->hpat);
  4798.     if (cc->ext) {
  4799.         Compcond c, o;
  4800.         int i;
  4801.  
  4802.         cc = cc->ext;
  4803.         printf("-x ");
  4804.  
  4805.         while (cc) {
  4806.         c = cc->cond;
  4807.  
  4808.         putchar('\"');
  4809.         for (c = cc->cond; c;) {
  4810.             o = c->or;
  4811.             while (c) {
  4812.             putchar(mss[c->type]);
  4813.  
  4814.             for (i = 0; i < c->n; i++)
  4815.                 switch(c->type) {
  4816.                   case CCT_POS:
  4817.                   case CCT_NUMWORDS:
  4818.                 printf("[%d,%d]", c->u.r.a[i], c->u.r.b[i]);
  4819.                 break;
  4820.                   case CCT_CURSUF:
  4821.                   case CCT_CURPRE:
  4822.                 printf("[%s]", c->u.s.s[i]);
  4823.                 break;
  4824.                   case CCT_RANGESTR:
  4825.                   case CCT_RANGEPAT:
  4826.                 printf("[%s,%s]", c->u.l.a[i], c->u.l.b[i]);
  4827.                 break;
  4828.                   default:
  4829.                 printf("[%d,%s]", c->u.s.p[i], c->u.s.s[i]);
  4830.                 }
  4831.             if ((c = c->and))
  4832.                 putchar(' ');
  4833.             }
  4834.             if ((c = o))
  4835.             printf(" , ");
  4836.         }
  4837.         printf("\" ");
  4838.         c = cc->cond;
  4839.         cc->cond = NULL;
  4840.         printcompctl(NULL, cc);
  4841.         cc->cond = c;
  4842.         if ((cc = (Compctl) (cc->next)))
  4843.             printf("- ");
  4844.         }
  4845.     }
  4846.     if (cc && cc->xor) {
  4847.         printf("+ ");
  4848.         if (cc->xor != &cc_default)
  4849.         printcompctl(NULL, cc->xor);
  4850.     }
  4851.     if (s)
  4852.         putchar('\n');
  4853.     }
  4854. }
  4855.  
  4856. void compctl_process(s, mask, uk, gl, st, fu, ex, pr, su, sc, hp, hn)    /**/
  4857. char **s;
  4858. int mask;
  4859. char *uk;
  4860. char *gl;
  4861. char *st;
  4862. char *fu;
  4863. char *ex;
  4864. char *pr;
  4865. char *su;
  4866. char *sc;
  4867. char *hp;
  4868. int hn;
  4869. {
  4870.     Compctl cc;
  4871.  
  4872.     cc = (Compctl) zcalloc(sizeof *cc);
  4873.     cc->mask = mask;
  4874.     cc->keyvar = ztrdup(uk);
  4875.     cc->glob = ztrdup(gl);
  4876.     cc->str = ztrdup(st);
  4877.     cc->func = ztrdup(fu);
  4878.     cc->explain = ztrdup(ex);
  4879.     cc->prefix = ztrdup(pr);
  4880.     cc->suffix = ztrdup(su);
  4881.     cc->subcmd = ztrdup(sc);
  4882.     cc->hpat = ztrdup(hp);
  4883.     cc->hnum = hn;
  4884.  
  4885.     compctl_process_cc(s, cc);
  4886. }
  4887.  
  4888. void compctl_process_cc(s, cc)    /**/
  4889. char **s;
  4890. Compctl cc;
  4891. {
  4892.     Compctlp ccp;
  4893.  
  4894.     cc->refc = 0;
  4895.     for (; *s; s++) {
  4896.     cc->refc++;
  4897.     ccp = (Compctlp) zalloc(sizeof *ccp);
  4898.     ccp->cc = cc;
  4899.     addhnode(ztrdup(*s), ccp, compctltab, freecompctlp);
  4900.     }
  4901. }
  4902.  
  4903. int bin_ttyctl(name, argv, ops, func)    /**/
  4904. char *name;
  4905. char **argv;
  4906. char *ops;
  4907. int func;
  4908. {
  4909.     if (!ops['@'])
  4910.     printf("tty is %sfrozen\n", ttyfrozen ? "" : "not ");
  4911.     else if (ops['f'])
  4912.     ttyfrozen = 1;
  4913.     else
  4914.     ttyfrozen = 0;
  4915.     return 0;
  4916. }
  4917.