home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / ssh-1.7 / part03 / shcmds.c
Encoding:
C/C++ Source or Header  |  1993-04-15  |  37.5 KB  |  1,891 lines

  1. /* $Copyright:    $
  2.  * Copyright (c) 1991,1992,1993 by Steve Baker
  3.  * All rights reserved
  4.  *  
  5.  * This software is provided as is without any express or implied
  6.  * warranties, including, without limitation, the implied warranties
  7.  * of merchantability and fitness for a particular purpose.
  8.  */
  9. #include <errno.h>
  10. #include <ctype.h>
  11. #include "shell.h"
  12. #include "cmds.h"
  13.  
  14. struct Limits {
  15.   char *resource;
  16.   long val;
  17. } limits[6] = {
  18.   "cpu",RLIMIT_CPU,
  19.   "filesize",RLIMIT_FSIZE,
  20.   "datasize",RLIMIT_DATA,
  21.   "stacksize",RLIMIT_STACK,
  22.   "coredumpsize",RLIMIT_CORE,
  23.   "memoryuse",RLIMIT_RSS,
  24. };
  25.  
  26. char *funcs[] = {
  27.   0, "Previous history", "Next history", "Move Left", "Move Right",
  28.   "Delete/Backspace", "Toggle insert/overstrike", "Move to beginning of line",
  29.   "Delete to the right", "Move to EOL", "Kill to EOL", "Restore line",
  30.   "Kill line", "Quoted insert", "Find matching history", "Kill to BOL",
  31.   "Filename completion", "Backward one word", "Forward one word",
  32.   "Expand line.", "Kill word", "Next character is a control character",
  33.   "Bell", 0
  34. };
  35.  
  36. extern char _restricted;
  37. extern char *_home, *_statline, _loginshell, _glob, **_cdpath, _nofork;
  38. extern char ***file, **history, *getenv();
  39. extern char *_kbuf[MAX_GLVL], _kmax[MAX_GLVL];
  40. extern char *exit_val[], *_term[11];
  41. extern int _maxhist, curhist, fptr, _failat;
  42. extern struct custom_keys **keys[MAX_GLVL];
  43. extern struct proc_tab *proc;
  44. extern int max_ent, errno, _pgrp, _string, _status;
  45. extern int _source, err;
  46. extern char path[1025], buf[1025];
  47. extern struct _setvar *setvar, *find_var(), *makenvar();
  48. extern unsigned long SIGMASK;
  49.  
  50. char lif;    /* result of last single line if */
  51.  
  52. char *string(), *UPPER(), *grab(), **evalw();
  53. int setenv();
  54. void unsetenv(), *malloc();
  55.  
  56. int a, b, c, d;
  57.  
  58. execute(cmd,arg,in,inf,out,outf,outa,err,errf,erra,forked)
  59. char cmd,**arg,*inf,*outf,*errf,outa,erra,forked;
  60. int in,out,err;
  61. {
  62.   FILE *fin = stdin, *fout = stdout, *ferr = stderr;
  63.   int pid,n = nargs(arg), rc = 0;
  64.  
  65.   if (forked) {
  66.     if (pid = fork()) return pid;
  67.   }
  68.   sh_redirect(&in,inf,&out,outf,outa,&err,errf,erra,forked);
  69.   if (in > 0) fin = fdopen(in,"r");
  70.   if (out > 1) {
  71.     if (outa) fout = fdopen(out,"a");
  72.     else fout = fdopen(out,"w");
  73.   }
  74.   if (err > 2 && err != out) {
  75.     if (erra) ferr = fdopen(err,"a");
  76.     else ferr = fdopen(err,"w");
  77.   } else if (err == out) ferr = fout;
  78.  
  79.   switch(cmd) {
  80.     case CMD_CD:
  81.       rc = cd(n,arg,fin,fout,ferr);
  82.       break;
  83.     case CMD_HISTORY:
  84.       rc = hist(n,arg,fin,fout,ferr);
  85.       break;
  86.     case CMD_JOBS:
  87.       rc = jobs(n,arg,fin,fout,ferr);
  88.       break;
  89.     case CMD_KEY:
  90.       rc = key(n,arg,fin,fout,ferr);
  91.       break;
  92.     case CMD_ALIAS:
  93.       rc = ALIAS(n,arg,fin,fout,ferr);
  94.       break;
  95.     case CMD_LIMIT:
  96.       rc = limit(n,arg,fin,fout,ferr);
  97.       break;
  98.     case CMD_UNLIMIT:
  99.       rc = unlimit(n,arg,fin,fout,ferr);
  100.       break;
  101.     case CMD_FG:
  102.       rc = fg(n,arg,fin,fout,ferr);
  103.       break;
  104.     case CMD_BG:
  105.       rc = bg(n,arg,fin,fout,ferr);
  106.       break;
  107.     case CMD_STOP:
  108.       rc = stop(n,arg,fin,fout,ferr);
  109.       break;
  110.     case CMD_SOURCE:
  111.       rc = SOURCE(n,arg,fin,fout,ferr);
  112.       break;
  113.     case CMD_SET:
  114.       rc = SET(n,arg,fin,fout,ferr);
  115.       break;
  116.     case CMD_SETENV:
  117.       rc = SETENV(n,arg,fin,fout,ferr);
  118.       break;
  119.     case CMD_UNSETENV:
  120.       rc = UNSETENV(n,arg,fin,fout,ferr);
  121.       break;
  122.     case CMD_UNSET:
  123.       rc = UNSET(n,arg,fin,fout,ferr);
  124.       break;
  125.     case CMD_UNKEY:
  126.       rc = unkey(n,arg,fin,fout,ferr);
  127.       break;
  128.     case CMD_UNALIAS:
  129.       rc = UNALIAS(n,arg,fin,fout,ferr);
  130.       break;
  131.     case CMD_UMASK:
  132.       rc = UMASK(n,arg,fin,fout,ferr);
  133.       break;
  134.     case CMD_EXIT:
  135.       rc = EXIT(n,arg);
  136.       break;
  137.     case CMD_LOGOUT:
  138.       rc = logout(n,arg,ferr);
  139.       break;
  140.     case CMD_VERSION:
  141.       rc = version(fout);
  142.       break;
  143.     case CMD_INPUT:
  144.       rc = INPUT(n,arg,fin,fout,ferr);
  145.       break;
  146.     case CMD_IF:
  147.       rc = IF(n,arg,ferr);
  148.       break;
  149.     case CMD_ELSE:
  150.       rc = ELSE(n,arg,ferr);
  151.       break;
  152.     case CMD_ENDIF:
  153.       rc = ENDIF(ferr);
  154.       break;
  155.     case CMD_LOGIN:
  156.       rc = login(n,arg,ferr);
  157.       break;
  158.     case CMD_SECHO:
  159.       rc = secho(n,arg,fin,fout,ferr);
  160.       break;
  161.     case CMD_WHILE:
  162.       rc = WHILE(n,arg,ferr);
  163.       break;
  164.     case CMD_REPEAT:
  165.       rc = REPEAT(n,arg,ferr);
  166.       break;
  167.     case CMD_BREAK:
  168.       rc = BREAK(ferr);
  169.       break;
  170.     case CMD_CONTINUE:
  171.       rc = CONTINUE(ferr);
  172.       break;
  173.     case CMD_GOTO:
  174.       rc = GOTO(n,arg,ferr);
  175.       break;
  176.     case CMD_FOREACH:
  177.       rc = FOREACH(n,arg,ferr);
  178.       break;
  179.     case CMD_FOR:
  180.       rc = FOR(n,arg,ferr);
  181.       break;
  182.     case CMD_INC:
  183.       rc = INC(n,arg,ferr);
  184.       break;
  185.     case CMD_DEC:
  186.       rc = DEC(n,arg,ferr);
  187.       break;
  188.     case CMD_LABEL:
  189.       rc = LABEL(n,arg,ferr);
  190.       break;
  191.     case CMD_WEND:
  192.       rc = WEND(ferr);
  193.       break;
  194.     case CMD_UNTIL:
  195.       rc = UNTIL(ferr);
  196.       break;
  197.     case CMD_ENDFOR:
  198.       rc = ENDFOR(ferr);
  199.       break;
  200.     case CMD_NEXT:
  201.       rc = NEXT(ferr);
  202.       break;
  203.     case CMD_SWITCH:
  204.       rc = SWITCH(n,arg,ferr);
  205.       break;
  206.     case CMD_ENDSW:
  207.       rc = ENDSW(ferr);
  208.       break;
  209.     case CMD_EVAL:
  210.       rc = EVAL(n,arg,ferr);
  211.       break;
  212.     case CMD_EXEC:
  213.       rc = EXECUTE(n,arg,ferr);
  214.       break;
  215.     case CMD_USAGE:
  216.       rc = usage(fout,ferr);
  217.       break;
  218.     case CMD_INTR:
  219.       rc = INTR(n,arg,fout,ferr);
  220.       break;
  221.     case CMD_TERM:
  222.       rc = TERM(n,arg,fout,ferr);
  223.       break;
  224.     case CMD_PROTECT:
  225.       rc = PROTECT(n,arg,ferr);
  226.       break;
  227.     case CMD_ASSIGN:
  228.       rc = ASSIGN(n,arg,fout,ferr);
  229.       break;
  230.     case CMD_UNASSIGN:
  231.       rc = UNASSIGN(n,arg,fout,ferr);
  232.       break;
  233.     case CMD_SHIFT:
  234.       rc = SHIFT(n,arg,ferr);
  235.       break;
  236.     case CMD_SOPEN:
  237.       rc = SOPEN(n,arg,ferr);
  238.       break;
  239.     case CMD_SCLOSE:
  240.       rc = SCLOSE(n,arg,ferr);
  241.       break;
  242.     case CMD_SREAD:
  243.       rc = SREAD(n,arg,ferr);
  244.       break;
  245.     case CMD_SWRITE:
  246.       rc = SWRITE(n,arg,ferr);
  247.       break;
  248.     case CMD_SSEEK:
  249.       rc = SSEEK(n,arg,ferr);
  250.       break;
  251.   }
  252.   _status = rc;
  253.   if (forked) exit(rc);
  254.   if (in > 0) { fclose(fin); close(in); }
  255.   if (out > 1) { fclose(fout); close(out); }
  256.   if (err > 2 && err != out) { fclose(ferr); close(err); }
  257.   return 0;
  258. }
  259.  
  260. nargs(arg)
  261. char **arg;
  262. {
  263.   int i;
  264.  
  265.   for(i=0;arg[i];i++);
  266.   return i;
  267. }
  268.  
  269. cd(n,arg,in,out,err)
  270. int n;
  271. FILE *in,*out,*err;
  272. char **arg;
  273. {
  274.   if (n > 2) fprintf(err,"cd: too many arguments\n");
  275.   if (n == 1) {
  276.     if (!_home) {
  277.       fprintf(err,"cd: no home directory\n");
  278.       return 0;
  279.     }
  280.     if ((a = chdir(_home)) < 0) c = errno;
  281.   } else {
  282.     if ((a = chdir(arg[1])) < 0) {
  283.       c = errno;
  284.       if (_cdpath) {
  285.     for(b=0;_cdpath[b];b++) {
  286.       sprintf(path,"%s/%s",_cdpath[b],arg[1]);
  287.       if (chdir(path) < 0) continue;
  288.       a = 0;
  289.       break;
  290.     }
  291.       }
  292.     }
  293.   }
  294.   if (a < 0) {
  295.     switch(c) {
  296.       case ENOTDIR:
  297.     fprintf(err,"%s: Not a directory\n",arg[1]);
  298.     break;
  299.       case ENOENT:
  300.     fprintf(err,"%s: No such file or directory\n",arg[1]);
  301.     break;
  302.       case ELOOP:
  303.     fprintf(err,"%s: Too many symbolic links.\n",arg[1]);
  304.     break;
  305.       default:
  306.     fprintf(err,"%s: Permission denied.\n",arg[1]);
  307.     break;
  308.     }
  309.     return 1;
  310.   } else {
  311.     getwd(path);
  312.     if (_restricted && strncmp(_home,path,strlen(_home))) {
  313.       chdir(_home);
  314.       getwd(path);
  315.     }
  316.     makeset("cwd",path);
  317.   }
  318.   return 0;
  319. }
  320.  
  321. limit(n,arg,in,out,err)
  322. int n;
  323. FILE *in,*out,*err;
  324. char **arg;
  325. {
  326.   struct rlimit rlm;
  327.  
  328.   b = -1;
  329.   if (n > 1) {
  330.     for(a=0;a<6;a++)
  331.       if (!strcmp(arg[1],limits[a].resource)) {
  332.     b = a;
  333.     break;
  334.       }
  335.   }
  336.   if (n > 1 && b == -1) {
  337.     fprintf(err,"limit: undefined limit %s\n",arg[1]);
  338.     return 1;
  339.   }
  340.   if (n < 3) {
  341.     if (n == 1) {
  342.       for(a=0;a<6;a++) {
  343.     getrlimit(limits[a].val,&rlm);
  344.     if (rlm.rlim_cur == RLIM_INFINITY) fprintf(out,"%-15s unlimited\n",limits[a].resource);
  345.     else fprintf(out,"%-15s %d K\n",limits[a].resource,rlm.rlim_cur/1024);
  346.       }
  347.     } else {
  348.       getrlimit(limits[b].val,&rlm);
  349.       if (rlm.rlim_cur == RLIM_INFINITY) fprintf(out,"%-15s unlimited\n",arg[1]);
  350.       else fprintf(out,"%-15s %d K\n",arg[1],rlm.rlim_cur/1024);
  351.     }
  352.   } else if (n == 3) {
  353.     if (!strcmp(arg[2],"unlimit") || !strcmp(arg[2],"unlimited")) {
  354.       getrlimit(limits[b].val,&rlm);
  355.       rlm.rlim_cur = RLIM_INFINITY;
  356.       setrlimit(limits[b].val,&rlm);
  357.     } else {
  358.       if (!isnum(arg[2])) {
  359.         fprintf(err,"limit: invalid argument - %s\n",arg[2]);
  360.     return 1;
  361.       }
  362.       getrlimit(limits[b].val,&rlm);
  363.       rlm.rlim_cur = atoi(arg[2]) * 1024;
  364.       setrlimit(limits[b].val,&rlm);
  365.     }
  366.   } else {
  367.     fprintf(err,"limit: too many arguments\n");
  368.     return 1;
  369.   }
  370.   return 0;
  371. }
  372.  
  373. unlimit(n,arg,in,out,err)
  374. int n;
  375. FILE *in,*out,*err;
  376. char **arg;
  377. {
  378.   struct rlimit rlm;
  379.  
  380.   rlm.rlim_cur = RLIM_INFINITY;
  381.   if (n == 1) {
  382.     fprintf(err,"unlimit: no limit specified\n");
  383.     return 1;
  384.   }
  385.   if (n > 2) {
  386.     fprintf(err,"unlimit: too many aguments\n");
  387.     return 1;
  388.   }
  389.   for(a=1;arg[a];a++) {
  390.     for(b=0;b<6;b++)
  391.       if (!strcmp(arg[a],limits[b].resource)) {
  392.     setrlimit(limits[b].val,&rlm);
  393.     break;
  394.       }
  395.     if (b == 6) {
  396.       fprintf(err,"unlimit: invalid limit\n");
  397.       return 1;
  398.     }
  399.   }
  400.   return 0;
  401. }
  402.  
  403. hist(n,arg,in,out,err)
  404. int n;
  405. FILE *in,*out,*err;
  406. char **arg;
  407. {
  408.   char inc = 1, nflg = TRUE;
  409.  
  410.   c = -1;
  411.   d = 0;
  412.   for(a=0;arg[a];a++) {
  413.     if (arg[a][0] == '-') {
  414.       switch(arg[a][1]) {
  415.     case 'r':
  416.       d = curhist - 1;
  417.       inc = -1;
  418.       break;
  419.     case 'n':
  420.         nflg = FALSE;
  421.       break;
  422.     default:
  423.       b = atoi(arg[a]+1);
  424.       if (b > 0) c = b;
  425.       break;
  426.       }
  427.     }
  428.   }
  429.   for(a=d;a > -1 && a<curhist && c;a+=inc) {
  430.     if (nflg) fprintf(out,"%d %s\n",a,history[a]);
  431.     else fprintf(out,"%s\n",history[a]);
  432.     if (c != -1) c--;
  433.   }
  434.   return 0;
  435. }
  436.  
  437. key(n,arg,in,out,err)
  438. int n;
  439. FILE *in,*out,*err;
  440. char **arg;
  441. {
  442.   struct custom_keys *key;
  443.   char lvl=0;
  444.  
  445.   if (n == 1) {
  446.     for(b=0;b<MAX_GLVL;b++) {
  447.       if (!keys[b]) continue;
  448.       for(a=0;keys[b][a];a++) {
  449.     fprt(out,keys[b][a]->key);
  450.     fprintf(out,"\t[%d] ",b);
  451.     if (keys[b][a]->gold) fprintf(out,"GOLD -> LEVEL %d",keys[b][a]->glvl);
  452.     else if (keys[b][a]->func) fprintf(out,"Function %2d: %s",keys[b][a]->func,funcs[(keys[b][a]->func)<21?(keys[b][a]->func):21]);
  453.     else {
  454.       fputc('"',out);
  455.       fprt(out,keys[b][a]->cmd);
  456.       fputc('"',out);
  457.       if (keys[b][a]->rtn) fprintf(out,"\t[RETURN]");
  458.       if (keys[b][a]->clr) fprintf(out,"%c[CLEAR]",keys[b][a]->rtn?' ':'\t');
  459.     }
  460.     fputc('\n',out);
  461.       }
  462.     }
  463.     return 0;
  464.   }
  465.   key = (struct custom_keys *)malloc(sizeof(struct custom_keys));
  466.   bzero(key,sizeof(struct custom_keys));
  467.   for(a=1;a<n;a++) {
  468.     if (arg[a][0] == '-') {
  469.       switch(arg[a][1]) {
  470.     case 'r':
  471.       key->rtn = 1;
  472.       break;
  473.     case 'c':
  474.       key->clr = 1;
  475.       break;
  476.     case 'g':
  477.       key->gold = 1;
  478.       if (arg[a][2] >= '0' && arg[a][2] <= '4' ) key->glvl = arg[a][2] - 48;
  479.       else key->glvl = 0;
  480.       break;
  481.     case 'l':
  482.       if (isdigit(arg[a][2]) && arg[a][2] < '5') lvl = arg[a][2] - 48;
  483.       break;
  484.     case 'f':
  485.       key->func = atoi(arg[a]+2);
  486.       break;
  487.       }
  488.     } else break;
  489.   }
  490.   if ((a+2 > n && (!key->gold && !key->func)) || (a+1 > n && (key->gold || key->func))) {
  491.     fprintf(err,"not enough arguments\n");
  492.     free(key);
  493.     return 1;
  494.   }
  495.   key->key = (char *)strcpy(malloc(strlen(arg[a])+1),arg[a]);
  496.   a++;
  497.   if (!key->gold && !key->func) key->cmd = string(arg+a);
  498.   if (keys[lvl]) {
  499.     for(a=0;keys[lvl][a];a++) {
  500.       if (!strcmp(keys[lvl][a]->key,key->key)) {
  501.     free(keys[lvl][a]->key);
  502.     if (keys[lvl][a]->cmd) free(keys[lvl][a]->cmd);
  503.     free(keys[lvl][a]);
  504.     keys[lvl][a] = key;
  505.     return 0;
  506.       }
  507.     }
  508.   }
  509.   if (strlen(key->key) > _kmax[lvl]) _kmax[lvl] = strlen(key->key);
  510.   a = strlen(_kbuf[lvl]);
  511.   _kbuf[lvl] = (char *)realloc(_kbuf[lvl],a+2);
  512.   _kbuf[lvl][a] = key->key[0];
  513.   _kbuf[lvl][a+1] = 0;
  514.   if (!keys[lvl]) keys[lvl] = (struct custom_keys **)calloc(2,sizeof(struct custom_keys *));
  515.   else keys[lvl] = (struct custom_keys **)realloc(keys[lvl], sizeof(struct custom_keys *) * (a+2));
  516.   keys[lvl][a++] = key;
  517.   keys[lvl][a] = NULL;
  518.   return 0;
  519. }
  520.  
  521. jobs(n,arg,in,out,err)
  522. int n;
  523. char **arg;
  524. FILE *in,*out,*err;
  525. {
  526.   unsigned long mask;
  527.  
  528.   mask = sigblock(sigmask(SIGCHLD));
  529.   for(a=0;a<max_ent;a++) {
  530.     if (proc[a].pid != 0) {
  531.       if (proc[a].status) {
  532.     fprintf(out," [%d] (%d) %-30s%s %s\n",a,proc[a].pid,exit_val[proc[a].status],(proc[a].bg?" (background)":""),proc[a].cmd);
  533.       } else {
  534.     if (proc[a].bg) fprintf(out," [%d] (%d) %-30s %s\n",a,proc[a].pid,"Running (background)",proc[a].cmd);
  535.     else fprintf(out," [%d] (%d) %-30s %s\n",a,proc[a].pid,"Running",proc[a].cmd);
  536.       }
  537.     }
  538.   }
  539.   sigsetmask(mask);
  540.   return 0;
  541. }
  542.  
  543. SETENV(n,arg,in,out,err)
  544. int n;
  545. char **arg;
  546. FILE *in,*out,*err;
  547. {
  548.   char *ptr;
  549.  
  550.   if (n < 2) {
  551.     fprintf(err,"setenv: not enough arguments\n");
  552.   } else if (n > 3) {
  553.     fprintf(err,"setenv: too many arguments\n");
  554.   } else if (n == 2) {
  555.     ptr = getenv(arg[1]);
  556.     if (ptr) {
  557.       printf("%s=%s\n",arg[1],ptr);
  558.       free(ptr);
  559.     }
  560.   } else {
  561.     setenv(arg[1],arg[2],1);
  562.   }
  563.   return 0;
  564. }
  565.  
  566. UNSETENV(n,arg,in,out,err)
  567. int n;
  568. char **arg;
  569. FILE *in,*out,*err;
  570. {
  571.   if (n < 2) {
  572.     fprintf(err,"unsetenv: variable identifier expected.\n");
  573.   } else if (n > 2) {
  574.     fprintf(err,"unsetenv: too many arguments.\n");
  575.   } else {
  576.     unsetenv(arg[1]);
  577.   }
  578.   return 0;
  579. }
  580.  
  581. fg(n,arg,in,out,err)
  582. int n;
  583. char **arg;
  584. FILE *in,*out,*err;
  585. {
  586.   unsigned long mask;
  587.  
  588.   if (n > 2) {
  589.     fprintf(err,"%s: too many args\n",arg[0]);
  590.     return 1;
  591.   }
  592.   if (n == 1) {
  593.     mask = sigblock(sigmask(SIGCHLD));
  594.     for(a=0;a<max_ent;a++) {
  595.       if (proc[a].pid != 0 && (proc[a].bg || proc[a].status)) {
  596.     if (proc[a].bg) {
  597.       proc[a].bg = 0;
  598.       setpgrp(proc[a].pid,proc[a].pid);
  599.       proc[a].pgrp = proc[a].pid;
  600.     }
  601.     if (proc[a].pgrp != _pgrp) tcsetpgrp(TTY,proc[a].pgrp);
  602.     if (killpg(proc[a].pgrp,SIGCONT) < 0) return 1;
  603.     proc[a].status = STAT_RUNNING;
  604.     break;
  605.       }
  606.     }
  607.     sigsetmask(mask);
  608.     return 0;
  609.   } else {
  610.     a = atoi(arg[1]);
  611.     if (a < 0 || a >= max_ent) {
  612.       fprintf(err,"%s: No such job: %d\n",a);
  613.       return 1;
  614.     }
  615.     mask = sigblock(sigmask(SIGCHLD));
  616.     if (proc[a].pid != 0 && (proc[a].bg || proc[a].status)) {
  617.       if (proc[a].bg) {
  618.     proc[a].bg = 0;
  619.     setpgrp(proc[a].pid,proc[a].pid);
  620.     proc[a].pgrp = proc[a].pid;
  621.       }
  622.       if (proc[a].pgrp != _pgrp) tcsetpgrp(TTY,proc[a].pgrp);
  623.       if (killpg(proc[a].pgrp,SIGCONT) < 0) return 1;
  624.       proc[a].status = STAT_RUNNING;
  625.     }
  626.     sigsetmask(mask);
  627.   }
  628.   return 0;
  629. }
  630.  
  631. bg(n,arg,in,out,err)
  632. int n;
  633. char **arg;
  634. FILE *in,*out,*err;
  635. {
  636.   unsigned long mask;
  637.  
  638.   if (n > 2) {
  639.     fprintf(err,"%s: too many args\n",arg[0]);
  640.     return 1;
  641.   }
  642.   if (n == 1) {
  643.     mask = sigblock(sigmask(SIGCHLD));
  644.     for(a=0;a<max_ent;a++) {
  645.       if (proc[a].pid != 0 && !proc[a].bg) {
  646.     proc[a].bg = 1;
  647.     setpgrp(proc[a].pid,_pgrp);
  648.     proc[a].pgrp = _pgrp;
  649.     tcsetpgrp(TTY,_pgrp);
  650.     if (killpg(proc[a].pgrp,SIGCONT) < 0) return 1;
  651.     proc[a].status = STAT_RUNNING;
  652.     break;
  653.       }
  654.     }
  655.     sigsetmask(mask);
  656.     return 0;
  657.   } else {
  658.     a = atoi(arg[1]);
  659.     if (a < 0 || a >= max_ent) {
  660.       fprintf(err,"%s: No such job: %d\n",a);
  661.       return 1;
  662.     }
  663.     mask = sigblock(sigmask(SIGCHLD));
  664.     if (proc[a].pid != 0 && !proc[a].bg) {
  665.       proc[a].bg = 1;
  666.       setpgrp(proc[a].pid,_pgrp);
  667.       proc[a].pgrp = _pgrp;
  668.       tcsetpgrp(TTY,_pgrp);
  669.       if (killpg(proc[a].pgrp,SIGCONT) < 0) return 1;
  670.       proc[a].status = STAT_RUNNING;
  671.     }
  672.     sigsetmask(mask);
  673.   }
  674.   return 0;
  675. }
  676.  
  677. stop(n,arg,in,out,err)
  678. int n;
  679. char **arg;
  680. FILE *in,*out,*err;
  681. {
  682.   unsigned long mask;
  683.  
  684.   if (n > 2) {
  685.     fprintf(err,"stop: too many args\n");
  686.     return 1;
  687.   }
  688.   mask = sigblock(sigmask(SIGCHLD));
  689.   if (n == 1) {
  690.     for(a=0;a<max_ent;a++) {
  691.       if (proc[a].pid != 0 && proc[a].bg) {
  692.     if (killpg(proc[a].pgrp,SIGTSTP) < 0) return 1;
  693.     break;
  694.       }
  695.     }
  696.   } else {
  697.     a = atoi(arg[1]);
  698.     if (proc[a].pid != 0 && proc[a].bg) {
  699.       if (killpg(proc[a].pgrp,SIGTSTP) < 0) return 1;
  700.     }
  701.   }
  702.   sigsetmask(mask);
  703.   return 0;
  704. }
  705.  
  706. SOURCE(n,arg,in,out,err)
  707. int n;
  708. char **arg;
  709. FILE *in,*out,*err;
  710. {
  711.   int i,j,f;
  712.   char ***tfile;
  713.  
  714.   if (n < 2) {
  715.     source(NULL);
  716.     return 0;
  717.   }
  718.   for(i=1;arg[i];i++) {
  719.     f = fptr;
  720.     tfile = file;
  721.     j = source(arg[i]);
  722.     fptr = f;
  723.     file = tfile;
  724.     if (j < 0) {
  725.       fprintf(err,"source: error opening file %s\n",arg[i]);
  726.       return 1;
  727.     }
  728.   }
  729.   return 0;
  730. }
  731.  
  732. unkey(n,arg,in,out,err)
  733. int n;
  734. char **arg;
  735. FILE *in,*out,*err;
  736. {
  737.   c = 0;
  738.   if (n < 2) {
  739.     fprintf(stderr,"unkey: macro definition expected.\n");
  740.     return 1;
  741.   }
  742.   for(a=1;arg[a];a++) {
  743.     if (arg[a][0] == '-') {
  744.       if (arg[a][1] == 'l') c = atoi(arg[a]+2);
  745.       else {
  746.         fprintf(stderr,"unkey: %s invalid argument.\n",arg[a]);
  747.     return 1;
  748.       }
  749.     } else break;
  750.   }
  751.   for(b=0;keys[c][b];b++) {
  752.     if (!strcmp(arg[a],keys[c][b]->key)) {
  753.       free(keys[c][b]->cmd);
  754.       free(keys[c][b]->key);
  755.       free(keys[c][b]);
  756.       for(;keys[c][b];b++) {
  757.         keys[c][b] = keys[c][b+1];
  758.     _kbuf[c][b] = _kbuf[c][b+1];
  759.       }
  760.       return 0;
  761.     }
  762.   }
  763.   return 0;
  764. }
  765.  
  766. UMASK(n,arg,in,out,err)
  767. int n;
  768. char **arg;
  769. FILE *in, *out, *err;
  770. {
  771.   char *ex;
  772.  
  773.   if (n == 1) {
  774.     a = umask(0);    
  775.     fprintf(out,"%03o\n",a);
  776.     umask(a);
  777.     return 0;
  778.   }
  779.   ex = grab(arg,1,NULL,&a);
  780.   if (!ex) {
  781.     fprintf(err,"umask: file protection mask expected.\n");
  782.     return 1;
  783.   }
  784.   a = expr(ex);
  785.   free(ex);
  786.   umask(a);
  787.   return 0;
  788. }
  789.  
  790. EXIT(n,arg)
  791. int n;
  792. char **arg;
  793. {
  794.   char *ex;
  795.  
  796.   if (n > 1) {
  797.     ex = grab(arg,1,NULL,&a);
  798.     a = expr(ex);
  799.   } else a = 0;
  800.   if (_source) {
  801.     err = ERR_EXIT;
  802.     return a;
  803.   }
  804.   if (_statline) printf("%s%s%s",_term[TS],_term[CE],_term[FS]);
  805.   exit(a);
  806. }
  807.  
  808. logout(n,arg,err)
  809. int n;
  810. char **arg;
  811. FILE *err;
  812. {
  813.   static char f = TRUE;
  814.   unsigned long mask;
  815.   FILE *fd;
  816.  
  817.   if (f) {
  818.     mask = sigblock(sigmask(SIGCHLD));
  819.     for(a=0;a<max_ent;a++)
  820.       if (proc[a].pid != 0 && (proc[a].bg || proc[a].status)) {
  821.     fprintf(err,"You have stopped jobs!\n");
  822.     f = FALSE;
  823.     break;
  824.       }
  825.     sigsetmask(mask);
  826.     if (!f) return 1;
  827.   }
  828.   
  829.   if (_loginshell) {
  830.     for(a=0;a<n;a++) {
  831.       sprintf(path,"%d",a);
  832.       makeset(path,arg[a]);
  833.     }
  834.     sprintf(path,"%s/%s",_home,HIST_SAVE);
  835.     b = open(path,O_WRONLY | O_CREAT | O_TRUNC,0600);
  836.     fd = fdopen(b,"w");
  837.     fprintf(fd,"%d\n",_maxhist);
  838.     for(a=0;a < curhist;a++) fprintf(fd,"%s\n",history[a]);
  839.     fclose(fd);
  840.     close(b);
  841.     sprintf(path,"%s/%s",_home,SHELL_EXIT);
  842.     source(path);
  843.   }
  844.   if (_statline) printf("%s%s%s",_term[TS],_term[CE],_term[FS]);
  845.   exit(0);
  846. }
  847.  
  848. char *string(wrd)
  849. char **wrd;
  850. {
  851.   int i,j;
  852.   char *str;
  853.  
  854.   for(i=j=0;wrd[i];i++) j += strlen(wrd[i])+1;
  855.   str = (char *)malloc(j);
  856.   strcpy(str,wrd[0]);
  857.   for(i=1;wrd[i];i++) {
  858.     strcat(str," ");
  859.     strcat(str,wrd[i]);
  860.   }
  861.   return str;
  862. }
  863.  
  864. char *UPPER(wrd)
  865. char *wrd;
  866. {
  867.   char *tmp;
  868.  
  869.   tmp = (char *)malloc(strlen(wrd)+1);
  870.   for(a=0;*wrd;wrd++) tmp[a++] = (islower(*wrd)? toupper(*wrd) : *wrd);
  871.   tmp[a] = 0;
  872.   return tmp;
  873. }
  874.  
  875. fprt(stream,str)
  876. FILE *stream;
  877. char *str;
  878. {
  879.   char c;
  880.  
  881.   while(*str) {
  882.     c = *str++ & 127;
  883.     if (c < 32) {
  884.       if (_term[SO]) fprintf(stream,"%s%c%s",_term[SO],c+64,_term[SE]);
  885.       else fprintf(stream,"^%c",c+64);
  886.     } else if (c == 127) {
  887.       if (_term[SO]) fprintf(stream,"%s?%s",_term[SO],_term[SE]);
  888.       else fprintf(stream,"^?");
  889.     } else fputc(c,stream);
  890.   }
  891. }
  892.  
  893. version(out)
  894. FILE *out;
  895. {
  896.   fprintf(out," Ssh V1.7\n Copyright (C) 1991,1992,1993 by Steve Baker and Thomas Moore.\n All rights reserved.\n");
  897.   return 0;
  898. }
  899.  
  900. IF(n,arg,ferr)
  901. int n;
  902. char **arg;
  903. FILE *ferr;
  904. {
  905.   long res;
  906.   int i,nest;
  907.   int start = fptr, stop = fptr+1, end = fptr+1;
  908.   char *ex;
  909.  
  910.   ex = grab(arg,1,"then",&i);
  911.   if (!ex) {
  912.     fprintf(ferr,"if: expression expected.\n");
  913.     return err = 1;
  914.   }
  915.   if (!arg[i++]) {
  916.     fprintf(ferr,"if: keyword 'then' expected.\n");
  917.     return err = 1;
  918.   }
  919.   err = 0;
  920.   res = expr(ex);
  921.   free(ex);
  922.   if (err) return 1;
  923.  
  924.   if (!_source && !arg[i]) return 1;  
  925.   nest = 0;
  926.   if (!arg[i]) {
  927.     while(file[stop]) {
  928.       if (!nest && (!strcmp(file[stop][0],"else") || !strcmp(file[stop][0],"endif"))) break;
  929.       else if (nest && !strcmp(file[stop][0],"endif")) nest--;
  930.       else if (!strcmp(file[stop][0],"if")) {
  931.     for(i=1;file[stop][i];i++) {
  932.       if (!strcmp(file[stop][i],"then"))
  933.         if (file[stop][i+1]) break;
  934.         else {
  935.           nest++;
  936.           break;
  937.         }
  938.     }
  939.       }
  940.       stop++;
  941.     }
  942.     end = stop;
  943.     while(file[end]) {
  944.       if (!nest && !strcmp(file[end][0],"endif")) break;
  945.       else if (nest && !strcmp(file[end][0],"endif")) nest--;
  946.       else if (!strcmp(file[end][0],"if")) {
  947.     for(i=1;file[end][i];i++) {
  948.       if (!strcmp(file[end][i],"then"))
  949.         if (file[end][i+1]) break;
  950.         else {
  951.           nest++;
  952.           break;
  953.         }
  954.     }
  955.       }
  956.       end++;
  957.     }
  958.     if (!file[stop] || !file[end]) {
  959.       fprintf(ferr,"if: unexpected end of file.\n");
  960.       return err = 1;
  961.     }
  962.     if (!res) {
  963.       start = stop;
  964.       stop = end;
  965.     }
  966.     if (start == end) {
  967.       fptr = end;
  968.       return 0;
  969.     }
  970.     fptr = start+1;
  971.     while(fptr < stop) {
  972.       run(fptr);
  973.       if (err || badstat(_status)) {
  974.     fptr = end;
  975.     return _status&RET_MASK;
  976.       }
  977.       fptr++;
  978.     }
  979.     fptr = end;
  980.   } else if (res) {
  981.     lif = TRUE;
  982.     ex = string(arg+i);
  983.     run2(ex);
  984.     free(ex);
  985.   } else lif = FALSE;
  986.   return 0;
  987. }
  988.  
  989. ELSE(n,arg,err)
  990. int n;
  991. char **arg;
  992. FILE *err;
  993. {
  994.   char *cmd;
  995.  
  996.   if (!_source) {
  997.     fprintf(err,"else: no previous if-then statement.\n");
  998.     return 1;
  999.   } else {
  1000.     if (!fptr || strcmp(file[fptr-1][0],"if")) {
  1001.       fprintf(err,"else: no previous if-then statement.\n");
  1002.       return 1;
  1003.     }
  1004.     if (n < 2) {
  1005.       fprintf(err,"else: no command for else condition.\n");
  1006.       return 1;
  1007.     }
  1008.     if (lif) return 0;
  1009.     cmd = string(arg+1);
  1010.     run2(cmd);
  1011.     free(cmd);
  1012.   }
  1013.   return 0;
  1014. }
  1015.  
  1016. ENDIF(err)
  1017. FILE *err;
  1018. {
  1019.   fprintf(err,"else: no previous if-then-else statement.\n");
  1020.   return 1;
  1021. }
  1022.  
  1023. INPUT(n,arg,in,out,err)
  1024. int n;
  1025. char **arg;
  1026. FILE *in, *out, *err;
  1027. {
  1028.   char *var = NULL, *prompt = NULL;
  1029.  
  1030.   c = d = 0;
  1031.   if (n < 2) {
  1032.     fprintf(err,"input: not enough arguments\n");
  1033.     return 1;
  1034.   }
  1035.   for(a=1;arg[a];a++) {
  1036.     if (prompt == arg[a]) continue;
  1037.     if (arg[a][0] == '-') {
  1038.       for(b=1;arg[a][b];b++) {
  1039.     switch(arg[a][b]) {
  1040.       case 'n':    /* don't replace var if nothing entered. */
  1041.         c = TRUE;
  1042.         break;
  1043.       case 'c':    /* read a single character immediately. */
  1044.         d = 1;
  1045.         break;
  1046.       case 'w':    /* break line up into words. */
  1047.         d = 2;
  1048.         break;
  1049.       case 'e':    /* read single character, echoing it to screen. */
  1050.         d = 3;
  1051.         break;
  1052.       case 'p':    /* Next word is the prompt */
  1053.         if (arg[a+1]) prompt = arg[a+1];
  1054.         else {
  1055.           fprintf(err,"input: no prompt specified.\n");
  1056.           return 1;
  1057.         }
  1058.         break;
  1059.     }
  1060.       }
  1061.     } else if (!var) var = arg[a];
  1062.     else {
  1063.       fprintf(err,"input: too many arguments.\n");
  1064.       return 1;
  1065.     }
  1066.   }
  1067.   if (prompt) fprintf(out,"%s",prompt);
  1068.   switch (d) {
  1069.     case 0:
  1070.     case 2:
  1071.       fgets(buf,1024,in);
  1072.       buf[strlen(buf)-1] = 0;
  1073.       if (buf[0] == 0 && c) return 0;
  1074.       makeset(var,buf);
  1075.       return 0;
  1076.     case 1:
  1077.     case 3:
  1078.       noecho();
  1079.       buf[0] = getchar();
  1080.       if (d == 3) outch(buf[0]);
  1081.       buf[1] = 0;
  1082.       makeset(var,buf);
  1083.       echo();
  1084.       return 0;
  1085.   }
  1086.   /*NOTREACHED*/
  1087. }
  1088.  
  1089. login(n,arg,err)
  1090. int n;
  1091. char **arg;
  1092. FILE *err;
  1093. {
  1094.   execv("/bin/login",arg);
  1095.   fprintf(err,"login: command not found.\n");
  1096.   return 1;
  1097. }
  1098.  
  1099. secho(n,arg,in,out,err)
  1100. int n;
  1101. char **arg;
  1102. FILE *in, *out, *err;
  1103. {
  1104.   char *ex;
  1105.   char x,z;
  1106.  
  1107.   x = z = b = d = TRUE;
  1108.   c = FALSE;
  1109.  
  1110.   for(a=1;arg[a] && x;a++) {
  1111.     if (z && arg[a][0] == '-' && (!arg[a][1] || !arg[a][2])) {
  1112.       switch(arg[a][1]) {
  1113.     case 'n':
  1114.       b = FALSE;
  1115.       break;
  1116.     case 'w':
  1117.       c = !c;
  1118.       break;
  1119.     case 'e':
  1120.       d = !d;
  1121.       break;
  1122.     case 'x':
  1123.       ex = string(arg+(a+1));
  1124.       d = expr(ex);
  1125.       fprintf(out,"%ld",d);
  1126.       free(ex);
  1127.       x = c = FALSE;
  1128.       break;
  1129.     case 0:
  1130.       z = FALSE;
  1131.       break;
  1132.       }
  1133.     } else {
  1134.       if (d) fputs((char *)pline(arg[a],1023,1023),out);
  1135.       else fputs(arg[a],out);
  1136.       if (!c && arg[a+1]) fputc(' ',out);
  1137.       if (c) fputc('\n',out);
  1138.     }
  1139.   }
  1140.   if (b && !c) fputc('\n',out);
  1141.   return 0;
  1142. }
  1143.  
  1144. BREAK()
  1145. {
  1146.   err = ERR_BREAK;
  1147.   return 0;
  1148. }
  1149.  
  1150. CONTINUE()
  1151. {
  1152.   err = ERR_CONTINUE;
  1153.   return 0;
  1154. }
  1155.  
  1156. WHILE(n,arg,ferr)
  1157. int n;
  1158. char **arg;
  1159. FILE *ferr;
  1160. {
  1161.   int start = fptr+1, end = fptr+1;
  1162.   char *ex, nest = 0;
  1163.  
  1164.   if (!_source) return 1;
  1165.   while(file[end]) {
  1166.     if (!strcmp(file[end][0],"while")) {
  1167.       nest++;
  1168.       end++;
  1169.       continue;
  1170.     }
  1171.     if (!nest && !strcmp(file[end][0],"wend")) break;
  1172.     if (nest && !strcmp(file[end][0],"wend")) nest--;
  1173.     end++;
  1174.   }
  1175.   if (!file[end]) {
  1176.     fprintf(ferr,"while: while without matching wend.\n");
  1177.     return 1;
  1178.   }
  1179.   
  1180.   ex = string(arg+1);
  1181.   while (expr(ex)) {
  1182.     fptr = start;
  1183.     while(fptr < end) {
  1184.       run(fptr);
  1185.       if (err == ERR_BREAK) {
  1186.     fptr = end;
  1187.     free(ex);
  1188.         return err = 0;
  1189.       } else if (err == ERR_CONTINUE) {
  1190.         err = 0;
  1191.     break;
  1192.       }
  1193.       if (err || badstat(_status)) {
  1194.     fptr = end;
  1195.         free(ex);
  1196.         return _status&RET_MASK;
  1197.       }
  1198.       fptr++;
  1199.     }
  1200.   }
  1201.   fptr = end;
  1202.   free(ex);
  1203.   return 0;
  1204. }
  1205.  
  1206. WEND(ferr)
  1207. FILE *ferr;
  1208. {
  1209.   fprintf(ferr,"wend: wend without matching while.\n");
  1210.   return 1;
  1211. }
  1212.  
  1213. REPEAT(n,arg,ferr)
  1214. int n;
  1215. char **arg;
  1216. FILE *ferr;
  1217. {
  1218.   int start = fptr+1, end = fptr+1;
  1219.   char *ex = NULL, nest = 0;
  1220.  
  1221.   if (!_source) return 1;
  1222.  
  1223.   while(file[end]) {
  1224.     if (!strcmp(file[end][0],"repeat")) {
  1225.       nest++;
  1226.       end++;
  1227.       continue;
  1228.     }
  1229.     if (!nest && !strcmp(file[end][0],"until")) break;
  1230.     if (nest && !strcmp(file[end][0],"until")) nest--;
  1231.     end++;
  1232.   }
  1233.   if (!file[end]) {
  1234.     fprintf(ferr,"repeat: repeat without matching until.\n");
  1235.     err = 1;
  1236.     return 1;
  1237.   }
  1238.   ex = string(file[end]+1);
  1239.  
  1240.   do {
  1241.     fptr = start;
  1242.     while (fptr < end) {
  1243.       run(fptr);
  1244.       if (err == ERR_BREAK) {
  1245.     fptr = end;
  1246.     break;
  1247.       } else if (err == ERR_CONTINUE) {
  1248.     fptr = end;
  1249.     err = 0;
  1250.     break;
  1251.       }
  1252.       if (err || badstat(_status)) {
  1253.     fptr = end;
  1254.         if (ex) free(ex);
  1255.         return _status&RET_MASK;
  1256.       }
  1257.       fptr++;
  1258.     }
  1259.     if (err) break;
  1260.   } while (!expr(ex));
  1261.   if (err) err = 0;
  1262.   free(ex);
  1263.   return 0;
  1264. }
  1265.  
  1266. UNTIL(ferr)
  1267. FILE *ferr;
  1268. {
  1269.   fprintf(ferr,"until: until without matching repeat.\n");
  1270.   return 1;
  1271. }
  1272.  
  1273. FOR(n,arg,ferr)
  1274. int n;
  1275. char **arg;
  1276. FILE *ferr;
  1277. {
  1278.   long beg, en, step;
  1279.   int i,nest = 0, start = fptr+1, end = fptr+1;
  1280.   char *ex = NULL;
  1281.   struct _setvar *v;
  1282.  
  1283.   if (!_source) return 1;
  1284.  
  1285.   if (arg[1]) v = makenvar(arg[1],0);
  1286.   else {
  1287.     fprintf(ferr,"for: missing variable identifier.\n");
  1288.     return err = 1;
  1289.   }
  1290.   if (!arg[2] || arg[2][0] != '=' || arg[2][1] != 0) {
  1291.     fprintf(ferr,"for: '=' expected.\n");
  1292.     return err = 1;
  1293.   }
  1294.   ex = grab(arg,3,"to", &i);
  1295.   if (!ex) {
  1296.     fprintf(ferr,"for: assignment expected.\n");
  1297.     return err = 1;
  1298.   }
  1299.   if (!arg[i]) {
  1300.     fprintf(ferr,"for: keyword 'to' expected.\n");
  1301.     return err = 1;
  1302.   }
  1303.   beg = expr(ex);
  1304.   if (err) return 1;
  1305.   free(ex);
  1306.   i++;
  1307.   ex = grab(arg,i,"step",&i);
  1308.   if (!ex) {
  1309.     fprintf(ferr,"for: ending value expected.\n");
  1310.     return err = 1;
  1311.   }
  1312.   en = expr(ex);
  1313.   free(ex);
  1314.   if (arg[i++]) {
  1315.     ex = grab(arg,i,NULL,&i);
  1316.     if (!ex) {
  1317.       fprintf(ferr,"for: step value expected.\n");
  1318.       return err = 1;
  1319.     }
  1320.     step = expr(ex);
  1321.     free(ex);
  1322.   } else step = 1;
  1323.  
  1324.   while(file[end]) {
  1325.     if (!nest && !strcmp(file[end][0],"next")) break;
  1326.     else if (nest && !strcmp(file[end][0],"next")) nest--;
  1327.     else if (!strcmp(file[end][0],"for")) nest++;
  1328.     end++;
  1329.   }
  1330.   if (!file[end]) {
  1331.     fprintf(ferr,"for: for without next.\n");
  1332.     fptr = end-1;
  1333.     return 1;
  1334.   }
  1335.   v->sv.val = beg;
  1336.  
  1337.   while(1) {
  1338.     if (step < 0) {
  1339.       if (v->sv.val < en) break;
  1340.     } else {
  1341.       if (v->sv.val > en) break;
  1342.     }
  1343.     fptr = start;
  1344.     while(fptr < end) {
  1345.       run(fptr);
  1346.       if (err == ERR_BREAK) {
  1347.     fptr = end;
  1348.     return err = 0;
  1349.       } else if (err == ERR_CONTINUE) {
  1350.     fptr = end;
  1351.     err = 0;
  1352.     break;
  1353.       }
  1354.       if (err || badstat(_status)) {
  1355.     fptr = end;
  1356.         return _status&RET_MASK;
  1357.       }
  1358.       fptr++;
  1359.     }
  1360.     if (err == ERR_BREAK) {
  1361.     }
  1362.     v->sv.val += step;
  1363.   }
  1364.   fptr = end;
  1365.   return 0;
  1366. }
  1367.  
  1368. NEXT(ferr)
  1369. FILE *ferr;
  1370. {
  1371.   fprintf(ferr,"next: Next without matching for statement.\n");
  1372.   return 1;
  1373. }
  1374.  
  1375. LABEL(n,arg,ferr)
  1376. int n;
  1377. char **arg;
  1378. FILE *ferr;
  1379. {
  1380.   if (n < 2) {
  1381.     fprintf(ferr,"label: missing label\n");
  1382.     return 1;
  1383.   }
  1384.   if (n > 3) {
  1385.     fprintf(ferr,"label: too many labels\n");
  1386.     return 1;
  1387.   }
  1388.   return 0;
  1389. }
  1390.  
  1391. GOTO(n,arg,ferr)
  1392. int n;
  1393. char **arg;
  1394. FILE *ferr;
  1395. {
  1396.   char *lab = NULL;
  1397.   char dir = 2;
  1398.   int ptr = fptr;
  1399.  
  1400.   if (!_source) return 0;
  1401.   for(a=1;arg[a];a++) {
  1402.     if (arg[a][0] == '-') {
  1403.       switch (arg[a][1]) {
  1404.     case 'f':
  1405.       dir = 0;
  1406.       break;
  1407.     case 'r':
  1408.       dir = 1;
  1409.       break;
  1410.     case 't':
  1411.       dir = 2;
  1412.       break;
  1413.     default:
  1414.       fprintf(ferr,"goto: invalid switch %s\n",arg[a]);
  1415.       return 1;
  1416.       }
  1417.     } else if (!lab) lab = arg[a];
  1418.       else {
  1419.     fprintf(ferr,"goto: illegal argument: %s",arg[a]);
  1420.     return 1;
  1421.       }
  1422.   }
  1423.   if (dir == 2) dir = ptr = 0;
  1424.   else if (dir) ptr--;
  1425.   else ptr++;
  1426.   if (dir) {
  1427.     for(; ptr >= 0 ; ptr--) {
  1428.       if (!strcmp(file[ptr][0],"label")) {
  1429.         if (!strcmp(file[ptr][1],lab)) {
  1430.       err = ERR_GOTO;
  1431.       fptr = ptr;
  1432.       return 0;
  1433.     }
  1434.       }
  1435.     }
  1436.   } else {
  1437.     for(; file[ptr] ; ptr++) {
  1438.       if (!strcmp(file[ptr][0],"label")) {
  1439.         if (!strcmp(file[ptr][1],lab)) {
  1440.       err = ERR_GOTO;
  1441.       fptr = ptr;
  1442.       return 0;
  1443.     }
  1444.       }
  1445.     }
  1446.   }
  1447.   fprintf(ferr,"goto: label '%s' not found.\n",lab);
  1448.   return 1;
  1449. }
  1450.  
  1451. FOREACH(n,arg,ferr)
  1452. int n;
  1453. char **arg;
  1454. FILE *ferr;
  1455. {
  1456.   int start = fptr+1, end = fptr+1, p = 2;
  1457.   char *ex = arg[1], nest = 0;
  1458.  
  1459.   if (!_source) return 1;
  1460.  
  1461.   while(file[end]) {
  1462.     if (!strcmp(file[end][0],"foreach")) {
  1463.       nest++;
  1464.       end++;
  1465.       continue;
  1466.     }
  1467.     if (!nest && !strcmp(file[end][0],"endfor")) break;
  1468.     if (nest && !strcmp(file[end][0],"endfor")) nest--;
  1469.     end++;
  1470.   }
  1471.   if (!file[end]) {
  1472.     fprintf(ferr,"foreach: foreach without matching endfor.\n");
  1473.     fptr = end-1;
  1474.     return 1;
  1475.   }
  1476.   if (n < 3) {
  1477.     fprintf(ferr,"foreach: Not enough arguments.\n");
  1478.     fptr = end;
  1479.     return 1;
  1480.   }
  1481.  
  1482.   while(arg[p]) {
  1483.     fptr = start;
  1484.     makeset(ex,arg[p++]);
  1485.     while (fptr < end) {
  1486.       run(fptr);
  1487.       if (err == ERR_BREAK) {
  1488.     fptr = end;
  1489.     break;
  1490.       } else if (err == ERR_CONTINUE) {
  1491.     fptr = end;
  1492.     err = 0;
  1493.     break;
  1494.       }
  1495.       if (err || badstat(_status)) {
  1496.     fptr = end;
  1497.         return 0;
  1498.       }
  1499.       fptr++;
  1500.     }
  1501.     if (err) break;
  1502.   }
  1503.   fptr = end;
  1504.   return 0;
  1505. }
  1506.  
  1507. ENDFOR(ferr)
  1508. FILE *ferr;
  1509. {
  1510.   fprintf(ferr,"endfor: endfor without foreach.\n");
  1511.   return 1;
  1512. }
  1513.  
  1514. char *grab(arg,start,hit,pt)
  1515. char **arg;
  1516. char *hit;
  1517. int start,*pt;
  1518. {
  1519.   static int i,j,k,p;
  1520.   static char *ex;
  1521.  
  1522.   j = 0;
  1523.   ex = NULL;
  1524.   if (!hit) {
  1525.     for(i=start;arg[i];i++) j+= strlen(arg[i]);
  1526.   } else {
  1527.     for(i=start;arg[i] && strcmp(arg[i],hit);i++) j+= strlen(arg[i]);
  1528.   }
  1529.   if (!j) return NULL;
  1530.   *pt = i;
  1531.   ex = (char *)malloc(j+1);
  1532.   for(p=0,k=start;k<i;k++) {
  1533.     for(j=0;arg[k][j];j++) ex[p++] = arg[k][j];
  1534.   }
  1535.   ex[p] = 0;
  1536.   return ex;
  1537. }
  1538.  
  1539. INC(n,arg,ferr)
  1540. int n;
  1541. char **arg;
  1542. FILE *ferr;
  1543. {
  1544.   struct _setvar *s;
  1545.  
  1546.   if (n < 2) {
  1547.     fprintf(ferr,"inc: variable expected.\n");
  1548.     return 1;
  1549.   }
  1550.   for(a=1;arg[a];a++) {
  1551.     s = find_var(arg[a]);
  1552.     if (!s) makenvar(arg[a],1);
  1553.     else {
  1554.       s->sv.val++;
  1555.     }
  1556.   }
  1557.   return 0;
  1558. }
  1559.  
  1560. DEC(n,arg,ferr)
  1561. int n;
  1562. char **arg;
  1563. FILE *ferr;
  1564. {
  1565.   struct _setvar *s;
  1566.  
  1567.   if (n < 2) {
  1568.     fprintf(ferr,"dec: variable expected.\n");
  1569.     return 1;
  1570.   }
  1571.   for(a=1;arg[a];a++) {
  1572.     s = find_var(arg[a]);
  1573.     if (!s) makenvar(arg[a],1);
  1574.     else {
  1575.       s->sv.val--;
  1576.     }
  1577.   }
  1578.   return 0;
  1579. }
  1580.  
  1581. EVAL(n,arg,ferr)
  1582. int n;
  1583. char **arg;
  1584. FILE *ferr;
  1585. {
  1586.   char *ex;
  1587.  
  1588.   if (n < 2) {
  1589.     fprintf(ferr,"eval: argument expected.\n");
  1590.     return 1;
  1591.   }
  1592.   ex = string(arg+1);
  1593.   run2(ex);
  1594.   free(ex);
  1595.   return 0;
  1596. }
  1597.  
  1598. EXECUTE(n,arg,ferr)
  1599. int n;
  1600. char **arg;
  1601. FILE *ferr;
  1602. {
  1603.   char *ex;
  1604.  
  1605.   if (n < 2) {
  1606.     fprintf(ferr,"exec: argument expected.\n");
  1607.     return 1;
  1608.   }
  1609.   ex = string(arg+1);
  1610.   _nofork = TRUE;
  1611.   run2(ex);
  1612.   _nofork = FALSE;
  1613.   free(ex);
  1614.   return 1;
  1615. }
  1616.  
  1617. SWITCH(n,arg,ferr)
  1618. int n;
  1619. char **arg;
  1620. FILE *ferr;
  1621. {
  1622.   char *s = arg[1], l = 0, **etmp, *tmp;
  1623.   int ptr = fptr+1, start = 0, end = 0, i, j, k;
  1624.  
  1625.   if (n < 2) {
  1626.     fprintf(ferr,"switch: string argument expected.\n");
  1627.     return 1;
  1628.   }
  1629.   if (n > 2) {
  1630.     fprintf(ferr,"switch: Too many arguments.\n");
  1631.     return 1;
  1632.   }
  1633.   for(;file[ptr]; ptr++) {
  1634.     if (!l && !start && file[ptr][1] && !strcmp("case",file[ptr][0])) {
  1635.       for(i=1;i<n && start != ptr;i++) {
  1636.     if (file[ptr][i][0] == '"' || file[ptr][i][0] == '\'') {
  1637.       j = file[ptr][i][(k=strlen(file[ptr][i]))-1];
  1638.       file[ptr][i][k-1] = 0;
  1639.       etmp = evalw(tmp=file[ptr][i]+1);
  1640.       file[ptr][i][k-1] = j;
  1641.     } else etmp = evalw(tmp=file[ptr][i]);
  1642.     for(j=0;etmp[j];j++)
  1643.       if (patmatch(s,etmp[j])) {
  1644.         start = ptr;
  1645.         break;
  1646.       }
  1647.     if (tmp != etmp[0])
  1648.       for(j=0;etmp[j];j++) free(etmp[j]);
  1649.     free(etmp);
  1650.       }
  1651.     } else if (!l && !start && !strcmp("default",file[ptr][0])) {
  1652.       start = ptr;
  1653.     } else if (!strcmp("switch",file[ptr][0])) l++;
  1654.     else if (l && !strcmp("endsw",file[ptr][0])) l--;
  1655.     else if (!l && !strcmp("endsw",file[ptr][0])) {
  1656.       end = ptr;
  1657.       break;
  1658.     }
  1659.   }
  1660.   if (!end) {
  1661.     fprintf(ferr,"switch: switch without matching endsw.\n");
  1662.     return 1;
  1663.   }
  1664.   if (!start) {
  1665.     fptr = end;
  1666.     return 0;
  1667.   }
  1668.   fptr = start+1;
  1669.   while(fptr < end) {
  1670.     if (!strcmp("case",file[fptr][0]) || !strcmp("default",file[fptr][0])) {
  1671.       fptr++;
  1672.       continue;
  1673.     }
  1674.     run(fptr);
  1675.     if (err == ERR_BREAK) {
  1676.       fptr = end;
  1677.       err = 0;
  1678.       return 0;
  1679.     }
  1680.     if (err || badstat(_status)) {
  1681.       fptr = end;
  1682.       return _status&RET_MASK;
  1683.     }
  1684.     fptr++;
  1685.   }
  1686.   return 0;
  1687. }
  1688.  
  1689. ENDSW(ferr)
  1690. FILE *ferr;
  1691. {
  1692.   fprintf(ferr,"endsw: endsw without matching switch.\n");
  1693.   return 1;
  1694. }
  1695.  
  1696. usage(fout,ferr)
  1697. FILE *fout, *ferr;
  1698. {
  1699.   static struct rusage ru;
  1700.  
  1701.   getrusage(RUSAGE_SELF,&ru);
  1702.   a = ru.ru_utime.tv_sec;
  1703.   b = a%3600;
  1704.   c = b%60;
  1705.   fprintf(fout,"USER time: %02d:%02d:%02d.%06d\t",a/3600,b/60,c,ru.ru_utime.tv_usec);
  1706.   a = ru.ru_stime.tv_sec;
  1707.   b = a%3600;
  1708.   c = b%60;
  1709.   fprintf(fout,"SYSTEM time: %02d:%02d:%02d.%06d\n",a/3600,b/60,c,ru.ru_stime.tv_usec);
  1710.   fprintf(fout,"MAX RSS: %dK\tPage Reclaims: %d\t Page faults: %d\n",(ru.ru_maxrss*getpagesize())/1024,ru.ru_minflt,ru.ru_majflt);
  1711.   fprintf(fout,"SWAPS: %d\tBlocks In: %d\tBlocks Out: %d\tSignals: %d\n",ru.ru_nswap,ru.ru_inblock,ru.ru_oublock,ru.ru_nsignals);
  1712.   return 0;
  1713. }
  1714.  
  1715. isnum(w)
  1716. char *w;
  1717. {
  1718.   while(*w) if (!isdigit(*w++)) return FALSE;
  1719.   return TRUE;
  1720. }
  1721.  
  1722. INTR(n,arg,fout,ferr)
  1723. int n;
  1724. char **arg;
  1725. FILE *fout, *ferr;
  1726. {
  1727.   static char *sigs[] = {
  1728.     "HUP","INT","QUIT","ILL","TRAP","IOT","EMT","FPE","KILL","BUS","SEGV",
  1729.     "SYS","PIPE","ALRM","TERM","URG","STOP","TSTP","CONT","CHLD","TTIN",
  1730.     "TTOU","IO","XCPU","XFSZ","VTALRM","PROF","WINCH","USR1","USR2",0
  1731.   };
  1732.  
  1733.   if (n == 1) {
  1734.     for(a=0;sigs[a];a++)
  1735.       if (SIGMASK&(1<<a))
  1736.     fprintf(fout,"%s%s",a?" ":"",sigs[a]);
  1737.     fputc('\n',fout);
  1738.     return 0;
  1739.   }
  1740.   for(a=1;arg[a];a++) {
  1741.     if (arg[a][0] == '-' && !arg[a][1]) SIGMASK = 0;
  1742.     else if (arg[a][0] == '+' && !arg[a][1]) SIGMASK = 0xFFFFFFFF;
  1743.     else {
  1744.       for(b=0;sigs[b];b++) {
  1745.     if (!strcmp(sigs[b],arg[a])) {
  1746.       SIGMASK ^= (1<<b);
  1747.       break;
  1748.     }
  1749.       }
  1750.       if (!sigs[b]) {
  1751.     fprintf(ferr,"intr: %s: invalid argument.\n",arg[a]);
  1752.     return 1;
  1753.       }
  1754.     }
  1755.   }
  1756.   return 0;
  1757. }
  1758.  
  1759. TERM(n,arg,fout,ferr)
  1760. int n;
  1761. char **arg;
  1762. FILE *fout, *ferr;
  1763. {
  1764.   static char *t[12] = {"SO","SE","CE","KS","KE","DC","IC","DS","TC","FS","HS",0};
  1765.   struct _setvar *VAR;
  1766.  
  1767.   if (n == 1) {
  1768.     if ((VAR = find_var("term")) != NULL) fprintf(fout,"term: %s\n",VAR->sv.wrd[0]);
  1769.     for(a=0;a<10;a++) {
  1770.       fprintf(fout,"%s\t",t[a]);
  1771.       if (_term[a]) {
  1772.         fputc('\042',fout);
  1773.         fprt(fout,_term[a]);
  1774.         fputc('\042',fout);
  1775.       } else fputs("<undefined>",fout);
  1776.       fputc('\n',fout);
  1777.     }
  1778.     fprintf(fout,"HS\t%d\n",_term[HS]);
  1779.     return 0;
  1780.   } else {
  1781.     if (n == 2) {
  1782.       for(a=0;t[a];a++) {
  1783.         if (!strcmp(t[a],arg[1])) {
  1784.       if (a == HS) fprintf(fout,"HS\t%d\n",_term[HS]);
  1785.       else {
  1786.         fprintf(fout,"%s\t",t[a]);
  1787.         if (_term[a]) {
  1788.           fputc('\042',fout);
  1789.           fprt(fout,_term[a]);
  1790.           fputc('\042',fout);
  1791.         } else fputs("<undefined>",fout);
  1792.         fputc('\n',fout);
  1793.       }
  1794.       return 0;
  1795.     }
  1796.       }
  1797.       fprintf(ferr,"term: %s not found.\n",arg[1]);
  1798.       return 1;
  1799.     } else {
  1800.       for(a=0;t[a];a++) {
  1801.         if (!strcmp(t[a],arg[1])) {
  1802.       if (a == HS) _term[HS] = (char *)atoi(arg[2]);
  1803.       else {
  1804.         free(_term[a]);
  1805.         _term[a] = string(arg+2);
  1806.         if (!strlen(_term[a])) {
  1807.           free(_term[a]);
  1808.           _term[a] = NULL;
  1809.         }
  1810.       }
  1811.       return 0;
  1812.     }
  1813.       }
  1814.       fprintf(ferr,"term: %s not found.\n",arg[1]);
  1815.       return 1;
  1816.     }
  1817.   }
  1818. }
  1819.  
  1820. PROTECT(n,arg,ferr)
  1821. int n;
  1822. char **arg;
  1823. FILE *ferr;
  1824. {
  1825.   struct _setvar *VAR;
  1826.  
  1827.   if (n < 2) {
  1828.     fprintf(ferr,"protect: missing argument.\n");
  1829.     return 1;
  1830.   }
  1831.   if ((VAR = find_var(arg[1])) == NULL) {
  1832.     fprintf(ferr,"protect: %s not found.\n",arg[1]);
  1833.     return 1;
  1834.   }
  1835.   VAR->protect = 1;
  1836.   return 0;
  1837. }
  1838.  
  1839. #ifdef NOSETENV
  1840. extern char **environ;
  1841. extern int errno;
  1842.  
  1843. int setenv(name,value,overwrite)
  1844. char *name, *value;
  1845. int overwrite;
  1846. {
  1847.   int i, l = strlen(name);
  1848.   char **tmp, **se = environ;
  1849.  
  1850.   if (name[l-1] == '=') l--;
  1851.   for(i=0;environ[i];i++) {
  1852.     if (!strncmp(name,environ[i],l) && environ[i][l] == '=') {
  1853.       if (overwrite) {
  1854.         free(environ[i]);
  1855.     break;
  1856.       }
  1857.       return 0;
  1858.     }
  1859.   }
  1860.   if (!environ[i]) {
  1861.     if ((environ = (char **)realloc(environ,sizeof(char *)*(i+2))) == NULL) {
  1862.       if (errno == EINVAL) {
  1863.     if ((tmp = (char **)malloc(sizeof(char *) * (i+2))) == NULL) return -1;
  1864.     for(i=0;se[i];i++) tmp[i] = se[i];
  1865.     environ = tmp;
  1866.       } else return -1;
  1867.     }
  1868.     environ[i+1] = NULL;
  1869.   }
  1870.   if ((environ[i] = (char *)malloc(l+strlen(value)+2)) == NULL) return -1;
  1871.   sprintf(environ[i],"%.*s=%s",l,name,value[0]=='='?value+1:value);
  1872.   return 0;
  1873. }
  1874.  
  1875. void unsetenv(name)
  1876. char *name;
  1877. {
  1878.   int i = 0, j, f = 0, l = strlen(name);
  1879.  
  1880.   if (name[l-1] == '=') l--;
  1881.   while(environ[i]) {
  1882.     if (!strncmp(name,environ[i],l) && environ[i][l] == '=') {
  1883.       f = 1;
  1884.       free(environ[i]);
  1885.       for(j=i;environ[j];j++) environ[j] = environ[j+1];
  1886.     } else i++;
  1887.   }
  1888. /*  if (f) environ = (char **)realloc(environ,sizeof(char *) * i+1); */
  1889. }
  1890. #endif
  1891.