home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / z / zsh220.zip / zsh2.2 / src / builtin.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  62KB  |  2,970 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 <sys/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.  
  63. struct bincmd {
  64.     char *name;
  65.     int (*handlerfunc) DCLPROTO((char *,char **,char *,int));
  66.     int minargs;        /* min # of args */
  67.     int maxargs;        /* max # of args, or -1 for no limit */
  68.     int flags;            /* BINF_flags (see above) */
  69.     int funcid;            /* xbins (see above) for overloaded handlerfuncs */
  70.     char *optstr;        /* string of legal options */
  71.     char *defopts;        /* options set by default for overloaded handlerfuncs */
  72.     };
  73.  
  74. /* structure for foo=bar assignments */
  75.  
  76. struct asgment {
  77.     struct asgment *next;
  78.     char *name,*value;
  79.     };
  80.  
  81. static char *auxdata;
  82. static int auxlen;
  83. static int showflag = 0,showflag2 = 0;
  84.  
  85. struct bincmd builtins[] = {
  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,0,NULL,NULL,
  89.     "alias",bin_alias,0,-1,0,0,"ga",NULL,
  90.     "autoload",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tx","fu",
  91.     "bg",bin_fg,0,-1,0,BIN_BG,NULL,NULL,
  92.     "bindkey",bin_bindkey,0,-1,0,0,"asvemdrl",NULL,
  93.     "break",bin_break,0,1,0,BIN_BREAK,NULL,NULL,
  94.     "builtin",NULL,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,1,-1,0,0,NULL,NULL,
  103.     "disown",bin_fg,1,-1,0,BIN_DISOWN,NULL,NULL,
  104.     "echo",bin_print,0,-1,BINF_PRINTOPTS|BINF_ECHOPTS,BIN_PRINT,"n","-",
  105.     "echotc",bin_echotc,1,-1,0,0,NULL,NULL,
  106.     "enable",bin_enable,1,-1,0,0,NULL,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,0,"LRZfilrtu","x",
  110.     "false",bin_let,0,0,0,0,NULL,NULL,
  111.     "fc",bin_fc,0,-1,BINF_FCOPTS,BIN_FC,"nlreRWAdD",NULL,
  112.     "fg",bin_fg,0,-1,0,BIN_FG,NULL,NULL,
  113.     "functions",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tu","f",
  114.     "getln",bin_read,0,-1,0,0,NULL,"zr",
  115.     "getopts",bin_getopts,2,-1,0,0,NULL,NULL,
  116.     "hash",bin_hash,2,2,0,0,"r",NULL,
  117.     "history",bin_fc,0,-1,0,BIN_FC,"nrdD","l",
  118.     "integer",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZlrtux","i",
  119.     "jobs",bin_fg,0,-1,0,BIN_JOBS,"lpZ",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,"LRZfilrtux",NULL,
  124.     "log",bin_log,0,0,0,0,NULL,NULL,
  125.     "logout",bin_break,0,1,0,BIN_LOGOUT,NULL,NULL,
  126.     "popd",bin_cd,0,2,0,BIN_POPD,NULL,NULL,
  127.     "print",bin_print,0,-1,BINF_PRINTOPTS,BIN_PRINT,"RDPnrslzNu0123456789p-",NULL,
  128.     "pushd",bin_cd,0,2,0,BIN_PUSHD,NULL,NULL,
  129.     "pushln",bin_print,0,-1,BINF_PRINTOPTS,BIN_PRINT,NULL,"-nz",
  130.     "pwd",bin_pwd,0,0,0,0,NULL,NULL,
  131.     "r",bin_fc,0,-1,BINF_R,BIN_FC,"nrl",NULL,
  132.     "read",bin_read,0,-1,0,0,"rzu0123456789p",NULL,
  133.     "readonly",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfiltux","r",
  134.     "rehash",bin_rehash,0,0,0,0,"f",NULL,
  135.     "return",bin_break,0,1,0,BIN_RETURN,NULL,NULL,
  136.     "sched",bin_sched,0,-1,0,0,NULL,NULL,
  137.     "set",bin_set,0,-1,BINF_SETOPTS|BINF_PLUSOPTS,0,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZaefghijklnosuvwxy",NULL,
  138.     "setopt",bin_setopt,0,-1,BINF_PLUSOPTS,0,"0123456789BCDEFGHIJKLMNOPQRSTUVWXYZaefghijklmnosuvwxy",NULL,
  139.     "shift",bin_break,0,1,0,BIN_SHIFT,NULL,NULL,
  140.     "source",bin_dot,1,-1,0,0,NULL,NULL,
  141.     "suspend",bin_suspend,0,0,0,0,"f",NULL,
  142.     "test",bin_test,0,-1,0,BIN_TEST,NULL,NULL,
  143.     "ttyctl",bin_ttyctl,0,0,0,0,"fu",NULL,
  144.     "times",bin_times,0,0,0,0,NULL,NULL,
  145.     "trap",bin_trap,0,-1,0,0,NULL,NULL,
  146.     "true",bin_colon,0,0,0,0,NULL,NULL,
  147.     "type",bin_whence,0,-1,0,0,"pfa","v",
  148.     "typeset",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
  149.     "ulimit",bin_ulimit,0,1,0,0,"HSacdfmnt",NULL,
  150.     "umask",bin_umask,0,1,0,0,NULL,NULL,
  151.     "unalias",bin_unalias,1,-1,0,0,NULL,NULL,
  152.     "unfunction",bin_unhash,1,-1,0,0,NULL,NULL,
  153.     "unhash",bin_unhash,1,-1,0,0,NULL,NULL,
  154.     "unlimit",bin_unlimit,0,-1,0,0,"h",NULL,
  155.     "unset",bin_unset,1,-1,0,0,NULL,NULL,
  156.     "unsetopt",bin_setopt,0,-1,BINF_PLUSOPTS,1,"0123456789BCDEFGHIJKLMNOPQRSTUWXYZabefghijklmnosuvwxy",NULL,
  157.     "vared",bin_vared,1,1,0,0,NULL,NULL,
  158.     "wait",bin_fg,0,-1,0,BIN_WAIT,NULL,NULL,
  159.     "whence",bin_whence,0,-1,0,0,"pvcfa",NULL,
  160.     "which",bin_whence,0,-1,0,0,"pa","c",
  161.     NULL,NULL,0,0,0,0,NULL,NULL
  162.     };
  163.  
  164. /* print options */
  165.  
  166. static void prtopt()
  167. {
  168. struct option *opp;
  169.  
  170.     if (isset(KSHOPTIONPRINT)) {
  171.         printf("Current option settings\n");
  172.         for (opp = optns; opp->name; opp++)
  173.             printf("%-20s%s\n", opp->name,
  174.                 (opts[opp->id] == OPT_SET) ? "on" : "off");
  175.     } else
  176.         for (opp = optns; opp->name; opp++)
  177.             if (opts[opp->id] == OPT_SET)
  178.                 puts(opp->name);
  179. }
  180.  
  181. /* add builtins to the command hash table */
  182.  
  183. void addbuiltins() /**/
  184. {
  185. struct cmdnam *c;
  186. struct bincmd *b;
  187. int t0;
  188.  
  189.     for (t0 = 0, b = builtins; b->name; b++,t0++)
  190.         {
  191.         c = (Cmdnam) zcalloc(sizeof *c);
  192.         c->type = BUILTIN;
  193.         c->u.binnum = t0;
  194.         addhperm(b->name,c,cmdnamtab,freecmdnam);
  195.         }
  196. }
  197.  
  198. /* enable */
  199.  
  200. int bin_enable(name,argv,ops,whocares) /**/
  201. char *name;char **argv;char *ops;int whocares;
  202. {
  203. struct cmdnam *c;
  204. struct bincmd *b;
  205. int t0,ret = 0;
  206.  
  207.     for (; *argv; argv++)
  208.         {
  209.         for (t0 = 0, b = builtins; b->name; b++,t0++)
  210.             if (!strcmp(*argv,b->name))
  211.                 break;
  212.         if (!b->name)
  213.             {
  214.             zerrnam(name,"no such builtin: %s",*argv,0);
  215.             ret = 1;
  216.             }
  217.         else
  218.             {
  219.             c = (Cmdnam) zcalloc(sizeof *c);
  220.             c->type = BUILTIN;
  221.             c->u.binnum = t0;
  222.             addhperm(b->name,c,cmdnamtab,freecmdnam);
  223.             }
  224.         }
  225.     return ret;
  226. }
  227.  
  228. /* :, true */
  229.  
  230. int bin_colon(name,argv,ops,whocares) /**/
  231. char *name;char **argv;char *ops;int whocares;
  232. {
  233.     return 0;
  234. }
  235.  
  236. /* break, bye, continue, exit, logout, return, shift */
  237.  
  238. int bin_break(name,argv,ops,func) /**/
  239. char *name;char **argv;char *ops;int func;
  240. {
  241. int num = -1;
  242.  
  243.     if (*argv)
  244.         num = matheval(*argv);
  245.     if ((func == BIN_BREAK || func == BIN_CONTINUE) && !loops)
  246.         {
  247.         if (func == BIN_CONTINUE)
  248.             zerrnam(name,"not in loop",NULL,0);
  249.         return 1;
  250.         }
  251.     switch (func)
  252.         {
  253.         case BIN_CONTINUE:
  254.             contflag = 1;
  255.         case BIN_BREAK:
  256.             breaks = (num == -1) ? 1 : num;
  257.             if (breaks > loops) breaks = loops;
  258.             break;
  259.         case BIN_LOGOUT:
  260.             if (!islogin)
  261.                 {
  262.                 zerrnam(name,"not login shell",NULL,0);
  263.                 return 1;
  264.                 }
  265.         case BIN_EXIT:
  266.             zexit((num == -1) ? lastval : num);
  267.             break;
  268.         case BIN_RETURN:
  269.             retflag = 1;
  270.             return lastval = (num == -1) ? lastval : num;
  271.         case BIN_SHIFT:
  272.             {
  273.             char **s;
  274.  
  275.             if (num == -1)
  276.                 num = 1;
  277.             if (num > arrlen(pparams))
  278.                 num = arrlen(pparams);
  279.             permalloc();
  280.             s = arrdup(pparams+num);
  281.             heapalloc();
  282.             freearray(pparams);
  283.             pparams = s;
  284.             break;
  285.             }
  286.         }
  287.     return 0;
  288. }
  289.  
  290. /* bg, disown, fg, jobs, wait */
  291.  
  292. int bin_fg(name,argv,ops,func) /**/
  293. char *name;char **argv;char *ops;int func;
  294. {
  295. int job,lng,firstjob = -1,retval = 0;
  296.  
  297.     if (ops['Z']) { if (*argv) strcpy(hackzero,*argv); return 0; }
  298.     lng = (ops['l']) ? 1 : (ops['p']) ? 2 : 0;
  299.     if ((func == BIN_FG || func == BIN_BG) && !jobbing)
  300.         {
  301.         zerrnam(name,"no job control in this shell.",NULL,0);
  302.         return 1;
  303.         }
  304.     if (unset(NOTIFY)) scanjobs();
  305.     if (!(jobtab[curjob].stat & STAT_INUSE))
  306.         {
  307.         curjob = prevjob; setprevjob();
  308.         if (!(jobtab[curjob].stat & STAT_INUSE))
  309.             curjob = prevjob; setprevjob();
  310.         }
  311.     if (func == BIN_JOBS)
  312.         stopmsg = 2;
  313.     if (!*argv)
  314.         if (func == BIN_FG || func == BIN_BG)
  315.             {
  316.             if (curjob == -1 || curjob == thisjob)
  317.                 {
  318.                 zerrnam(name,"no current job",NULL,0);
  319.                 return 1;
  320.                 }
  321.             firstjob = curjob;
  322.             }
  323.         else if (func == BIN_JOBS)
  324.             {
  325.             for (job = 0; job != MAXJOB; job++)
  326.                 if (job != thisjob && jobtab[job].stat)
  327.                     printjob(job+jobtab,lng);
  328.             return 0;
  329.             }
  330.         else
  331.             {
  332.             for (job = 0; job != MAXJOB; job++)
  333.                 if (job != thisjob && jobtab[job].stat)
  334.                     waitjob(job);
  335.             return lastval;
  336.             }
  337.     for (; (firstjob != -1) || *argv; ( void ) (*argv && argv++))
  338.         {
  339.         int stopped,ocj = thisjob;
  340.  
  341.         if (func == BIN_WAIT && isanum(*argv)) {
  342.             waitforpid((long) atoi(*argv));
  343.             retval = lastval;
  344.             thisjob = ocj;
  345.             continue;
  346.         }
  347.         job = (*argv) ? getjob(*argv,name) : firstjob;
  348.         firstjob = -1;
  349.         if (job == -1)
  350.             break;
  351.         if (!(jobtab[job].stat & STAT_INUSE))
  352.             {
  353.             zerrnam(name,"no such job: %d",0,job);
  354.             return 1;
  355.             }
  356.         switch (func)
  357.             {
  358.             case BIN_FG:
  359.             case BIN_BG:
  360.                 if (stopped = (jobtab[job].stat & STAT_STOPPED))
  361.                     makerunning(jobtab+job);
  362.                 else if (func == BIN_BG)
  363.                     {
  364.                     zerrnam(name,"job already in background",NULL,0);
  365.                     thisjob = ocj;
  366.                     return 1;
  367.                     }
  368.                 if (curjob == job)
  369.                     {
  370.                     curjob = prevjob;
  371.                     prevjob = (func == BIN_BG) ? -1 : job;
  372.                     }
  373.                 if (prevjob == job)
  374.                     prevjob = -1;
  375.                 if (prevjob == -1)
  376.                     setprevjob();
  377.                 if (curjob == -1)
  378.                     {
  379.                     curjob = prevjob;
  380.                     setprevjob();
  381.                     }
  382.                 printjob(jobtab+job,(stopped) ? -1 : 0);
  383.                 if (func == BIN_FG)
  384.                     {
  385.                     thisjob = job;
  386.                     if (strcmp(jobtab[job].pwd,pwd))
  387.                         {
  388.                         printf("(pwd : ");
  389.                         printdir(jobtab[job].pwd);
  390.                         printf(")\n");
  391.                         }
  392.                     fflush(stdout);
  393.                     attachtty(jobtab[job].gleader);
  394.                     }
  395.                 if (stopped)
  396.                     killpg(jobtab[job].gleader,SIGCONT);
  397.                 if (func == BIN_FG)
  398.                     waitjobs();
  399.                 break;
  400.             case BIN_JOBS:
  401.                 printjob(job+jobtab,lng);
  402.                 break;
  403.             case BIN_WAIT:
  404.                 waitjob(job);
  405.                 retval = lastval;
  406.                 break;
  407.             case BIN_DISOWN:
  408.                 {
  409.                 static struct job zero;
  410.                 jobtab[job] = zero;
  411.                 break;
  412.                 }
  413.             }
  414.         thisjob = ocj;
  415.         }
  416.     return retval;
  417. }
  418.  
  419. /* false, let */
  420.  
  421. int bin_let(name,argv,ops,func) /**/
  422. char *name;char **argv;char *ops;int func;
  423. {
  424. long val = 0;
  425.  
  426.     while (*argv)
  427.         val = matheval(*argv++);
  428.     return !val;
  429. }
  430.  
  431. /* print the directory stack */
  432.  
  433. static void pdstack()
  434. {
  435. Lknode node;
  436.  
  437.     printdir(pwd);
  438.     for (node = firstnode(dirstack); node; incnode(node))
  439.         {
  440.         putchar(' ');
  441.         printdir(getdata(node));
  442.         }
  443.     putchar('\n');
  444. }
  445.  
  446. /* exit the shell */
  447.  
  448. int zexit(val) /**/
  449. int val;
  450. {
  451.     if (isset(MONITOR))
  452.         if (!stopmsg) {
  453.             checkjobs();
  454.             if (stopmsg) {
  455.                 stopmsg = 2;
  456.                 return 1;
  457.             }
  458.         } else killrunjobs();
  459.     savehistfile(getsparam("HISTFILE"),0,0);
  460.     if (islogin && unset(NORCS))
  461.         sourcehome(".zlogout");
  462.     if (sigtrapped[SIGEXIT])
  463.         dotrap(SIGEXIT);
  464.     exit(val); return 0;
  465. }
  466.  
  467. /* identify an option name */
  468.  
  469. int optlookup(s) /**/
  470. char *s;
  471. {
  472. char *t;
  473. struct option *o;
  474.  
  475.     t = s = strdup(s);
  476.     while (*t)
  477.         if (*t == '_')
  478.             chuck(t);
  479.         else {
  480.             *t = tulower(*t);
  481.             t++;
  482.         }
  483.     for (o = optns; o->name; o++)
  484.         if (!strcmp(o->name,s))
  485.             return o->id;
  486.     return -1;
  487. }
  488.  
  489. /* setopt, unsetopt */
  490.  
  491. int bin_setopt(nam,args,ops,isun) /**/
  492. char *nam;char **args;char *ops;int isun;
  493. {
  494. struct option *opp;
  495. int c;
  496.  
  497.     if (!ops['@'] && !*args) {
  498.         if (!isun)
  499.             prtopt();
  500.         return 0;
  501.     }
  502.     for (opp = optns; opp->name; opp++)
  503.         if (ops[opp->id] == 1+isun)
  504.             opts[opp->id] = OPT_SET;
  505.         else if (ops[opp->id] == 2-isun)
  506.             opts[opp->id] = OPT_UNSET;
  507.     while (*args) {
  508.         c = optlookup(*args++);
  509.         if (c != -1) {
  510.             if (c == INTERACTIVE || c == MONITOR)
  511.                 zerrnam(nam,"can't change that option",NULL,0);
  512.             else
  513.                 opts[c] = (isun) ? OPT_UNSET : OPT_SET;
  514.         } else {
  515.             zerrnam(nam,"no such option: %s",args[-1],0);
  516.             return 1;
  517.         }
  518.     }
  519.     return 0;
  520. }
  521.  
  522. /* execute func on each member of the hash table ht */
  523.  
  524. void listhtable(ht,func) /**/
  525. Hashtab ht;HFunc func;
  526. {
  527. int t0;
  528. struct hashnode *hn;
  529.  
  530.     for (t0 = ht->hsize-1; t0 >= 0; t0--)
  531.         for (hn = ht->nodes[t0]; hn; hn = hn->next)
  532.             func(hn->nam,(char *) hn);
  533. }
  534.  
  535. /* print a shell function (used with listhtable) */
  536.  
  537. void pshfunc(s,cc) /**/
  538. char *s;Cmdnam cc;
  539. {
  540. char *t;
  541.  
  542.     if (cc->type != SHFUNC)
  543.         return;
  544.     if (showflag && (cc->flags & showflag2) != showflag2)
  545.         return;
  546.     if (cc->flags & PMFLAG_u)
  547.         printf("undefined ");
  548.     if (cc->flags & PMFLAG_t)
  549.         printf("traced ");
  550.     if (!cc->u.list || !showflag) {
  551.         printf("%s ()\n",s);
  552.         return;
  553.     }
  554.     t = getpermtext((vptr) (cc->u.list));
  555.     printf("%s () {\n\t%s\n}\n",s,t);
  556.     free(t);
  557. }
  558.  
  559. void niceprint(s) /**/
  560. char *s;
  561. {
  562.     niceprintf(s,stdout);
  563. }
  564.  
  565. void niceprintf(s,f) /**/
  566. char *s;FILE *f;
  567. {
  568.     for (; *s; s++)
  569.         {
  570.         if (isprint(*s))
  571.             fputc(*s,f);
  572.         else if (*s == '\n')
  573.             {
  574.             putc('\\',f);
  575.             putc('n',f);
  576.             }
  577.         else
  578.             {
  579.             putc('^',f);
  580.             fputc(*s | 0x40,f);
  581.             }
  582.         }
  583. }
  584.  
  585. int bin_umask(nam,args,ops,func) /**/
  586. char *nam;char **args;char *ops;int func;
  587. {
  588. int um;
  589. char *s = *args;
  590.  
  591.     um = umask(0);
  592.     umask(um);
  593.     if (!s)
  594.         {
  595.         printf("%03o\n",um);
  596.         return 0;
  597.         }
  598.     if (idigit(*s))
  599.         {
  600.         um = zstrtol(s,&s,8);
  601.         if (*s)
  602.             {
  603.             zerrnam(nam,"bad umask",NULL,0);
  604.             return 1;
  605.             }
  606.         }
  607.     else
  608.         {
  609.         int whomask,op,mask;
  610.  
  611.         for (;;)
  612.             {
  613.             if (*s == 'u')
  614.                 s++, whomask = 0100;
  615.             else if (*s == 'g')
  616.                 s++, whomask = 0010;
  617.             else if (*s == 'o')
  618.                 s++, whomask = 0001;
  619.             else
  620.                 whomask = 0111;
  621.             op = *s++;
  622.             if (!(op == '+' || op == '-' || op == '='))
  623.                 {
  624.                 zerrnam(nam,"bad symbolic mode operator: %c",NULL,op);
  625.                 return 1;
  626.                 }
  627.             mask = whomask;
  628.             if (*s == 'r')
  629.                 mask *= 04;
  630.             else if (*s == 'w')
  631.                 mask *= 02;
  632.             else if (*s != 'x')
  633.                 {
  634.                 zerrnam(nam,"bad symbolic mode permission: %c",NULL,*s);
  635.                 return 1;
  636.                 }
  637.             if (op == '+')
  638.                 um |= mask;
  639.             else if (op == '-')
  640.                 um &= ~mask;
  641.             else /* op == '=' */
  642.                 um = (um & ~(whomask*07)) | mask;
  643.             if (*++s == ',')
  644.                 s++;
  645.             else
  646.                 break;
  647.             }
  648.         if (*s)
  649.             {
  650.             zerrnam(nam,"bad character in symbolic mode: %c",NULL,*s);
  651.             return 1;
  652.             }
  653.         }
  654.     umask(um);
  655.     return 0;
  656. }
  657.  
  658. /* type, whence, which */
  659.  
  660. int bin_whence(nam,argv,ops,func) /**/
  661. char *nam;char **argv;char *ops;int func;
  662. {
  663. struct cmdnam *chn;
  664. struct alias *a;
  665. int retval = 0;
  666. int csh = ops['c'],all = ops['a'];
  667. int v = ops['v'] || csh;
  668. char *cnam;
  669.  
  670.     for (; *argv; argv++) {
  671.         if (!ops['p'] && (a = (Alias) gethnode(*argv,aliastab))) {
  672.             if (a->cmd < 0)
  673.                 printf((csh) ? "%s: shell reserved word\n" :
  674.                     (v) ? "%s is a reserved word\n" : "%s\n",*argv);
  675.             else if (!v)
  676.                 puts(a->text);
  677.             else if (a->cmd)
  678.                 printf((csh) ? "%s: aliased to %s\n" :
  679.                     "%s is an alias for %s\n",*argv,a->text);
  680.             else
  681.                 printf((csh) ? "%s: globally aliased to %s\n" :
  682.                     "%s is a global alias for %s\n",*argv,a->text);
  683.             retval = 0;
  684.             if (!all) continue;
  685.         }
  686.         if (!ops['p'] && (chn = (Cmdnam) gethnode(*argv,cmdnamtab)) &&
  687.                 (chn->type == SHFUNC || chn->type == BUILTIN)) {
  688.             if (chn->type == SHFUNC) {
  689.                 if (csh || ops['f']) {
  690.                     showflag = 1; showflag2 = 0;
  691.                     pshfunc(*argv,chn);
  692.                 } else {
  693.                     printf((v) ? "%s is a function\n" : "%s\n",*argv);
  694.                 }
  695.             } else
  696.                 printf((csh) ? "%s: shell built-in command\n" :
  697.                     (v) ? "%s is a shell builtin\n" : "%s\n",*argv);
  698.             retval = 0;
  699.             if (!all) continue;
  700.         }
  701.         if (all) {
  702.             char **pp,buf[MAXPATHLEN],*z;
  703.             for (pp = path; *pp; pp++) {
  704.                 z = buf;
  705.                 strucpy(&z,*pp);
  706.                 *z++ = '/';
  707.                 strcpy(z,*argv);
  708.                 if (iscom(buf)) {
  709.                     if (v && !csh) printf("%s is %s\n",*argv,buf);
  710.                     else puts(buf);
  711.                     retval = 0;
  712.                 }
  713.             }
  714.         } else if (!(cnam = findcmd(*argv))) {
  715.             if (v) printf("%s not found\n",*argv);
  716.             retval = 1;
  717.             break;
  718.         } else {
  719.             if (v && !csh) printf("%s is %s\n",*argv,cnam);
  720.             else puts(cnam);
  721.             retval = 0;
  722.         }
  723.     }
  724.     return retval;
  725. }
  726.  
  727. /* cd, chdir, pushd, popd */
  728.  
  729. int bin_cd(nam,argv,ops,func) /**/
  730. char *nam;char **argv;char *ops;int func;
  731. {
  732. char *dest;
  733.  
  734.     if (func == BIN_CD && isset(AUTOPUSHD))
  735.         func = BIN_PUSHD;
  736.     dest = cd_get_dest(nam,argv,ops,func);
  737.     if (!dest) return 1;
  738.     dest = cd_do_chdir(nam,dest);
  739.     if (!dest) return 1;
  740.     cd_new_pwd(func,dest);
  741.     return 0;
  742. }
  743.  
  744. char *cd_get_dest(nam,argv,ops,func) /**/
  745. char *nam;char **argv;char *ops;int func;
  746. {
  747. char *dest;
  748.  
  749.     if (!argv[0])
  750.         if (func == BIN_CD || (func == BIN_PUSHD && isset(PUSHDTOHOME)
  751.                 || !full(dirstack)))
  752.             dest = home;
  753.         else
  754.             dest = getnode(dirstack);
  755.     else if (!argv[1]) {
  756.         Lknode n;
  757.         int dd;
  758.  
  759.         if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '-' : '+')) {
  760.             dd = atoi(argv[0]+1)-1;
  761.             if (dd < 0) {
  762.                 zerrnam(nam,"bad directory specification",NULL,0);
  763.                 return NULL;
  764.             }
  765.             for (n = firstnode(dirstack); n && dd; dd--, incnode(n));
  766.             if (!n) {
  767.                 zerrnam(nam,"no such entry in dir stack",NULL,0);
  768.                 return NULL;
  769.             }
  770.             dest = remnode(dirstack,n);
  771.         } else if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '+' : '-')) {
  772.             dd = atoi(argv[0]+1);
  773.             for (n = lastnode(dirstack); n != (Lknode) dirstack && dd;
  774.                     dd--, n = prevnode(n));
  775.             if (n == (Lknode) dirstack) {
  776.                 zerrnam(nam,"no such entry in dir stack",NULL,0);
  777.                 return NULL;
  778.             }
  779.             dest = remnode(dirstack,n);
  780.         } else {
  781.             if (!strcmp(argv[0],"-")) printdircr(dest = oldpwd);
  782.             else dest = argv[0];
  783.         }
  784.     } else {
  785.         char *u;
  786.         int len1,len2,len3;
  787.  
  788.         if (!(u = ztrstr(pwd,argv[0]))) {
  789.             zerrnam(nam,"string not in pwd: %s",argv[0],0);
  790.             return NULL;
  791.         }
  792.         len1 = strlen(argv[0]);
  793.         len2 = strlen(argv[1]);
  794.         len3 = u-pwd;
  795.         dest = alloc(len3+len2+strlen(u+len1)+1);
  796.         strncpy(dest,pwd,len3);
  797.         strcpy(dest+len3,argv[1]);
  798.         strcat(dest,u+len1);
  799.         printdircr(dest);
  800.     }
  801.     return dest;
  802. }
  803.  
  804. char *cd_do_chdir(cnam,dest) /**/
  805. char *cnam; char *dest;
  806. {
  807. int hasdot = 0, eno = ENOENT;
  808. char **pp,*ret;
  809.  
  810.     if (*dest == '/') {
  811.         if (ret = cd_try_chdir(NULL,dest)) return ret;
  812.         zerrnam(cnam,"%e: %s",dest,errno);
  813.         return NULL;
  814.     }
  815.     for (pp = cdpath; *pp; pp++)
  816.         if ((*pp)[0] == '.' && (*pp)[1] == '\0') hasdot = 1;
  817.     if (!hasdot) {
  818.         if (ret = cd_try_chdir(NULL,dest)) return ret;
  819.         if (errno != ENOENT) eno = errno;
  820.     }
  821.     for (pp = cdpath; *pp; pp++) {
  822.         if (ret = cd_try_chdir(*pp,dest)) {
  823.             if (strcmp(*pp,".")) {
  824.                 printdircr(ret);
  825.             }
  826.             return ret;
  827.         }
  828.         if (errno != ENOENT) eno = errno;
  829.     }
  830.     if (isset(CDABLEVARS)) {
  831.         char *s = getsparam(dest);
  832.         if (s && *s == '/' && chdir(s) != -1) {
  833.             printdircr(s);
  834.             return s;
  835.         }
  836.         if (errno != ENOENT) eno = errno;
  837.     }
  838.     zerrnam(cnam,"%e: %s",dest,eno);
  839.     return NULL;
  840. }
  841.  
  842. char *cd_try_chdir(pfix,dest) /**/
  843. char *pfix; char *dest;
  844. {
  845. static char buf[MAXPATHLEN], buf2[MAXPATHLEN];
  846. char *s;
  847. int dotsct;
  848.  
  849.     if (pfix) sprintf(buf,"%s/%s",(!strcmp("/",pfix)) ? "" : pfix,dest); 
  850.     else strcpy(buf,dest);
  851.     dotsct = fixdir(buf2,buf);
  852.     if (buf2[0] == '/') return (chdir(buf2) == -1) ? NULL : buf2;
  853.     if (!dotsct) {
  854.         if (chdir((*buf2) ? buf2 : ".") == -1) return NULL;
  855.         if (*buf2) sprintf(buf,"%s/%s",(!strcmp("/",pwd)) ? "" : pwd,buf2);
  856.         else strcpy(buf,pwd);
  857.         return buf;
  858.     }
  859.     strcpy(buf,pwd);
  860.     s = buf+strlen(buf)-1;
  861.     while (dotsct--) while (s != buf) if (*--s == '/') break;
  862.     if (s == buf || *buf2) s++;
  863.     strcpy(s,buf2);
  864.     if (chdir(buf) != -1 || chdir(dest) != -1) return buf;
  865.     return NULL;
  866. }
  867.  
  868. int fixdir(d,s) /**/
  869. char *d; char *s;
  870. {
  871. int ct = 0;
  872. char *d0 = d;
  873.  
  874. #ifdef HAS_RFS
  875.     if (*s == '/' && s[1] == '.' && s[2] == '.') {
  876.         *d++ = '/'; *d++ = '.'; *d++ = '.';
  877.         s += 3;
  878.     }
  879. #endif
  880.     for (;;) {
  881.         if (*s == '/') {
  882.             *d++ = *s++;
  883.             while (*s == '/') s++;
  884.         }
  885.         if (!*s) {
  886.             while (d > d0+1 && d[-1] == '/') d--;
  887.             *d = '\0';
  888.             return ct;
  889.         }
  890.         if (s[0] == '.' && s[1] == '.' && (s[2] == '\0' || s[2] == '/')) {
  891.             if (d > d0+1) {
  892.                 for (d--; d > d0+1 && d[-1] != '/'; d--);
  893.             } else ct++;
  894.             s += 2; if (*s) s++;
  895.         } else if (s[0] == '.' && (s[1] == '/' || s[1] == '\0')) {
  896.             s++; if (*s) s++;
  897.         } else {
  898.             while (*s != '/' && *s != '\0') *d++ = *s++;
  899.         }
  900.     }
  901. }
  902.  
  903. void cd_new_pwd(func,s) /**/
  904. int func; char *s;
  905. {
  906. Param pm;
  907. List l;
  908.  
  909.     oldpwd = pwd;
  910.     if (isset(CHASELINKS))
  911.         pwd = findpwd(s);
  912.     else
  913.         pwd = ztrdup(s);
  914.     if ((pm = gethnode("PWD", paramtab)) &&
  915.          (pm->flags & PMFLAG_x) && pm->env)
  916.         pm->env = replenv(pm->env,pwd);
  917.     if ((pm = gethnode("OLDPWD", paramtab)) &&
  918.          (pm->flags & PMFLAG_x) && pm->env)
  919.         pm->env = replenv(pm->env,oldpwd);
  920.     if (func == BIN_PUSHD) {
  921.         permalloc();
  922.         if (isset(PUSHDIGNOREDUPS)) {
  923.             Lknode n;
  924.             for (n = firstnode(dirstack); n; incnode(n))
  925.                 if (!strcmp(oldpwd,getdata(n))) {
  926.                     free(remnode(dirstack,n)); break;
  927.                 }
  928.         }
  929.         pushnode(dirstack,oldpwd);
  930.         heapalloc();
  931.     }
  932.     if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
  933.         pdstack();
  934.     if (l = getshfunc("chpwd")) {
  935.         fflush(stdout); fflush(stderr);
  936.         doshfuncnoval(dupstruct(l),NULL,0);
  937.     }
  938.     if (dirstacksize != -1 && countnodes(dirstack) >= dirstacksize) {
  939.         if (dirstacksize < 2)
  940.             dirstacksize = 2;
  941.         else
  942.             free(remnode(dirstack,lastnode(dirstack)));
  943.     }
  944. }
  945.  
  946. void convertwd(s,t,off) /**/
  947. char *s; char *t; int off;
  948. {
  949. char *u,*start;
  950.  
  951.     *t++ = '/';
  952.     start = t;
  953.     while (off--) *t++ = *s++;
  954.     for (;;) {
  955.         while (*s == '/') s++;
  956.         for (u = s; *u && *u != '/'; u++);
  957.         if (!strncmp(s,".",u-s)) {
  958.             ;
  959.         } else if (!strncmp(s,"..",u-s)) {
  960.             while (t != start && *--t != '/');
  961.         } else {
  962.             if (t != start) *t++ = '/';
  963.             struncpy(&t,s,u-s);
  964.         }
  965.         if (!*u) break;
  966.         s = u;
  967.     }
  968.     *t = '\0';
  969. }
  970.  
  971. int bin_rehash(name,argv,ops,func) /**/
  972. char *name;char **argv;char *ops;int func;
  973. {
  974.     newcmdnamtab();
  975.     if (ops['f']) fullhash();
  976.     return 0;
  977. }
  978.  
  979. int bin_hash(name,argv,ops,func) /**/
  980. char *name;char **argv;char *ops;int func;
  981. {
  982. struct cmdnam *chn;
  983.  
  984.     chn = (Cmdnam) zcalloc(sizeof *chn);
  985.     chn->type = EXCMD;
  986.     chn->pcomp = NULL; /* this is probably a bug ! */
  987.     chn->u.nam = ztrdup(argv[1]);
  988.     addhnode(ztrdup(argv[0]),chn,cmdnamtab,freecmdnam);
  989.     return 0;
  990. }
  991.  
  992. /* != 0 if s is a prefix of t */
  993.  
  994. int prefix(s,t) /**/
  995. char *s;char *t;
  996. {
  997.     while (*s && *t && *s == *t) s++,t++;
  998.     return (!*s);
  999. }
  1000.  
  1001. /* convert %%, %1, %foo, %?bar? to a job number */
  1002.  
  1003. int getjob(s,prog) /**/
  1004. char *s;char *prog;
  1005. {
  1006. int t0,retval;
  1007.  
  1008.     if (*s != '%')
  1009.         goto jump;
  1010.     s++;
  1011.     if (*s == '%' || *s == '+' || !*s)
  1012.         {
  1013.         if (curjob == -1)
  1014.             {
  1015.             zerrnam(prog,"no current job",NULL,0);
  1016.             retval = -1; goto done;
  1017.             }
  1018.         retval = curjob; goto done;
  1019.         }
  1020.     if (*s == '-')
  1021.         {
  1022.         if (prevjob == -1)
  1023.             {
  1024.             zerrnam(prog,"no previous job",NULL,0);
  1025.             retval = -1; goto done;
  1026.             }
  1027.         retval = prevjob; goto done;
  1028.         }
  1029.     if (idigit(*s))
  1030.         {
  1031.         t0 = atoi(s);
  1032.         if (t0 && t0 < MAXJOB && jobtab[t0].stat && t0 != thisjob)
  1033.             { retval = t0; goto done; }
  1034.         zerrnam(prog,"no such job",NULL,0);
  1035.         retval = -1; goto done;
  1036.         }
  1037.     if (*s == '?')
  1038.         {
  1039.         struct process *pn;
  1040.  
  1041.         for (t0 = MAXJOB-1; t0 >= 0; t0--)
  1042.             if (jobtab[t0].stat && t0 != thisjob)
  1043.                 for (pn = jobtab[t0].procs; pn; pn = pn->next)
  1044.                     if (ztrstr(pn->text,s+1))
  1045.                         { retval = t0; goto done; }
  1046.         zerrnam(prog,"job not found: %s",s,0);
  1047.         retval = -1; goto done;
  1048.         }
  1049. jump:
  1050.     if ((t0 = findjobnam(s)) != -1)
  1051.         { retval = t0; goto done; }
  1052.     zerrnam(prog,"job not found: %s",s,0);
  1053.     retval = -1;
  1054. done:
  1055.     return retval;
  1056. }
  1057.  
  1058. /* find a job named s */
  1059.  
  1060. int findjobnam(s) /**/
  1061. char *s;
  1062. {
  1063. int t0;
  1064.  
  1065.     for (t0 = MAXJOB-1; t0 >= 0; t0--)
  1066.         if (jobtab[t0].stat && jobtab[t0].procs && t0 != thisjob && 
  1067.                 jobtab[t0].procs->text && prefix(s,jobtab[t0].procs->text))
  1068.             return t0;
  1069.     return -1;
  1070. }
  1071.  
  1072. int isanum(s) /**/
  1073. char *s;
  1074. {
  1075.     while (*s == '-' || idigit(*s)) s++;
  1076.     return *s == '\0';
  1077. }
  1078.  
  1079. int bin_kill(nam,argv,ops,func) /**/
  1080. char *nam;char **argv;char *ops;int func;
  1081. {
  1082. int sig = SIGTERM;
  1083. int retval = 0;
  1084.  
  1085.     if (*argv && **argv == '-') {
  1086.         if (idigit((*argv)[1]))
  1087.             sig = atoi(*argv+1);
  1088.         else {
  1089.             if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
  1090.                 printf("%s",sigs[1]);
  1091.                 for (sig = 2; sig != SIGCOUNT; sig++)
  1092.                     printf(" %s",sigs[sig]);
  1093.                 putchar('\n');
  1094.                 return 0;
  1095.             }
  1096.             for (sig = 0; sig != SIGCOUNT; sig++)
  1097.                 if (!strcmp(sigs[sig],*argv+1)) break;
  1098.             if (sig == SIGCOUNT) {
  1099.                 zerrnam(nam,"unknown signal: SIG%s",*argv+1,0);
  1100.                 zerrnam(nam,"type kill -l for a List of signals",NULL,0);
  1101.                 return 1;
  1102.             }
  1103.         }
  1104.         argv++;
  1105.     }
  1106.     for (; *argv; argv++) {
  1107.         if (**argv == '%') {
  1108.             int p = getjob(*argv,"kill");
  1109.  
  1110.             if (p == -1) {
  1111.                 retval = 1;
  1112.                 continue;
  1113.             }
  1114.             if (killjb(jobtab+p,sig) == -1) {
  1115.                 zerrnam("kill","kill failed: %e",NULL,errno);
  1116.                 retval = 1;
  1117.                 continue;
  1118.             }
  1119.             if (jobtab[p].stat & STAT_STOPPED) {
  1120.                 if (sig == SIGCONT)
  1121.                     jobtab[p].stat &= ~STAT_STOPPED;
  1122.                 if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP
  1123.                         && sig != SIGTTOU && sig != SIGTTIN && sig != SIGSTOP)
  1124.                     killjb(jobtab+p,SIGCONT);
  1125.             }
  1126.         } else if (!isanum(*argv)) {
  1127.             zerrnam("kill","illegal pid: %s",*argv,0);
  1128.         } else if (kill(atoi(*argv),sig) == -1) {
  1129.                 zerrnam("kill","kill failed: %e",NULL,errno);
  1130.                 retval = 1;
  1131.         }
  1132.     }
  1133.     return 0;
  1134. }
  1135.  
  1136. static char *recs[] = {
  1137.     "cputime","filesize","datasize","stacksize","coredumpsize",
  1138.     "resident","descriptors"
  1139.     };
  1140.  
  1141. int bin_limit(nam,argv,ops,func) /**/
  1142. char *nam;char **argv;char *ops;int func;
  1143. {
  1144. #ifndef RLIM_INFINITY
  1145.     zerrnam(nam,"not available on this system",NULL,0);
  1146.     return 1;
  1147. #else
  1148. char *s;
  1149. int hard = ops['h'],t0,lim;
  1150. long val;
  1151.  
  1152.     if (ops['s'])
  1153.         {
  1154.         if (*argv)
  1155.             zerrnam(nam,"arguments after -s ignored",NULL,0);
  1156.         for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1157.             if (setrlimit(t0,limits+t0) < 0)
  1158.                 zerrnam(nam,"setrlimit failed: %e",NULL,errno);
  1159.         return 0;
  1160.         }
  1161.     if (!*argv)
  1162.         {
  1163.         showlimits(hard,-1);
  1164.         return 0;
  1165.         }
  1166.     while (s = *argv++)
  1167.         {
  1168.         for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1169.             if (!strncmp(recs[t0],s,strlen(s)))
  1170.                 {
  1171.                 if (lim != -1)
  1172.                     lim = -2;
  1173.                 else
  1174.                     lim = t0;
  1175.                 }
  1176.         if (lim < 0)
  1177.             {
  1178.             zerrnam("limit",
  1179.                 (lim == -2) ? "ambiguous resource specification: %s"
  1180.                                 : "no such resource: %s",s,0);
  1181.             return 1;
  1182.             }
  1183.         if (!(s = *argv++))
  1184.             {
  1185.             showlimits(hard,lim);
  1186.             return 0;
  1187.             }
  1188.         if (!lim)
  1189.             {
  1190.             val = zstrtol(s,&s,10);
  1191.             if (*s)
  1192.                 if ((*s == 'h' || *s == 'H') && !s[1])
  1193.                     val *= 3600L;
  1194.                 else if ((*s == 'm' || *s == 'M') && !s[1])
  1195.                     val *= 60L;
  1196.                 else if (*s == ':')
  1197.                     val = val*60+zstrtol(s+1,&s,10);
  1198.                 else
  1199.                     {
  1200.                     zerrnam("limit","unknown scaling factor: %s",s,0);
  1201.                     return 1;
  1202.                     }
  1203.             }
  1204. #ifdef RLIMIT_NOFILE
  1205.         else if (lim == RLIMIT_NOFILE)
  1206.             val = zstrtol(s,&s,10);
  1207. #endif
  1208.         else
  1209.             {
  1210.             val = zstrtol(s,&s,10);
  1211.             if (!*s || ((*s == 'k' || *s == 'K') && !s[1]))
  1212.                 val *= 1024L;
  1213.             else if ((*s == 'M' || *s == 'm') && !s[1])
  1214.                 val *= 1024L*1024;
  1215.             else
  1216.                 {
  1217.                 zerrnam("limit","unknown scaling factor: %s",s,0);
  1218.                 return 1;
  1219.                 }
  1220.             }
  1221.         if (hard)
  1222.             if (val > limits[lim].rlim_max && geteuid())
  1223.                 {
  1224.                 zerrnam("limit","can't raise hard limits",NULL,0);
  1225.                 return 1;
  1226.                 }
  1227.             else
  1228.                 {
  1229.                 limits[lim].rlim_max = val;
  1230.                 if (limits[lim].rlim_max < limits[lim].rlim_cur)
  1231.                     limits[lim].rlim_cur = limits[lim].rlim_max;
  1232.                 }
  1233.         else
  1234.             if (val > limits[lim].rlim_max)
  1235.                 {
  1236.                 zerrnam("limit","limit exceeds hard limit",NULL,0);
  1237.                 return 1;
  1238.                 }
  1239.             else
  1240.                 limits[lim].rlim_cur = val;
  1241.         }
  1242.     return 0;
  1243. #endif
  1244. }
  1245.  
  1246. int bin_unlimit(nam,argv,ops,func) /**/
  1247. char *nam;char **argv;char *ops;int func;
  1248. {
  1249. #ifndef RLIM_INFINITY
  1250.     zerrnam(nam,"not available on this system",NULL,0);
  1251.     return 1;
  1252. #else
  1253. int hard = ops['h'],t0,lim;
  1254.  
  1255.     if (hard && geteuid())
  1256.         {
  1257.         zerrnam(nam,"can't remove hard limits",NULL,0);
  1258.         return 1;
  1259.         }
  1260.     if (!*argv)
  1261.         {
  1262.         for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1263.             {
  1264.             if (hard)
  1265.                 limits[t0].rlim_max = RLIM_INFINITY;
  1266.             else
  1267.                 limits[t0].rlim_cur = limits[t0].rlim_max;
  1268.             }
  1269.         return 0;
  1270.         }
  1271.     for (; *argv; argv++)
  1272.         {
  1273.         for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1274.             if (!strncmp(recs[t0],*argv,strlen(*argv)))
  1275.                 {
  1276.                 if (lim != -1)
  1277.                     lim = -2;
  1278.                 else
  1279.                     lim = t0;
  1280.                 }
  1281.         if (lim < 0)
  1282.             {
  1283.             zerrnam(nam,
  1284.                 (lim == -2) ? "ambiguous resource specification: %s"
  1285.                                 : "no such resource: %s",*argv,0);
  1286.             return 1;
  1287.             }
  1288.         if (hard)
  1289.             limits[lim].rlim_max = RLIM_INFINITY;
  1290.         else
  1291.             limits[lim].rlim_cur = limits[lim].rlim_max;
  1292.         }
  1293.     return 0;
  1294. #endif
  1295. }
  1296.  
  1297. void showlimits(hard,lim) /**/
  1298. int hard;int lim;
  1299. {
  1300. int t0;
  1301. long val;
  1302.  
  1303. #ifdef RLIM_INFINITY
  1304.     for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1305.         if (t0 == lim || lim == -1)
  1306.             {
  1307.             printf("%-16s",recs[t0]);
  1308.             val = (hard) ? limits[t0].rlim_max : limits[t0].rlim_cur;
  1309.             if (val == RLIM_INFINITY)
  1310.                 printf("unlimited\n");
  1311.             else if (!t0)
  1312.                 printf("%d:%02d:%02d\n",(int) (val/3600),
  1313.                     (int) (val/60) % 60,(int) (val % 60));
  1314. #ifdef RLIMIT_NOFILE
  1315.             else if (t0 == RLIMIT_NOFILE)
  1316.                 printf("%d\n",(int) val);
  1317. #endif
  1318.             else if (val >= 1024L*1024L)
  1319.                 printf("%ldMb\n",val/(1024L*1024L));
  1320.             else
  1321.                 printf("%ldKb\n",val/1024L);
  1322.             }
  1323. #endif
  1324. }
  1325.  
  1326. int bin_sched(nam,argv,ops,func) /**/
  1327. char *nam;char **argv;char *ops;int func;
  1328. {
  1329. char *s = *argv++;
  1330. time_t t;
  1331. long h,m;
  1332. struct tm *tm;
  1333. struct schedcmd *sch,*sch2,*schl;
  1334. int t0;
  1335.  
  1336.     if (s && *s == '-')
  1337.         {
  1338.         t0 = atoi(s+1);
  1339.  
  1340.         if (!t0)
  1341.             {
  1342.             zerrnam("sched","usage for delete: sched -<item#>.",NULL,0);
  1343.             return 1;
  1344.             }
  1345.         for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds, t0--;
  1346.                 sch && t0; sch = (schl = sch)->next, t0--);
  1347.         if (!sch)
  1348.             {
  1349.             zerrnam("sched","not that many entries",NULL,0);
  1350.             return 1;
  1351.             }
  1352.         schl->next = sch->next;
  1353.         free(sch->cmd);
  1354.         free(sch);
  1355.         return 0;
  1356.         }
  1357.     if (!s)
  1358.         {
  1359.         char tbuf[40];
  1360.  
  1361.         for (t0 = 1, sch = schedcmds; sch; sch = sch->next,t0++)
  1362.             {
  1363.             t = sch->time;
  1364.             tm = localtime(&t);
  1365.             ztrftime(tbuf,20,"%a %b %e %k:%M:%S",tm);
  1366.             printf("%3d %s %s\n",t0,tbuf,sch->cmd);
  1367.             }
  1368.         return 0;
  1369.         }
  1370.     else if (!*argv)
  1371.         {
  1372.         zerrnam("sched","not enough arguments",NULL,0);
  1373.         return 1;
  1374.         }
  1375.     if (*s == '+')
  1376.         {
  1377.         h = zstrtol(s+1,&s,10);
  1378.         if (*s != ':')
  1379.             {
  1380.             zerrnam("sched","bad time specifier",NULL,0);
  1381.             return 1;
  1382.             }
  1383.         m = zstrtol(s+1,&s,10);
  1384.         if (*s)
  1385.             {
  1386.             zerrnam("sched","bad time specifier",NULL,0);
  1387.             return 1;
  1388.             }
  1389.         t = time(NULL)+h*3600+m*60;
  1390.         }
  1391.     else
  1392.         {
  1393.         h = zstrtol(s,&s,10);
  1394.         if (*s != ':')
  1395.             {
  1396.             zerrnam("sched","bad time specifier",NULL,0);
  1397.             return 1;
  1398.             }
  1399.         m = zstrtol(s+1,&s,10);
  1400.         if (*s && *s != 'a' && *s != 'p')
  1401.             {
  1402.             zerrnam("sched","bad time specifier",NULL,0);
  1403.             return 1;
  1404.             }
  1405.         t = time(NULL);
  1406.         tm = localtime(&t);
  1407.         t -= tm->tm_sec+tm->tm_min*60+tm->tm_hour*3600;
  1408.         if (*s == 'p')
  1409.             h += 12;
  1410.         t += h*3600+m*60;
  1411.         if (t < time(NULL))
  1412.             t += 3600*24;
  1413.         }
  1414.     sch = zcalloc(sizeof *sch);
  1415.     sch->time = t;
  1416.     sch->cmd = ztrdup(spacejoin(argv));
  1417.     sch->next = NULL;
  1418.     for (sch2 = (struct schedcmd *) &schedcmds; sch2->next; sch2 = sch2->next);
  1419.     sch2->next = sch;
  1420.     return 0;
  1421. }
  1422.  
  1423. int bin_eval(nam,argv,ops,func) /**/
  1424. char *nam;char **argv;char *ops;int func;
  1425. {
  1426. char *s = ztrdup(spacejoin(argv));
  1427. List list;
  1428.  
  1429.     hungets(s);
  1430.     free(s);
  1431.     strinbeg();
  1432.     if (!(list = parse_list()))
  1433.         {
  1434.         hflush();
  1435.         strinend();
  1436.         return 1;
  1437.         }
  1438.     strinend();
  1439.     runlist(list);
  1440.     return lastval;
  1441. }
  1442.  
  1443. /* get the history event associated with s */
  1444.  
  1445. int fcgetcomm(s) /**/
  1446. char *s;
  1447. {
  1448. int cmd;
  1449.  
  1450.     if (cmd = atoi(s))
  1451.         {
  1452.         if (cmd < 0)
  1453.             cmd = curhist+cmd+1;
  1454.         return cmd;
  1455.         }
  1456.     cmd = hcomsearch(s);
  1457.     if (cmd == -1)
  1458.         zerrnam("fc","event not found: %s",s,0);
  1459.     return cmd;
  1460. }
  1461.  
  1462. /* perform old=new substituion */
  1463.  
  1464. int fcsubs(sp,sub) /**/
  1465. char **sp;struct asgment *sub;
  1466. {
  1467. char *s1,*s2,*s3,*s4,*s = *sp,*s5;
  1468. int subbed = 0;
  1469.  
  1470.     while (sub)
  1471.         {
  1472.         s1 = sub->name;
  1473.         s2 = sub->value;
  1474.         sub = sub->next;
  1475.         s5 = s;
  1476.         while (s3 = (char *) ztrstr(s5,s1))
  1477.             {
  1478.             s4 = alloc(1+(s3-s)+strlen(s2)+strlen(s3+strlen(s1)));
  1479.             ztrncpy(s4,s,s3-s);
  1480.             strcat(s4,s2);
  1481.             s5 = s4+strlen(s4);
  1482.             strcat(s4,s3+strlen(s1));
  1483.             s = s4;
  1484.             subbed = 1;
  1485.             }
  1486.         }
  1487.     *sp = s;
  1488.     return subbed;
  1489. }
  1490.  
  1491. /* print a series of history events to a file */
  1492.  
  1493. int fclist(f,n,r,D,d,first,last,subs) /**/
  1494. FILE *f;int n;int r;int D;int d;int first;int last;struct asgment *subs;
  1495. {
  1496. int done = 0;
  1497. char *s,*hs;
  1498. Histent ent;
  1499.  
  1500.     if (!subs) done = 1;
  1501.     for (;;) {
  1502.         hs = quietgetevent(first);
  1503.         if (!hs) {
  1504.             zerrnam("fc","no such event: %d",NULL,first);
  1505.             return 1;
  1506.         }
  1507.         s = makehstr(hs);
  1508.         done |= fcsubs(&s,subs);
  1509.         if (n) fprintf(f,"%5d  ",first);
  1510.         ent = NULL;
  1511.         if (d) {
  1512.             struct tm *ltm;
  1513.             
  1514.             if (!ent) ent = gethistent(first);
  1515.             ltm = localtime(&ent->stim);
  1516.             fprintf(f,"%2d:%02d  ",ltm->tm_hour,ltm->tm_min);
  1517.         }
  1518.         if (D) {
  1519.             long diff;
  1520.  
  1521.             if (!ent) ent = gethistent(first);
  1522.             diff = (ent->ftim) ? ent->ftim-ent->stim : 0;
  1523.             fprintf(f,"%d:%02d  ",diff/60,diff%60);
  1524.         }
  1525.         if (f == stdout) {
  1526.             niceprintf(s,f);
  1527.             putc('\n',f);
  1528.         } else fprintf(f,"%s\n",s);
  1529.         if (first == last) break;
  1530.         (r) ? first-- : first++;
  1531.     }
  1532.     if (f != stdout) fclose(f);
  1533.     if (!done) {
  1534.         zerrnam("fc","no substitutions performed",NULL,0);
  1535.         return 1;
  1536.     }
  1537.     return 0;
  1538. }
  1539.  
  1540. int fcedit(ename,fn) /**/
  1541. char *ename;char *fn;
  1542. {
  1543.     if (!strcmp(ename,"-"))
  1544.         return 1;
  1545.     return !zyztem(ename,fn);
  1546. }
  1547.  
  1548. /* fc, history, r */
  1549.  
  1550. int bin_fc(nam,argv,ops,func) /**/
  1551. char *nam;char **argv;char *ops;int func;
  1552. {
  1553. int first = -1,last = -1,retval,minflag = 0;
  1554. char *s;
  1555. struct asgment *asgf = NULL,*asgl = NULL;
  1556.  
  1557.     if (!interact) {
  1558.         zerrnam(nam,"not interactive shell",NULL,0);
  1559.         return 1;
  1560.     }
  1561.     if (!(ops['l'] && unset(HISTNOSTORE))) remhist();
  1562.     if (ops['R']) {
  1563.         readhistfile(*argv ? *argv : getsparam("HISTFILE"),1);
  1564.         return 0;
  1565.     }
  1566.     if (ops['W']) {
  1567.         savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,0);
  1568.         return 0;
  1569.     }
  1570.     if (ops['A']) {
  1571.         savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,1);
  1572.         return 0;
  1573.     }
  1574.     while (*argv && equalsplit(*argv,&s)) {
  1575.         struct asgment *a = (struct asgment *) alloc(sizeof *a);
  1576.  
  1577.         if (!asgf) asgf = asgl = a;
  1578.         else {
  1579.             asgl->next = a;
  1580.             asgl = a;
  1581.         }
  1582.         a->name = *argv;
  1583.         a->value = s;
  1584.         argv++;
  1585.     }
  1586.     if (*argv) {
  1587.         minflag = **argv == '-';
  1588.         first = fcgetcomm(*argv);
  1589.         if (first == -1) return 1;
  1590.         argv++;
  1591.     }
  1592.     if (*argv) {
  1593.         last = fcgetcomm(*argv);
  1594.         if (last == -1) return 1;
  1595.         argv++;
  1596.     }
  1597.     if (*argv) {
  1598.         zerrnam("fc","too many arguments",NULL,0);
  1599.         return 1;
  1600.     }
  1601.     if (first == -1) first = (ops['l']) ? curhist-16 : curhist;
  1602.     if (last == -1) last = (ops['l']) ? curhist : first;
  1603.     if (first < firsthist()) first = firsthist();
  1604.     if (last == -1) last = (minflag) ? curhist : first;
  1605.     if (ops['l'])
  1606.         retval = fclist(stdout,!ops['n'],ops['r'],ops['D'],ops['d'],
  1607.             first,last,asgf);
  1608.     else {
  1609.         FILE *out;
  1610.         char *fil = gettemp();
  1611.  
  1612.         out = fopen(fil,"w");
  1613.         if (!out)
  1614.             zerrnam("fc","can't open temp file: %e",NULL,errno);
  1615.         else {
  1616.             retval = 1;
  1617.             if (!fclist(out,0,ops['r'],0,0,first,last,asgf))
  1618.                 if (fcedit(auxdata ? auxdata : fceditparam,fil))
  1619.                     if (stuff(fil))
  1620.                         zerrnam("fc","%e: %s",s,errno);
  1621.                     else
  1622.                         retval = 0;
  1623.         }
  1624.         unlink(fil);
  1625.     }
  1626.     return retval;
  1627. }
  1628.  
  1629. int bin_suspend(name,argv,ops,func) /**/
  1630. char *name;char **argv;char *ops;int func;
  1631. {
  1632.     if (islogin && !ops['f']) {
  1633.         zerrnam(name,"can't suspend login shell",NULL,0);
  1634.         return 1;
  1635.     }
  1636.     if (jobbing) {
  1637.         signal(SIGPIPE,SIG_DFL);
  1638.         signal(SIGTTIN,SIG_DFL);
  1639.         signal(SIGTSTP,SIG_DFL);
  1640.         signal(SIGTTOU,SIG_DFL);
  1641.     }
  1642.     kill(0,SIGTSTP);
  1643.     if (jobbing) {
  1644.         while (gettygrp() != mypgrp) {
  1645.             sleep(1);
  1646.             if (gettygrp() != mypgrp) kill(0,SIGTTIN);
  1647.         }
  1648.         signal(SIGTTOU,SIG_IGN);
  1649.         signal(SIGTSTP,SIG_IGN);
  1650.         signal(SIGTTIN,SIG_IGN);
  1651.         signal(SIGPIPE,SIG_IGN);
  1652.     }
  1653.     return 0;
  1654. }
  1655.  
  1656. int bin_alias(name,argv,ops,func) /**/
  1657. char *name;char **argv;char *ops;int func;
  1658. {
  1659. struct alias *an;
  1660. struct asgment *asg;
  1661. int incm = !(ops['a'] || ops['g']),ret = 0;
  1662.  
  1663.     showflag = !incm;
  1664.     if (!*argv)
  1665.         listhtable(aliastab,(HFunc) printalias);
  1666.     else while (asg = getasg(*argv++))
  1667.         {
  1668.         if (asg->value)
  1669.             addhnode(ztrdup(asg->name),mkanode(ztrdup(asg->value),incm),
  1670.                 aliastab,freeanode);
  1671.         else if (an = (Alias) gethnode(asg->name,aliastab))
  1672.             printalias(asg->name,an);
  1673.         else
  1674.             ret = 1;
  1675.         }
  1676.     return ret;
  1677. }
  1678.  
  1679. /* print an alias; used with listhtable */
  1680.  
  1681. void printalias(s,a) /**/
  1682. char *s;struct alias *a;
  1683. {
  1684.     if (a->cmd >= 0 && !(showflag && a->cmd))
  1685.         printf("%s=%s\n",s,a->text);
  1686. }
  1687.  
  1688. /* print a param; used with listhtable */
  1689.  
  1690. void printparam(s,p) /**/
  1691. char *s;Param p;
  1692. {
  1693.     if (showflag > 0 && !(p->flags & showflag))
  1694.         return;
  1695.     if (!showflag)
  1696.         {
  1697.         int fgs = p->flags;
  1698.  
  1699.         if (fgs & PMFLAG_i) printf("integer ");
  1700.         if (fgs & PMFLAG_A) printf("array ");
  1701.         if (fgs & PMFLAG_L) printf("left justified %d ",p->ct);
  1702.         if (fgs & PMFLAG_R) printf("right justified %d ",p->ct);
  1703.         if (fgs & PMFLAG_Z) printf("zero filled %d ",p->ct);
  1704.         if (fgs & PMFLAG_l) printf("lowercase ");
  1705.         if (fgs & PMFLAG_u) printf("uppercase ");
  1706.         if (fgs & PMFLAG_r) printf("readonly ");
  1707.         if (fgs & PMFLAG_t) printf("tagged ");
  1708.         if (fgs & PMFLAG_x) printf("exported ");
  1709.         }
  1710.     if (showflag2)
  1711.         printf("%s\n",s);
  1712.     else
  1713.         {
  1714.         char *t,**u;
  1715.  
  1716.         printf("%s=",s);
  1717.         switch (p->flags & PMTYPE)
  1718.             {
  1719.             case PMFLAG_s:
  1720.                 if (p->gets.cfn && (t = p->gets.cfn(p)))
  1721.                     puts(t);
  1722.                 else
  1723.                     putchar('\n');
  1724.                 break;
  1725.             case PMFLAG_i: printf("%ld\n",p->gets.ifn(p)); break;
  1726.             case PMFLAG_A:
  1727.                 putchar('(');
  1728.                 u = p->gets.afn(p);
  1729.                 if (!*u)
  1730.                     printf(")\n");
  1731.                 else
  1732.                     {
  1733.                     while (u[1])
  1734.                         printf("%s ",*u++);
  1735.                     printf("%s)\n",*u);
  1736.                     }
  1737.                 break;
  1738.             }
  1739.         }
  1740. }
  1741.  
  1742. /* autoload, declare, export, functions, integer, local, readonly, typeset */
  1743.  
  1744. int bin_typeset(name,argv,ops,func) /**/
  1745. char *name;char **argv;char *ops;int func;
  1746. {
  1747. int on = 0,off = 0,roff,bit = 1,retcode = 0;
  1748. char *optstr = "LRZilurtx";
  1749. struct param *pm;
  1750. struct asgment *asg;
  1751.  
  1752.     for (; *optstr; optstr++,bit <<= 1)
  1753.         if (ops[*optstr] == 1)
  1754.             on |= bit;
  1755.         else if (ops[*optstr] == 2)
  1756.             off |= bit;
  1757.     roff = off;
  1758.     if (ops['f']) {
  1759.         on &= PMFLAG_t|PMFLAG_u;
  1760.         off &= PMFLAG_t|PMFLAG_u;
  1761.         showflag = (ops['f'] == 1);
  1762.         if (ops['@'] && ((off & ~PMFLAG_t) || (on & ~(PMFLAG_u|PMFLAG_t)))) {
  1763.             zerrnam(name,"invalid option(s)",NULL,0);
  1764.             return 1;
  1765.         }
  1766.         showflag2 = 0;
  1767.         if (!*argv) {
  1768.             showflag2 = off|on;
  1769.             listhtable(cmdnamtab,(HFunc) pshfunc);
  1770.         } else for (; *argv; argv++) {
  1771.             Cmdnam cc;
  1772.  
  1773.             if ((cc = (Cmdnam) gethnode(*argv,cmdnamtab)) && cc->type == SHFUNC)
  1774.                 if (on|off) cc->flags = (cc->flags | on) & (~off);
  1775.                 else pshfunc(*argv,cc);
  1776.             else if (on & PMFLAG_u) {
  1777.                 cc = (Cmdnam) zcalloc(sizeof *cc);
  1778.                 cc->type = SHFUNC;
  1779.                 cc->flags = on;
  1780.                 addhnode(ztrdup(*argv),cc,cmdnamtab,freecmdnam);
  1781.             } else
  1782.                 retcode = 1;
  1783.         }
  1784.         return retcode;
  1785.     }
  1786.     if (on & PMFLAG_L)
  1787.         off |= PMFLAG_R;
  1788.     if (on & PMFLAG_R)
  1789.         off |= PMFLAG_L;
  1790.     if (on & PMFLAG_u)
  1791.         off |= PMFLAG_l;
  1792.     if (on & PMFLAG_l)
  1793.         off |= PMFLAG_u;
  1794.     on &= ~off;
  1795.     showflag = showflag2 = 0;
  1796.     if (!*argv) {
  1797.         showflag = on|off;
  1798.         showflag2 = roff;
  1799.         listhtable(paramtab,(HFunc) printparam);
  1800.     } else while (asg = getasg(*argv++)) {
  1801.         if (asg->value && *asg->value == '~') {
  1802.             *asg->value = Tilde;
  1803.             singsub(&asg->value);
  1804.         }
  1805.         pm = (Param) gethnode(asg->name,paramtab);
  1806.         if (pm) {
  1807.             if (!on && !roff && !asg->value) {
  1808.                 printparam(asg->name,pm);
  1809.                 continue;
  1810.             }
  1811.             pm->flags = (pm->flags | on) & ~off;
  1812.             if ((on & (PMFLAG_L | PMFLAG_R | PMFLAG_Z | PMFLAG_i)) 
  1813.                     && (pmtype(pm) != PMFLAG_A))
  1814.                 pm->ct = auxlen;
  1815.             if (pmtype(pm) != PMFLAG_A) {
  1816.                 if (pm->flags & PMFLAG_x) {
  1817.                     if (!pm->env)
  1818.                         pm->env = addenv(asg->name,
  1819.                             (asg->value) ? asg->value : getsparam(asg->name));
  1820.                 } else if (pm->env) {
  1821.                     delenv(pm->env);
  1822.                     free(pm->env);
  1823.                     pm->env = NULL;
  1824.                 }
  1825.                 if (asg->value)
  1826.                     setsparam(asg->name,ztrdup(asg->value));
  1827.             }
  1828.         } else {
  1829.             if (locallist && !(on & PMFLAG_x)) {
  1830.                 permalloc();
  1831.                 addnode(locallist,ztrdup(asg->name));
  1832.                 heapalloc();
  1833.             }
  1834.             createparam(ztrdup(asg->name),
  1835.                 ztrdup((asg->value) ? asg->value : ""),on);
  1836.             pm = (Param) gethnode(asg->name,paramtab);
  1837.             pm->ct = auxlen;
  1838.         }
  1839.     }
  1840.     return 0;
  1841. }
  1842.  
  1843. /* convert s with escape sequences */
  1844.  
  1845. char *escsubst(s,nnl) /**/
  1846. char *s; int *nnl;
  1847. {
  1848. char *t = alloc(strlen(s)+1),*ret = t;
  1849.  
  1850.     for (; *s; s++)
  1851.         if (*s == '\\' && s[1])
  1852.             switch (*++s) {
  1853.                 case 'b': *t++ = '\b'; break;
  1854.                 case 'c': *nnl |= 1; break;
  1855.                 case 'e': *t++ = '\033'; break;
  1856.                 case 'f': *t++ = '\f'; break;
  1857.                 case 'n': *t++ = '\n'; break;
  1858.                 case 'r': *t++ = '\r'; break;
  1859.                 case 't': *t++ = '\t'; break;
  1860.                 case 'v': *t++ = '\v'; break;
  1861.                 case '\\': *t++ = '\\'; break;
  1862.                 case '0': *t++ = zstrtol(s,&s,8); s--; break;
  1863.                 default: *t++ = '\\'; *t++ = *s; break;
  1864.             }
  1865.         else *t++ = *s;
  1866.     *t = '\0';
  1867.     return ret;
  1868. }
  1869.  
  1870. /* echo, print, pushln */
  1871.  
  1872. int bin_print(name,args,ops,func) /**/
  1873. char *name;char **args;char *ops;int func;
  1874. {
  1875. int nnl = 0, fd;
  1876. Histent ent;
  1877. FILE *fout = stdout;
  1878.  
  1879.     if (ops['z']) {
  1880.         permalloc();
  1881.         pushnode(bufstack,ztrdup(spacejoin(args)));
  1882.         heapalloc();
  1883.         return 0;
  1884.     }
  1885.     if (ops['s']) {
  1886.         permalloc();
  1887.         ent = gethistent(++curhist);
  1888.         ent->lex = ztrdup(join(args,HISTSPACE));
  1889.         ent->lit = ztrdup(join(args,' '));
  1890.         ent->stim = ent->ftim = time(NULL);
  1891.         heapalloc();
  1892.         return 0;
  1893.     }
  1894.     if (ops['R'])
  1895.         ops['r'] = 1;
  1896.     if (ops['u'] || ops['p']) {
  1897.         if (ops['u']) {
  1898.             for (fd = 0; fd < 10; fd++) if (ops[fd+'0']) break;
  1899.             if (fd == 10) fd = 0;
  1900.         } else fd = coprocout;
  1901.         if ((fd = dup(fd)) < 0) {
  1902.             zerrnam(name,"bad file number",NULL,0);
  1903.             return 1;
  1904.         }
  1905.         if ((fout = fdopen(fd,"w")) == 0) {
  1906.             zerrnam(name,"bad mode on fd",NULL,0);
  1907.             return 1;
  1908.         }
  1909.     }
  1910.     for (; *args; args++) {
  1911.         if (!ops['r']) *args = escsubst(*args,&nnl);
  1912.         if (ops['D']) fprintdir(*args,fout);
  1913.         else if (ops['P']) {
  1914.             int junk;
  1915.             fputs(putprompt(*args,&junk),fout);
  1916.         } else fputs(*args,fout);
  1917.         if (args[1]) fputc(ops['l'] ? '\n' : ops['0'] ? '\0' : ' ',fout);
  1918.     }
  1919.     if (!(ops['n'] || nnl)) fputc(ops['N'] ? '\0' : '\n',fout);
  1920.     if (fout != stdout) fclose(fout);
  1921.     return 0;
  1922. }
  1923.  
  1924. int bin_dirs(name,argv,ops,func) /**/
  1925. char *name;char **argv;char *ops;int func;
  1926. {
  1927. Lklist l;
  1928.  
  1929.     if (ops['v'])
  1930.         {
  1931.         Lknode node;
  1932.         int t0 = 1;
  1933.  
  1934.         printf("0\t");
  1935.         printdir(pwd);
  1936.         for (node = firstnode(dirstack); node; incnode(node))
  1937.             {
  1938.             printf("\n%d\t",t0++);
  1939.             printdir(getdata(node));
  1940.             }
  1941.         putchar('\n');
  1942.         return 0;
  1943.         }
  1944.     if (!*argv)
  1945.         {
  1946.         pdstack();
  1947.         return 0;
  1948.         }
  1949.     permalloc();
  1950.     l = newlist();
  1951.     if (!*argv)
  1952.         {
  1953.         heapalloc();
  1954.         return 0;
  1955.         }
  1956.     while (*argv)
  1957.         addnode(l,ztrdup(*argv++));
  1958.     freetable(dirstack,freestr);
  1959.     dirstack = l;
  1960.     heapalloc();
  1961.     return 0;
  1962. }
  1963.  
  1964. int bin_unalias(name,argv,ops,func) /**/
  1965. char *name;char **argv;char *ops;int func;
  1966. {
  1967. int ret = 0;
  1968. vptr dat;
  1969.  
  1970.     while (*argv)
  1971.         {
  1972.         if (dat = remhnode(*argv++,aliastab))
  1973.             freeanode(dat);
  1974.         else
  1975.             ret = 1;
  1976.         }
  1977.     return ret;
  1978. }
  1979.  
  1980. int bin_disable(name,argv,ops,func) /**/
  1981. char *name;char **argv;char *ops;int func;
  1982. {
  1983. Cmdnam chn;
  1984.  
  1985.     while (*argv) {
  1986.         if (!strncmp(*argv,"TRAP",4))
  1987.             unsettrap(getsignum(*argv+4));
  1988.         chn = zalloc(sizeof *chn);
  1989.         chn->type = DISABLED;
  1990.         addhnode(ztrdup(*argv++),chn,cmdnamtab,freecmdnam);
  1991.     }
  1992.     return 0;
  1993. }
  1994.  
  1995. int bin_unhash(name,argv,ops,func) /**/
  1996. char *name;char **argv;char *ops;int func;
  1997. {
  1998. vptr dat;
  1999.  
  2000.     while (*argv) {
  2001.         if (!strncmp(*argv,"TRAP",4)) unsettrap(getsignum(*argv+4));
  2002.         if (dat = remhnode(*argv++,cmdnamtab)) freecmdnam(dat);
  2003.     }
  2004.     return 0;
  2005. }
  2006.  
  2007. int bin_unset(name,argv,ops,func) /**/
  2008. char *name;char **argv;char *ops;int func;
  2009. {
  2010. int retval = 0;
  2011. char *s;
  2012.  
  2013.     while (s = *argv++)
  2014.         if (gethnode(s,paramtab))
  2015.             unsetparam(s);
  2016.         else
  2017.             retval = 1;
  2018.     return retval;
  2019. }
  2020.  
  2021. static char *zbuf;
  2022. static int readfd;
  2023.  
  2024. int zread() /**/
  2025. {
  2026. char cc;
  2027.  
  2028.     if (zbuf)
  2029.         return (*zbuf) ? *zbuf++ : EOF;
  2030.     if (read(readfd,&cc,1) != 1)
  2031.         return EOF;
  2032.     return cc;
  2033. }
  2034.  
  2035. int bin_read(name,args,ops,func) /**/
  2036. char *name;char **args;char *ops;int func;
  2037. {
  2038. char *reply,*pmpt;
  2039. int bsiz,c,gotnl = 0;
  2040. char *buf,*bptr;
  2041.  
  2042.     reply = (*args) ? *args++ : "REPLY";
  2043.     if (ops['u'] && !ops['p']) {
  2044.         for (readfd = 0; readfd < 10; ++readfd) if (ops[readfd+'0']) break;
  2045.         if (readfd == 10) readfd = 0;
  2046.     } else if (ops['p']) readfd = coprocin;
  2047.     else {
  2048.         attachtty((jobtab[thisjob].gleader) ? jobtab[thisjob].gleader : mypgrp);
  2049.         readfd = 0;
  2050.         if (isatty(0)) {
  2051.             for (pmpt = reply; *pmpt && *pmpt != '?'; pmpt++);
  2052.             if (*pmpt++) {
  2053.                 write(2,pmpt,strlen(pmpt));
  2054.                 pmpt[-1] = '\0';
  2055.             }
  2056.         }
  2057. #if 0
  2058.         else if (isset(SHINSTDIN) && unset(INTERACTIVE)) {
  2059.             if (isatty(1)) readfd = 1;
  2060.             else if (isatty(2)) readfd = 2;
  2061.         }
  2062. #endif
  2063.     }
  2064.     zbuf = (!ops['z']) ? NULL :
  2065.         (full(bufstack)) ? (char *) getnode(bufstack) : NULL;
  2066.     while (*args) {
  2067.         buf = bptr = zalloc(bsiz = 64);
  2068. redo:
  2069.         for(;;) {
  2070.             if (gotnl) break;
  2071.             c = zread();
  2072.             if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
  2073.                 bptr--;
  2074.                 continue;
  2075.             }
  2076.             if (c == EOF || isep(c) || c == '\n') break;
  2077.             *bptr++ = c;
  2078.             if (bptr == buf+bsiz) {
  2079.                 buf = realloc(buf,bsiz *= 2);
  2080.                 bptr = buf+(bsiz/2);
  2081.             }
  2082.         }
  2083.         if (c == EOF) {
  2084.             if (readfd == coprocin) {
  2085.                 close(coprocin);
  2086.                 close(coprocout);
  2087.                 coprocin = coprocout = -1;
  2088.             }
  2089.             return 1;
  2090.         }
  2091.         if (c == '\n') gotnl = 1;
  2092.         if (bptr == buf) goto redo;
  2093.         *bptr = '\0';
  2094.         setsparam(reply,buf);
  2095.         reply = *args++;
  2096.     }
  2097.     buf = bptr = zalloc(bsiz = 64);
  2098.     if (!gotnl)
  2099.         for (;;) {
  2100.             c = zread();
  2101.             if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
  2102.                 bptr--;
  2103.                 continue;
  2104.             }
  2105.             if (c == EOF || (c == '\n' && !zbuf)) break;
  2106.             *bptr++ = c;
  2107.             if (bptr == buf+bsiz) {
  2108.                 buf = realloc(buf,bsiz *= 2);
  2109.                 bptr = buf+(bsiz/2);
  2110.             }
  2111.         }
  2112.     *bptr = '\0';
  2113.     setsparam(reply,buf);
  2114.     if (c == EOF) {
  2115.         if (readfd == coprocin) {
  2116.             close(coprocin);
  2117.             close(coprocout);
  2118.             coprocin = coprocout = -1;
  2119.         }
  2120.         return 1;
  2121.     }
  2122.     return 0;
  2123. }
  2124.  
  2125. int bin_vared(name,args,ops,func) /**/
  2126. char *name;char **args;char *ops;int func;
  2127. {
  2128. char *s;char *t;
  2129. struct param *pm;
  2130.  
  2131.     if (!(s = getsparam(args[0]))) {
  2132.         zerrnam(name,"no such variable: %s",args[0],0);
  2133.         return 1;
  2134.     }
  2135.     permalloc();
  2136.     pushnode(bufstack,ztrdup(s));
  2137.     heapalloc();
  2138.     t = (char *) zleread((unsigned char *)"> ",NULL,2);
  2139.     if (!t || errflag)
  2140.         return 1;
  2141.     if (t[strlen(t)-1] == '\n')
  2142.         t[strlen(t)-1] = '\0';
  2143.     pm = gethnode(args[0],paramtab);
  2144.     if (pmtype(pm) == PMFLAG_A)
  2145.         setaparam(args[0],spacesplit(t));
  2146.     else
  2147.         setsparam(args[0],t);
  2148.     return 0;
  2149. }
  2150.  
  2151. #define fset(X) (flags & X)
  2152.  
  2153. /* execute a builtin handler function after parsing the arguments */
  2154.  
  2155. int execbin(args,cnode) /**/
  2156. Lklist args;Cmdnam cnode;
  2157. {
  2158. struct bincmd *b;
  2159. char ops[128],*arg,*pp,*name,**argv,**oargv,*optstr;
  2160. int t0,flags,sense,argc = 0,op;
  2161. Lknode n;
  2162.  
  2163.     auxdata = NULL;
  2164.     auxlen = 0;
  2165.     for (t0 = 0; t0 != 128; t0++)
  2166.         ops[t0] = 0;
  2167.     name = ugetnode(args);
  2168.     b = builtins+cnode->u.binnum;
  2169.  
  2170. /* the 'builtin' builtin is handled specially */
  2171.  
  2172.     if (b->funcid == BIN_BUILTIN)
  2173.         {
  2174.         if (!(name = ugetnode(args)))
  2175.             {
  2176.             zerrnam("builtin","command name expected",NULL,0);
  2177.             return 1;
  2178.             }
  2179.         for (t0 = 0, b = builtins; b->name; b++,t0++)
  2180.             if (!strcmp(name,b->name))
  2181.                 break;
  2182.         if (!b->name)
  2183.             {
  2184.             zerrnam("builtin","no such builtin: %s",name,0);
  2185.             return 1;
  2186.             }
  2187.         }
  2188.     flags = b->flags;
  2189.     arg = ugetnode(args);
  2190.     optstr = b->optstr;
  2191.     if (flags & BINF_ECHOPTS && arg && strcmp(arg,"-n"))
  2192.         optstr = NULL;
  2193.     if (optstr)
  2194.         while (arg &&
  2195.                 ((sense = *arg == '-') || fset(BINF_PLUSOPTS) && *arg == '+') &&
  2196.                 (fset(BINF_PLUSOPTS) || !atoi(arg)))
  2197.             {
  2198.             pp = arg;
  2199.             if (arg[1] == '-')
  2200.                 arg++;
  2201.             if (!arg[1])
  2202.                 {
  2203.                 ops['-'] = 1;
  2204.                 if (!sense)
  2205.                     ops['+'] = 1;
  2206.                 }
  2207.             else
  2208.                 ops['@'] = 1;
  2209.             op = -1;
  2210.             while (*++arg)
  2211.                 if (strchr(b->optstr,op = *arg))
  2212.                     ops[*arg] = (sense) ? 1 : 2;
  2213.                 else
  2214.                     break;
  2215.             if (*arg)
  2216.                 {
  2217.                 zerr("bad option: %c",NULL,*arg);
  2218.                 return 1;
  2219.                 }
  2220.             arg = ugetnode(args);
  2221.             if (fset(BINF_SETOPTS) && op == 'o')
  2222.                 {
  2223.                 int c;
  2224.                 
  2225.                 if (!arg)
  2226.                     prtopt();
  2227.                 else
  2228.                     {
  2229.                     c = optlookup(arg);
  2230.                     if (c == -1)
  2231.                         {
  2232.                         zerr("bad option: %s",arg,0);
  2233.                         return 1;
  2234.                         }
  2235.                     else
  2236.                         {
  2237.                         ops[c] = ops['o'];
  2238.                         arg = ugetnode(args);
  2239.                         }
  2240.                     }
  2241.                 }
  2242.             if ((fset(BINF_PRINTOPTS) && ops['R']) || ops['-'])
  2243.                 break;
  2244.             if (fset(BINF_SETOPTS) && ops['A'])
  2245.                 {
  2246.                 auxdata = arg;
  2247.                 arg = ugetnode(args);
  2248.                 break;
  2249.                 }
  2250.             if (fset(BINF_FCOPTS) && op == 'e')
  2251.                 {
  2252.                 auxdata = arg;
  2253.                 arg = ugetnode(args);
  2254.                 }
  2255.             if (fset(BINF_TYPEOPT) && (op == 'L' || op == 'R' ||
  2256.                     op == 'Z' || op == 'i') && arg && idigit(*arg))
  2257.                 {
  2258.                 auxlen = atoi(arg);
  2259.                 arg = ugetnode(args);
  2260.                 }
  2261.             }
  2262.     if (fset(BINF_R))
  2263.         auxdata = "-";
  2264.     if (pp = b->defopts)
  2265.         while (*pp)
  2266.             ops[*pp++] = 1;
  2267.     if (arg)
  2268.         {
  2269.         argc = 1;
  2270.         n = firstnode(args);
  2271.         while (n)
  2272.             argc++,incnode(n);
  2273.         }
  2274.     oargv = argv = (char **) ncalloc(sizeof(char **) * (argc+1));
  2275.     if (*argv++ = arg)
  2276.         while (*argv++ = ugetnode(args));
  2277.     argv = oargv;
  2278.     if (errflag)
  2279.         return 1;
  2280.     if (argc < b->minargs || (argc > b->maxargs && b->maxargs != -1)) {
  2281.         zerrnam(name,(argc < b->minargs)
  2282.             ? "not enough arguments" : "too many arguments",NULL,0);
  2283.         return 1;
  2284.     }
  2285.     if (isset(XTRACE)) {
  2286.         char **pp = argv;
  2287.         fprintf(stderr,"%s%s",(prompt4) ? prompt4 : "",name);
  2288.         while (*pp) fprintf(stderr," %s",*pp++);
  2289.         fputc('\n',stderr);
  2290.         fflush(stderr);
  2291.     }
  2292.     return (*(b->handlerfunc))(name,argv,ops,b->funcid);
  2293. }
  2294.  
  2295. struct asgment *getasg(s) /**/
  2296. char *s;
  2297. {
  2298. static struct asgment asg;
  2299.  
  2300.     if (!s)
  2301.         return NULL;
  2302.     if (*s == '=')
  2303.         {
  2304.         zerr("bad assignment",NULL,0);
  2305.         return NULL;
  2306.         }
  2307.     asg.name = s;
  2308.     for (; *s && *s != '='; s++);
  2309.     if (*s)
  2310.         {
  2311.         *s = '\0';
  2312.         asg.value = s+1;
  2313.         }
  2314.     else
  2315.         asg.value = NULL;
  2316.     return &asg;
  2317. }
  2318.  
  2319. /* ., source */
  2320.  
  2321. int bin_dot(name,argv,ops,func) /**/
  2322. char *name;char **argv;char *ops;int func;
  2323. {
  2324. char **old,*old0;
  2325. int ret;
  2326. char buf[MAXPATHLEN];
  2327. char *s,**t,*enam;
  2328.  
  2329.     if (!*argv)
  2330.         return 0;
  2331.     old = pparams;
  2332.     old0 = argzero;
  2333.     if (argv[1]) {
  2334.         permalloc();
  2335.         pparams = arrdup(argv+1);
  2336.         heapalloc();
  2337.     }
  2338.     enam = argzero = ztrdup(*argv);
  2339.     errno = ENOENT;
  2340.     ret = 1;
  2341.     for (s = argzero; *s; s++)
  2342.         if (*s == '/') {
  2343.             ret = source(argzero);
  2344.             break;
  2345.         }
  2346.     if (!*s) {
  2347.         for (t = path; *t; t++)
  2348.             if ((*t)[0] == '.' && !(*t)[1]) {
  2349.                 ret = source(argzero);
  2350.                 break;
  2351.             } else {
  2352.                 sprintf(buf,"%s/%s",*t,argzero);
  2353.                 if (access(buf,F_OK) == 0) {
  2354.                     ret = source(enam = buf);
  2355.                     break;
  2356.                 }
  2357.             }
  2358.         if (!*t && access(argzero,F_OK) == 0)
  2359.             ret = source(enam = argzero);
  2360.     }
  2361.     if (argv[1]) {
  2362.         freearray(pparams);
  2363.         pparams = old;
  2364.     }
  2365.     if (ret) zerrnam(name,"%e: %s",enam,errno);
  2366.     free(argzero);
  2367.     argzero = old0;
  2368.     return ret;
  2369. }
  2370.  
  2371. int bin_set(name,argv,ops,func) /**/
  2372. char *name;char **argv;char *ops;int func;
  2373. {
  2374. struct option *opp;
  2375. char **x;
  2376.  
  2377.     if (((ops['+'] && ops['-']) || !ops['-']) && !ops['@'] && !*argv)
  2378.         {
  2379.         showflag = ~0;
  2380.         showflag2 = ops['+'];
  2381.         listhtable(paramtab,(HFunc) printparam);
  2382.         }
  2383.    for (opp = optns; opp->name; opp++)
  2384.       if (ops[opp->id] == 1)
  2385.          opts[opp->id] = OPT_SET;
  2386.       else if (ops[opp->id] == 2)
  2387.          opts[opp->id] = OPT_UNSET;
  2388.     if (!*argv && !ops['-'])
  2389.         return 0;
  2390.     permalloc();
  2391.     x = arrdup(argv);
  2392.     heapalloc();
  2393.     if (ops['A'])
  2394.         setaparam(auxdata,x);
  2395.     else {
  2396.         freearray(pparams);
  2397.         pparams = x;
  2398.     }
  2399.     return 0;
  2400. }
  2401.  
  2402. #define pttime(X) printf("%dm%ds",(X)/3600,(X)/60%60)
  2403.  
  2404. int bin_times(name,argv,ops,func) /**/
  2405. char *name;char **argv;char *ops;int func;
  2406. {
  2407. struct tms buf;
  2408.  
  2409.     if (times(&buf) == -1)
  2410.         return 1;
  2411.     pttime(buf.tms_utime);
  2412.     putchar(' ');
  2413.     pttime(buf.tms_stime);
  2414.     putchar('\n');
  2415.     pttime(buf.tms_cutime);
  2416.     putchar(' ');
  2417.     pttime(buf.tms_cstime);
  2418.     putchar('\n');
  2419.     return 0;
  2420. }
  2421.  
  2422. int bin_getopts(name,argv,ops,func) /**/
  2423. char *name;char **argv;char *ops;int func;
  2424. {
  2425. char *optstr = *argv++,*var = *argv++;
  2426. char **args = (*argv) ? argv : pparams;
  2427. static int optcind = 1,quiet;
  2428. char *str,optbuf[3],*opch = optbuf+1;
  2429.  
  2430.     if (zoptind < 1) zoptind = 1;
  2431.     optbuf[0] = '+'; optbuf[1] = optbuf[2] = '\0';
  2432.     if (optarg) free(optarg);
  2433.     optarg = ztrdup("");
  2434.     setsparam(var,ztrdup(""));
  2435.     if (*optstr == ':') {
  2436.         quiet = 1;
  2437.         optstr++;
  2438.     }
  2439.     if (zoptind > arrlen(args)) return 1;
  2440.     str = args[zoptind-1];
  2441.     if (*str != '+' && *str != '-' || optcind >= strlen(str) ||
  2442.             !strcmp("--",str)) {
  2443.         if (*str == '+' || *str == '-')
  2444.             zoptind++;
  2445.         optcind = 0;
  2446.         return 1;
  2447.     }
  2448.     if (!optcind)
  2449.         optcind = 1;
  2450.     *opch = str[optcind++];
  2451.     if (!args[zoptind-1][optcind]) {
  2452.         zoptind++;
  2453.         optcind = 0;
  2454.     }
  2455.     for (; *optstr; optstr++)
  2456.         if (*opch == *optstr)
  2457.             break;
  2458.     if (!*optstr) {
  2459.         setsparam(var,ztrdup("?"));
  2460.         if (quiet) {
  2461.             free(optarg); optarg = ztrdup(opch);
  2462.             return 0;
  2463.         }
  2464.         zerr("bad option: %c",NULL,*opch); errflag = 0;
  2465.         return 0;
  2466.     }
  2467.     setsparam(var,ztrdup(opch-(*str == '+')));
  2468.     if (optstr[1] == ':') {
  2469.         if (!args[zoptind-1]) {
  2470.             if (quiet) {
  2471.                 free(optarg); optarg = ztrdup(opch);
  2472.                 setsparam(var,ztrdup(":"));
  2473.                 return 0;
  2474.             }
  2475.             setsparam(var,ztrdup("?"));
  2476.             zerr("argument expected after %c option",NULL,*opch); errflag = 0;
  2477.             return 0;
  2478.         }
  2479.         free(optarg);
  2480.         optarg = ztrdup(args[zoptind-1]+optcind);
  2481.         zoptind++;
  2482.         optcind = 0;
  2483.     }
  2484.     return 0;
  2485. }
  2486.  
  2487. /* get a signal number from a string */
  2488.  
  2489. int getsignum(s) /**/
  2490. char *s;
  2491. {
  2492. int x = atoi(s),t0;
  2493.  
  2494.     if (idigit(*s) && x >= 0 && x < VSIGCOUNT)
  2495.         return x;
  2496.     for (t0 = 0; t0 != VSIGCOUNT; t0++)
  2497.         if (!strcmp(s,sigs[t0]))
  2498.             return t0;
  2499.     return -1;
  2500. }
  2501.  
  2502. int bin_trap(name,argv,ops,func) /**/
  2503. char *name;char **argv;char *ops;int func;
  2504. {
  2505. List l;
  2506. char *arg;
  2507.  
  2508.     if (!*argv) {
  2509.         int t0;
  2510.  
  2511.         for (t0 = 0; t0 != VSIGCOUNT; t0++)
  2512.             if (sigtrapped[t0])
  2513.                 if (!sigfuncs[t0])
  2514.                     printf("TRAP%s () {}\n",sigs[t0]);
  2515.                 else {
  2516.                     char *s = getpermtext((vptr) sigfuncs[t0]);
  2517.                     printf("TRAP%s () {\n\t%s\n}\n",sigs[t0],s);
  2518.                     free(s);
  2519.                 }
  2520.         return 0;
  2521.     }
  2522.     if (!strcmp(*argv,"-")) {
  2523.         int t0;
  2524.  
  2525.         argv++;
  2526.         if (!*argv)
  2527.             for (t0 = 0; t0 != VSIGCOUNT; t0++) unsettrap(t0);
  2528.         else
  2529.             while (*argv) unsettrap(getsignum(*argv++));
  2530.         return 0;
  2531.     }
  2532.     arg = *argv++;
  2533.     if (!*arg) l = NULL;
  2534.     else if (!(l = parselstring(arg))) {
  2535.         zerrnam(name,"couldn't parse trap command",NULL,0);
  2536.         popheap();
  2537.         return 1;
  2538.     }
  2539.     for (; *argv; argv++) {
  2540.         int sg = getsignum(*argv);
  2541.         if (sg == -1) {
  2542.             zerrnam(name,"undefined signal: %s",*argv,0);
  2543.             break;
  2544.         }
  2545.         settrap(sg,l);
  2546.     }
  2547.     if (l) popheap();
  2548.     return errflag;
  2549. }
  2550.  
  2551. void printulimit(lim,hard) /**/
  2552. int lim;int hard;
  2553. {
  2554. long t0;
  2555.  
  2556. #ifdef RLIM_INFINITY
  2557.     t0 = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
  2558.     switch (lim)
  2559.         {
  2560.         case RLIMIT_CPU: printf("cpu time (seconds)         "); break;
  2561.         case RLIMIT_FSIZE: printf("file size (blocks)         "); t0 /= 512; break;
  2562.         case RLIMIT_DATA: printf("data seg size (kbytes)     "); t0 /= 1024; break;
  2563.         case RLIMIT_STACK: printf("stack size (kbytes)        "); t0 /= 1024; break;
  2564.         case RLIMIT_CORE: printf("core file size (blocks)    "); t0 /= 512; break;
  2565. #ifdef RLIMIT_RSS
  2566.         case RLIMIT_RSS: printf("resident set size (kbytes) "); t0 /= 1024; break;
  2567. #endif
  2568. #ifdef RLIMIT_NOFILE
  2569.         case RLIMIT_NOFILE: printf("file descriptors           "); break;
  2570. #endif
  2571.         }
  2572.     printf("%ld\n",t0);
  2573. #endif
  2574. }
  2575.  
  2576. int bin_ulimit(name,argv,ops,func) /**/
  2577. char *name;char **argv;char *ops;int func;
  2578. {
  2579. int res,hard;
  2580.  
  2581. #ifndef RLIM_INFINITY
  2582.     zerrnam(name,"not available on this system",NULL,0);
  2583.     return 1;
  2584. #else
  2585.     hard = ops['H'];
  2586.     if (ops['a'] || !ops['@'])
  2587.         res = -1;
  2588.     else if (ops['t'])
  2589.         res = RLIMIT_CPU;
  2590.     else if (ops['f'])
  2591.         res = RLIMIT_FSIZE;
  2592.     else if (ops['d'])
  2593.         res = RLIMIT_DATA;
  2594.     else if (ops['s'])
  2595.         res = RLIMIT_STACK;
  2596.     else if (ops['c'])
  2597.         res = RLIMIT_CORE;
  2598. #ifdef RLIMIT_RSS
  2599.     else if (ops['m'])
  2600.         res = RLIMIT_RSS;
  2601. #endif
  2602. #ifdef RLIMIT_NOFILE
  2603.     else if (ops['n'])
  2604.         res = RLIMIT_NOFILE;
  2605. #endif
  2606.     else
  2607.         {
  2608.         zerrnam(name,"no such limit",NULL,0);
  2609.         return 1;
  2610.         }
  2611.     if (res == -1)
  2612.         if (*argv)
  2613.             {
  2614.             zerrnam(name,"no arguments required after -a",NULL,0);
  2615.             return 1;
  2616.             }
  2617.         else
  2618.             {
  2619.             int t0;
  2620.  
  2621.             for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  2622.                 printulimit(t0,hard);
  2623.             return 0;
  2624.             }
  2625.     if (!*argv)
  2626.         printulimit(res,hard);
  2627.     else if (strcmp(*argv,"unlimited"))
  2628.         {
  2629.         long t0;
  2630.         
  2631.         t0 = atol(*argv);
  2632.         switch(res)
  2633.             {
  2634.             case RLIMIT_FSIZE: case RLIMIT_CORE: t0 *= 512; break;
  2635.             case RLIMIT_DATA: case RLIMIT_STACK:
  2636. #ifdef RLIMIT_RSS
  2637.             case RLIMIT_RSS:
  2638. #endif
  2639.                 t0 *= 1024; break;
  2640.             }
  2641.         if (hard)
  2642.             {
  2643.             if (t0 > limits[res].rlim_max && geteuid())
  2644.                 {
  2645.                 zerrnam(name,"can't raise hard limits",NULL,0);
  2646.                 return 1;
  2647.                 }
  2648.             limits[res].rlim_max = t0;
  2649.             }
  2650.         else
  2651.             {
  2652.             if (t0 > limits[res].rlim_max)
  2653.                 {
  2654.                 if (geteuid())
  2655.                     {
  2656.                     zerrnam(name,"value exceeds hard limit",NULL,0);
  2657.                     return 1;
  2658.                     }
  2659.                 limits[res].rlim_max = limits[res].rlim_cur = t0;
  2660.                 }
  2661.             else
  2662.                 limits[res].rlim_cur = t0;
  2663.             }
  2664.         }
  2665.     else
  2666.         {
  2667.         if (hard)
  2668.             {
  2669.             if (geteuid())
  2670.                 {
  2671.                 zerrnam(name,"can't remove hard limits",NULL,0);
  2672.                 return 1;
  2673.                 }
  2674.             limits[res].rlim_max = RLIM_INFINITY;
  2675.             }
  2676.         else
  2677.             limits[res].rlim_cur = limits[res].rlim_max;
  2678.         }
  2679.     return 0;
  2680. #endif
  2681. }
  2682.  
  2683. int putraw(c) /**/
  2684. int c;
  2685. {
  2686.     putchar(c);
  2687.     return 0;
  2688. }
  2689.  
  2690. int bin_echotc(name,argv,ops,func) /**/
  2691. char *name;char **argv;char *ops;int func;
  2692. {
  2693. char *s,buf[2048],*t,*u;
  2694. int num,argct,t0;
  2695.  
  2696.     s = *argv++;
  2697.     if (!termok)
  2698.         return 1;
  2699.     if ((num = tgetnum(s)) != -1)
  2700.         {
  2701.         printf("%d\n",num);
  2702.         return 0;
  2703.         }
  2704.     u = buf;
  2705.     t = tgetstr(s,&u);
  2706.     if (!t || !*t)
  2707.         {
  2708.         zerrnam(name,"no such capability: %s",s,0);
  2709.         return 1;
  2710.         }
  2711.     for (argct = 0, u = t; *u; u++)
  2712.         if (*u == '%')
  2713.             {
  2714.             if (u++, (*u == 'd' || *u == '2' || *u == '3' || *u == '.' ||
  2715.                     *u == '+'))
  2716.                 argct++;
  2717.             }
  2718.     if (arrlen(argv) != argct)
  2719.         {
  2720.         zerrnam(name,(arrlen(argv) < argct) ? "not enough arguments" :
  2721.             "too many arguments",NULL,0);
  2722.         return 1;
  2723.         }
  2724.     if (!argct)
  2725.         tputs(t,1,putraw);
  2726.     else
  2727.         {
  2728.         t0 = (argv[1]) ? atoi(argv[1]) : atoi(*argv);
  2729.         tputs(tgoto(t,atoi(*argv),t0),t0,putraw);
  2730.         }
  2731.     return 0;
  2732. }
  2733.  
  2734. int bin_pwd(name,argv,ops,func) /**/
  2735. char *name;char **argv;char *ops;int func;
  2736. {
  2737.     printf("%s\n",pwd);
  2738.     return 0;
  2739. }
  2740.  
  2741. #define TEST_END 0
  2742. #define TEST_INPAR 1
  2743. #define TEST_OUTPAR 2
  2744. #define TEST_STR 3
  2745. #define TEST_AND 4
  2746. #define TEST_OR 5
  2747. #define TEST_NOT 6
  2748.  
  2749. static char **tsp;
  2750. static int *tip;
  2751.  
  2752. int bin_test(name,argv,ops,func) /**/
  2753. char *name;char **argv;char *ops;int func;
  2754. {
  2755. char **s;
  2756. int cnt,*arr,*ap;
  2757. Cond c;
  2758.  
  2759.     if (func == BIN_BRACKET)
  2760.         {
  2761.         for (s = argv; *s; s++);
  2762.         if (s == argv || strcmp(s[-1],"]"))
  2763.             {
  2764.             zerrnam(name,"']' expected",NULL,0);
  2765.             return 1;
  2766.             }
  2767.         s[-1] = NULL;
  2768.         }
  2769.     for (s = argv, cnt = 0; *s; s++,cnt++);
  2770.     ap = arr = alloc((cnt+1)*sizeof *arr);
  2771.     for (s = argv; *s; s++,ap++)
  2772.         if (!strcmp(*s,"("))
  2773.             *ap = TEST_INPAR;
  2774.         else if (!strcmp(*s,")"))
  2775.             *ap = TEST_OUTPAR;
  2776.         else if (!strcmp(*s,"-a"))
  2777.             *ap = TEST_AND;
  2778.         else if (!strcmp(*s,"-o"))
  2779.             *ap = TEST_OR;
  2780.         else if (!strcmp(*s,"!"))
  2781.             *ap = TEST_NOT;
  2782.         else
  2783.             *ap = TEST_STR;
  2784.     *ap = TEST_END;
  2785.     tsp = argv;
  2786.     tip = arr;
  2787.     c = partest(0);
  2788.     if (*tip != TEST_END || errflag)
  2789.         {
  2790.         zerrnam(name,"parse error",NULL,0);
  2791.         return 1;
  2792.         }
  2793.     return (c) ? !evalcond(c) : 1;
  2794. }
  2795.  
  2796. Cond partest(level) /**/
  2797. int level;
  2798. {
  2799. Cond a,b;
  2800.  
  2801.     switch (level)
  2802.         {
  2803.         case 0:
  2804.             a = partest(1);
  2805.             if (*tip == TEST_OR)
  2806.                 {
  2807.                 tip++,tsp++;
  2808.                 b = makecond();
  2809.                 b->left = a;
  2810.                 b->right = partest(0);
  2811.                 b->type = COND_OR;
  2812.                 return b;
  2813.                 }
  2814.             return a;
  2815.         case 1:
  2816.             a = partest(2);
  2817.             if (*tip == TEST_AND)
  2818.                 {
  2819.                 tip++,tsp++;
  2820.                 b = makecond();
  2821.                 b->left = a;
  2822.                 b->right = partest(1);
  2823.                 b->type = COND_AND;
  2824.                 return b;
  2825.                 }
  2826.             return a;
  2827.         case 2:
  2828.             if (*tip == TEST_NOT)
  2829.                 {
  2830.                 tip++,tsp++;
  2831.                 b = makecond();
  2832.                 b->left = partest(2);
  2833.                 b->type = COND_NOT;
  2834.                 return b;
  2835.                 }
  2836.         case 3:
  2837.             if (*tip == TEST_INPAR)
  2838.                 {
  2839.                 tip++,tsp++;
  2840.                 b = partest(0);
  2841.                 if (*tip != TEST_OUTPAR)
  2842.                     {
  2843.                     zerrnam("test","parse error",NULL,0);
  2844.                     return NULL;
  2845.                     }
  2846.                 tip++,tsp++;
  2847.                 return b;
  2848.                 }
  2849.             if (tip[0] != TEST_STR)
  2850.                 {
  2851.                 zerrnam("test","parse error",NULL,0);
  2852.                 return NULL;
  2853.                 }
  2854.             else if (tip[1] != TEST_STR)
  2855.                 {
  2856.                 b = makecond();
  2857.                 if (!strcmp(*tsp,"-t"))
  2858.                     {
  2859.                     b->left = strdup("1");
  2860.                     b->type = 't';
  2861.                     }
  2862.                 else
  2863.                     {
  2864.                     b->left = tsp[0];
  2865.                     b->type = 'n';
  2866.                     }
  2867.                 tip++,tsp++;
  2868.                 return b;
  2869.                 }
  2870.             else if (tip[2] != TEST_STR)
  2871.                 {
  2872.                 b = par_cond_double(tsp[0],tsp[1]);
  2873.                 tip += 2,tsp += 2;
  2874.                 return b;
  2875.                 }
  2876.             else
  2877.                 {
  2878.                 b = par_cond_triple(tsp[0],tsp[1],tsp[2]);
  2879.                 tip += 3,tsp += 3;
  2880.                 return b;
  2881.                 }
  2882.         }
  2883.    return NULL;
  2884. }
  2885.  
  2886. int bin_compctl(name,argv,ops,func) /**/
  2887. char *name;char **argv;char *ops;int func;
  2888. {
  2889. int flags = 0;
  2890. Compctl cc = NULL;
  2891. char *usrkeys = NULL;
  2892.  
  2893.     for (; *argv && **argv == '-'; argv++)
  2894.         while (*++(*argv)) switch(**argv) {
  2895.         case 'c': flags |= CC_COMMPATH; break;
  2896.         case 'f': flags |= CC_FILES; break;
  2897.         case 'h': flags |= CC_HOSTS; break;
  2898.         case 'o': flags |= CC_OPTIONS; break;
  2899.         case 'v': flags |= CC_VARS; break;
  2900.         case 'b': flags |= CC_BINDINGS; break;
  2901.         case 'k':
  2902.             flags |= CC_USRKEYS;
  2903.             if ((*argv)[1]) { usrkeys = (*argv)+1; *argv = ""-1; }
  2904.             else if (!argv[1]) {
  2905.                 zerrnam(name,"variable name expected after -k",NULL,0);
  2906.                 return 1;
  2907.             } else { usrkeys = *++argv; *argv = ""-1; }
  2908.             break;
  2909.         case 'C': cc = &cc_compos; break;
  2910.         case 'D': cc = &cc_default; break;
  2911.         default: zerrnam(name,"bad option: %c",NULL,**argv); return 1;
  2912.         }
  2913.     if (cc) {
  2914.         cc->mask = flags;
  2915.         if (cc->keyvar) free(cc->keyvar);
  2916.         cc->keyvar  = ztrdup(usrkeys);
  2917.     }
  2918.     if (!*argv) {
  2919.         if (!cc) {
  2920.             showflag = flags;
  2921.             listhtable(compctltab,(HFunc) printcompctl);
  2922.             printcompctl("COMMAND",&cc_compos);
  2923.             printcompctl("DEFAULT",&cc_default);
  2924.         }
  2925.         return 0;
  2926.     }
  2927.     compctl_process(argv,flags,usrkeys);
  2928.     return 0;
  2929. }
  2930.  
  2931. void printcompctl(s,cc) /**/
  2932. char *s;Compctl cc;
  2933. {
  2934. char *css = "fchovb";
  2935.  
  2936.     if (cc->mask & showflag) {
  2937.         puts(s);
  2938.     } else if (!showflag) {
  2939.         int flags = cc->mask;
  2940.         printf("%s -",s);
  2941.         while (*css) {
  2942.             if (flags & 1) putchar(*css);
  2943.             css++; flags >>= 1;
  2944.         }
  2945.         if (flags & 1) printf("k %s",cc->keyvar);
  2946.         putchar('\n');
  2947.     }
  2948. }
  2949.  
  2950. void compctl_process(s,mask,uk) /**/
  2951. char **s;int mask;char *uk;
  2952. {
  2953. Compctl cc;
  2954.  
  2955.     for (;*s;s++) {
  2956.         cc = zalloc(sizeof *cc);
  2957.         cc->mask = mask; cc->keyvar = ztrdup(uk);
  2958.         addhnode(ztrdup(*s),cc,compctltab,freecompctl);
  2959.     }
  2960. }
  2961.  
  2962. int bin_ttyctl(name,argv,ops,func) /**/
  2963. char *name;char **argv;char *ops;int func;
  2964. {
  2965.     if (ops['f'] || !ops['@']) ttyfrozen = 1;
  2966.     else if (ops['u']) ttyfrozen = 0;
  2967.     return 0;
  2968. }
  2969.  
  2970.