home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / c / csh4.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1985-09-05  |  12KB  |  516 lines

  1. #include <debug.h>
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <signal.h>
  5. #include <fcntl.h>
  6. #include <setjmp.h>
  7. typedef struct        /* used to find builtin commands */
  8. {
  9.     char *cmdname;
  10.     int (*func)();
  11. } builtin;
  12.  
  13. extern builtin commands[];
  14. extern char histerr[];
  15. extern int j,hiscount;
  16. extern char *history[];
  17. extern int histsize;
  18. extern int numcmds;
  19.  
  20. char *version = "SHELL VERSION 1.1 Kent Williams";
  21.  
  22. jmp_buf env;
  23.  
  24. char *pipename[] =
  25. {
  26.     "\\shtmp1",
  27.     "\\shtmp2"
  28. };
  29.  
  30. char cmdbuf[512];
  31. int  currname = 0;
  32. int result = 0;
  33.  
  34. main(argc,argv)
  35.     char *argv[];
  36. {
  37.     register int i;
  38.     int repeat, quiet, state, inpipe = 0;
  39.     static char localbuf[256];
  40.     static char histbuf[256];
  41.     static char tail[256];
  42.     int histindex,argindex,takeline;
  43.     char *local = localbuf;
  44.     register char *current,*curr_save;
  45.     char *ntharg(), *argptr;
  46.     char *savestr();
  47.  
  48.     signal(SIGINT,SIG_IGN);    /* ignore breaks */
  49.  
  50.     quiet = !isatty(0);        /* quiet = batch shell */
  51.  
  52.     /* initialize local environment */
  53.     init_env();
  54.     /* command interpreter loop */
  55.     for(j=0;;)
  56.     {
  57.         /* kill tmp files */
  58.         unlink(pipename[0]); unlink(pipename[1]);
  59.  
  60.         hiscount = j % histsize; /* hiscount is current position in history */
  61.         if(!quiet)
  62.             fprintf(stderr,"%d%% ",j);
  63.  
  64. /*
  65.  * The following code simply reads a line from standard input.
  66.  * It is so complicated because when you save the standard stream
  67.  * files and execute another program/command, standard input is
  68.  * left in an uncertain state - the FILE stdin seems to be at EOF,
  69.  * even when standard input is associated with the console, and
  70.  * cr/lf combinations show up as line terminators, whereas usually
  71.  * only linefeeds get placed in the input stream.
  72.  * WHY? beats me.  Something could be wrong with
  73.  *  1. AZTEC C runtime
  74.  *  2. PCDOS
  75.  *  3. Me
  76.  *  4. All three, or permutations of 1-3 reducto ad absurdum.
  77.  * All I know is this works
  78.  */
  79.         /* clear command buffer so string read is null terminated */
  80.         setmem(cmdbuf,sizeof(cmdbuf),0);
  81.         for (current = cmdbuf;;current++)
  82.         {
  83.             int readresult;
  84.             if ((readresult = read(0,current,1)) == 0 ||
  85.                 readresult == -1)
  86.             {
  87.                 exit (0);
  88.             }
  89.             if (*current == '\r')
  90.             {
  91.                 if ((readresult = read(0,current,1)) == 0 ||
  92.                     readresult == -1)
  93.                 {
  94.                     exit (0);
  95.                 }
  96.                 *current = '\0';
  97.                 break;
  98.             }
  99.             else if (*current == '\n')
  100.             {
  101.                 *current = '\0';    /* terminate string */
  102.                 break;
  103.             }
  104.         }
  105.         current = cmdbuf;    /* point current at start of buffer */
  106. /*
  107.  * end of input weirdness
  108.  */
  109.         /* if we're recycling history strings, free previous one */
  110.         if (history[hiscount])
  111.             free(history[hiscount]);
  112.  
  113.         /* save current in history array */
  114.         history[hiscount] = savestr(current);
  115.  
  116. #define CHAR            -1
  117. #define PIPE            -2
  118. #define DOUBLEQUOTES     -3
  119. #define SINGLEQUOTES     -4
  120. #define EMIT             -5
  121. #define COMPOUND         -6
  122. #define DONE            -7
  123. #define EATWHITESPACE    -8
  124. #define HISTORY            -9
  125. #define CONTINUE        -0xA
  126.  
  127.         /* parse command for compound statements and pipes */
  128.         state = EATWHITESPACE;
  129.         local = localbuf;
  130.         setmem(localbuf,sizeof(localbuf),0);    /* clear buffer */
  131.         while (state != DONE && state != CONTINUE)
  132.         {
  133.             switch(state)
  134.             {
  135.             case CHAR:
  136.                 switch(*current)
  137.                 {
  138.                 case '\0':
  139.                     *local = '\0';
  140.                     state = EMIT;
  141.                     break;
  142.                 case '"' :
  143.                     state = DOUBLEQUOTES;
  144.                     *local++ = *current;
  145.                     break;
  146.                 case '/' :
  147.                     *local++ = '\\';
  148.                     break;
  149.                 case '\'':
  150.                     state = SINGLEQUOTES;
  151.                     *local++ = *current;
  152.                     break;
  153.                 case '\\':
  154.                     *local++ = *++current;
  155.                     break;
  156.                 case ';':
  157.                     *local = '\0';
  158.                     state = COMPOUND;
  159.                     break;
  160.                 case '|':
  161.                     *local = '\0';
  162.                     state = PIPE;
  163.                     break;
  164.                 case '!':
  165.                     state = HISTORY;
  166.                     break;
  167.                 default:
  168.                     *local++ = *current;
  169.                     break;
  170.                 }
  171.                 current++;
  172.                 break;
  173.             case EMIT:
  174.                 if (inpipe)
  175.                 {
  176.                     inpipe = 0;
  177.                     strcat(localbuf," < ");
  178.                     strcat(localbuf,pipename[currname]);
  179.                 }
  180.                 command(localbuf);
  181.                 state = DONE;
  182.                 break;
  183.             case COMPOUND:
  184.                 if (inpipe)
  185.                 {
  186.                     inpipe = 0;
  187.                     strcat(localbuf," < ");
  188.                     strcat(localbuf,pipename[currname]);
  189.                 }
  190.                 command(localbuf);
  191.                 local = localbuf;
  192.                 setmem(localbuf,sizeof(localbuf),0);    /* clear buffer */
  193.                 state = EATWHITESPACE;
  194.                 break;
  195.             case SINGLEQUOTES:
  196.                 switch (*current)
  197.                 {
  198.                 case '\0':
  199.                     write(2,"No closing quotes!!\r\n",21);
  200.                     state = DONE;
  201.                     break;
  202.                 case '\'':
  203.                     state = CHAR;
  204.                     *local++ = *current;
  205.                     break;
  206. #ifdef TEST
  207.                 case '\\':
  208.                     *local++ = *++current;
  209.                     break;
  210. #endif
  211.                 default:
  212.                     *local++ = *current;
  213.                 }
  214.                 current++;    
  215.                 break;
  216.             case DOUBLEQUOTES:
  217.                 switch(*current)
  218.                 {
  219.                 case '\0':
  220.                     write(2,"No closing quotes!!\r\n",21);
  221.                     state = DONE;
  222.                     break;
  223.                 case '"':
  224.                     state = CHAR;
  225.                     break;
  226. #ifdef TEST
  227.                 case '\\':
  228.                     ++current;
  229.                     break;
  230. #endif
  231.                 }
  232.                 *local++ = *current++;
  233.                 break;
  234.             case HISTORY:
  235.                 /* handle history substitutions */
  236.                 setmem(histbuf,sizeof(histbuf),0);    /* clear buffer */
  237.  
  238.                 /* save current pointer into command buffer */
  239.                 curr_save = current;
  240.                 DEBUGGER(fprintf(stderr,"current = %s\n",current););
  241.  
  242.                 /* copy command head */
  243.                 strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1);
  244.  
  245.                 /* takeline means take all arguments past current one */
  246.                 takeline = 0;
  247.  
  248.                 /* parse history expression */
  249.                 switch (*current)
  250.                 {
  251.                 case '!':    /* last command line */
  252.  
  253.                 DEBUGGER(fprintf(stderr,"last command\n"););
  254.                     if (j)    /* special case first time through */
  255.                     {
  256.                         histindex = hiscount ? hiscount - 1 : histsize - 1;
  257.                     }
  258.                     else
  259.                     {
  260.                         /* force error condition */
  261.                         write(2,histerr,strlen(histerr));
  262.                         state = CONTINUE;
  263.                     }
  264.                     current++;    /* point to next */
  265.                     break;
  266.                 case '-':        /* negative (relative #) */
  267.                 /* a particular numbered command */
  268.                 case '0':
  269.                 case '1':
  270.                 case '2':
  271.                 case '3':
  272.                 case '4':
  273.                 case '5':
  274.                 case '6':
  275.                 case '7':
  276.                 case '8':
  277.                 case '9':
  278.                     DEBUGGER(fprintf(stderr,\
  279.                     "numbered command current = %s\n",current););
  280.                     /* repeat numbered command */
  281.                     repeat = atoi(current);
  282.                     if (repeat < 0)    /* handle relative addressing */
  283.                         repeat += j;
  284.                     /* if command is within range */
  285.                     if ((j - repeat) <= histsize && repeat < j)
  286.                     {
  287.                         histindex = repeat % histsize;
  288.                     }
  289.                     else
  290.                     {
  291.                         state = CONTINUE;
  292.                     }
  293.  
  294.                     DEBUGGER(fprintf(stderr,"number %d\n",histindex););
  295.                     while(isdigit(*current)||*current=='-')
  296.                         ++current;
  297.                     break;
  298.                 default:
  299.                     write(2,"Bad history expression\r\n",24);
  300.                     state = CONTINUE;
  301.                     break;
  302.                 }
  303.                 if (state == CONTINUE)    /* error state */
  304.                     break;    
  305.                 /* look for particular argument substitutions */
  306.                 DEBUGGER(fprintf(stderr,\
  307.                     "looking for colon expression, current = %s\n",current););
  308.                 switch (*current)
  309.                 {
  310.                 /* we want the whole enchilada */
  311.                 case '\0':
  312.                 case '\t':
  313.                 case '\r':
  314.                 case '\n':
  315.                 case ' ':
  316.                     DEBUGGER(fprintf(stderr,"whole cmdline\n"););
  317.                     DEBUGGER(fprintf(stderr,"current = %s\n",current););
  318.                     strcat(histbuf,history[histindex]);
  319.                     state = CHAR;
  320.                     break;
  321.                 case ':':
  322.                     ++current;    /* point past colon */
  323.                 DEBUGGER(fprintf(stderr,"current = %s\n",current););
  324.                     switch (*current)
  325.                     {
  326.                     case '^':
  327.                         argindex = 1;
  328.                         ++current;
  329.                         break;
  330.                     case '0':
  331.                     case '1':
  332.                     case '2':
  333.                     case '3':
  334.                     case '4':
  335.                     case '5':
  336.                     case '6':
  337.                     case '7':
  338.                     case '8':
  339.                     case '9':
  340.                         /* index of argument */ 
  341.                         argindex = atoi(current);
  342.                         DEBUGGER(fprintf(stderr,"%s = %d\n",current,argindex););
  343.                         while(isdigit(*current))
  344.                             ++current;
  345.                         if (*current = '*')
  346.                         {
  347.                             takeline = 1;
  348.                             current++;
  349.                         }
  350.                         break;
  351.                     case '$':
  352.                         argindex = lastarg(history[histindex]);
  353.                         current++;
  354.                         break;
  355.                     case '*':
  356.                         takeline = 1;    /* take arg 1 through arg n */
  357.                         argindex = 1;
  358.                         current++;
  359.                         break;
  360.                     default:
  361.                         state = CONTINUE;
  362.                         break;
  363.                     }
  364.                     DEBUGGER(fprintf(stderr,"arg %d\n",argindex););
  365.                     if (state == CONTINUE)
  366.                         break;
  367.                     /* pick up pointer to argument in history we need */
  368.                     if (takeline == 0)
  369.                     {
  370.                         if (NULL == 
  371.                             (argptr = ntharg(history[histindex],argindex)))
  372.                         {
  373.  
  374.                         DEBUGGER(fprintf(stderr,"can't find ntharg"););
  375.                             state = CONTINUE;
  376.                             break;
  377.                         }
  378.                         strcat(histbuf,argptr);
  379.                     }
  380.                     else
  381.                     {
  382.                         while (NULL !=
  383.                             (argptr = ntharg(history[histindex],argindex++)))
  384.                         {
  385.                             strcat(histbuf,argptr);
  386.                             strcat(histbuf," ");
  387.                         }
  388.                     }
  389.                 }
  390.                 if (state == CONTINUE)
  391.                     break;
  392.                 /* history substitutions */
  393.                 /* copy command buffer tail to tail buffer */
  394.                 strcpy(tail,current);
  395.                 /* copy histbuf back to cmdbuf */
  396.                 strcpy(cmdbuf,histbuf);
  397.                 /* point current at history substitution to continue parsing */
  398.                 current = --curr_save; /* -1 to backup over first ! */
  399.                 /* copy tail in */
  400.                 strcat(cmdbuf,tail);
  401.                 DEBUGGER(fprintf(stderr,"current = %s\n",current);)
  402.                 DEBUGGER(fprintf(stderr,"cmdbuf = %s\n",cmdbuf);)
  403.                 free(history[hiscount]);
  404.                 history[hiscount] = savestr(cmdbuf);
  405.                 state = CHAR;
  406.                 break;
  407.             case PIPE:
  408.                 if (inpipe++)
  409.                 {
  410.                     inpipe = 1;
  411.                     strcat(localbuf," < ");
  412.                     strcat(localbuf,pipename[currname]);
  413.                 }
  414.                 strcat(localbuf," > ");
  415.                 currname ^= 1;
  416.                 strcat(localbuf,pipename[currname]);
  417.                 command(localbuf);
  418.                 local = localbuf;
  419.                 setmem(localbuf,sizeof(localbuf),0);
  420.                 state = EATWHITESPACE;
  421.                 break;
  422.             case EATWHITESPACE:
  423.                 /* strip out leading white space */
  424.                 while(isspace(*current))
  425.                     current++;
  426.                 if (!*current)
  427.                     state = CONTINUE;
  428.                 else
  429.                     state = CHAR;
  430.                 break;
  431.             default:
  432.                 fprintf(stderr,"Bad state parsing command line\n");
  433.                 state = DONE;
  434.                 break;
  435.             }
  436.         }
  437.         if (state == CONTINUE)
  438.             continue;
  439.         j++;    /* next command # */
  440.     }
  441. }
  442.  
  443. onintr()
  444. {
  445.     longjmp(env,-1);
  446. }
  447.  
  448. command(current)
  449.     register char *current;
  450. {
  451.     extern do_prog();
  452.     register int i;
  453.     DEBUGGER(write(2,current,strlen(current)); crlf();)
  454.     std_save();
  455.     if (-1 == (i = findcmd(current)))
  456.         result = _Croot(current,do_prog);
  457.     else
  458.     {
  459.         if (!setjmp(env))
  460.         {
  461.             signal(SIGINT,onintr);
  462.             result = _Croot(current,commands[i].func);
  463.         }
  464.         signal(SIGINT,SIG_IGN);
  465.     }
  466.     std_restore();
  467. }
  468.  
  469. char *
  470. ntharg(line,index)
  471. register char *line;
  472. {
  473.     register int i;
  474.     static char buf[64];
  475.     char *bptr;
  476.     for (i = 0; *line;i++)
  477.     {
  478.         /* find start of arg[i] */
  479.         while(*line && isspace(*line))
  480.         {
  481.             ++line;
  482.         }
  483.         /* if this is start of requested arg, return pointer to it */
  484.         if (i == index)
  485.         {
  486.             DEBUGGER(fprintf(stderr,"Found arg %d = %s\n",index,line););
  487.             bptr = buf;
  488.             while(*line && !isspace(*line))
  489.                 *bptr++ = *line++;
  490.             *bptr = '\0';
  491.             return buf;
  492.         }
  493.         /* find end of arg[i] */
  494.         while(*line && !isspace(*line))
  495.             ++line;
  496.     }
  497.     return NULL;
  498. }
  499.  
  500. lastarg(line)
  501. register char *line;
  502. {
  503.     register int i;
  504.  
  505.     for (i = 0; *line;i++)
  506.     {
  507.         /* find start of arg[i] */
  508.         while(*line && isspace(*line))
  509.             ++line;
  510.         /* find end of arg[i] */
  511.         while(*line && !isspace(*line))
  512.             ++line;
  513.     }
  514.     return i-1;
  515. }
  516.