home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 198_01 / exec.c < prev    next >
C/C++ Source or Header  |  1990-01-23  |  25KB  |  1,183 lines

  1. /*    This file is for functions dealing with execution of
  2.     commands, command lines, buffers, files and startup files
  3.  
  4.     written 1986 by Daniel Lawrence                */
  5.  
  6. #include    <stdio.h>
  7. #include    "estruct.h"
  8. #include    "edef.h"
  9.  
  10. /* namedcmd:    execute a named command even if it is not bound */
  11.  
  12. namedcmd(f, n)
  13.  
  14. int f, n;    /* command arguments [passed through to command executed] */
  15.  
  16. {
  17.     register (*kfunc)();    /* ptr to the requexted function to bind to */
  18.     int (*getname())();
  19.  
  20.     /* prompt the user to type a named command */
  21.     mlwrite(": ");
  22.  
  23.     /* and now get the function name to execute */
  24.     kfunc = getname();
  25.     if (kfunc == NULL) {
  26.         mlwrite("[No such function]");
  27.         return(FALSE);
  28.     }
  29.  
  30.     /* and then execute the command */
  31.     return((*kfunc)(f, n));
  32. }
  33.  
  34. /*    execcmd:    Execute a command line command to be typed in
  35.             by the user                    */
  36.  
  37. execcmd(f, n)
  38.  
  39. int f, n;    /* default Flag and Numeric argument */
  40.  
  41. {
  42.     register int status;        /* status return */
  43.     char cmdstr[NSTRING];        /* string holding command to execute */
  44.  
  45.     /* get the line wanted */
  46.     if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  47.         return(status);
  48.  
  49.     execlevel = 0;
  50.     return(docmd(cmdstr));
  51. }
  52.  
  53. /*    docmd:    take a passed string as a command line and translate
  54.         it to be executed as a command. This function will be
  55.         used by execute-command-line and by all source and
  56.         startup files. Lastflag/thisflag is also updated.
  57.  
  58.     format of the command line is:
  59.  
  60.         {# arg} <command-name> {<argument string(s)>}
  61.  
  62. */
  63.  
  64. docmd(cline)
  65.  
  66. char *cline;    /* command line to execute */
  67.  
  68. {
  69.     register int f;        /* default argument flag */
  70.     register int n;        /* numeric repeat value */
  71.     int (*fnc)();        /* function to execute */
  72.     int status;        /* return status of function */
  73.     int oldcle;        /* old contents of clexec flag */
  74.     char *oldestr;        /* original exec string */
  75.     char tkn[NSTRING];    /* next token off of command line */
  76.     int (*fncmatch())();
  77.         
  78.     /* if we are scanning and not executing..go back here */
  79.     if (execlevel)
  80.         return(TRUE);
  81.  
  82.     oldestr = execstr;    /* save last ptr to string to execute */
  83.     execstr = cline;    /* and set this one as current */
  84.  
  85.     /* first set up the default command values */
  86.     f = FALSE;
  87.     n = 1;
  88.     lastflag = thisflag;
  89.     thisflag = 0;
  90.  
  91.     if ((status = macarg(tkn)) != TRUE) {    /* and grab the first token */
  92.         execstr = oldestr;
  93.         return(status);
  94.     }
  95.  
  96.     /* process leadin argument */
  97.     if (gettyp(tkn) != TKCMD) {
  98.         f = TRUE;
  99.         strcpy(tkn, getval(tkn));
  100.         n = atoi(tkn);
  101.  
  102.         /* and now get the command to execute */
  103.         if ((status = macarg(tkn)) != TRUE) {
  104.             execstr = oldestr;
  105.             return(status);    
  106.         }    
  107.     }
  108.  
  109.     /* and match the token to see if it exists */
  110.     if ((fnc = fncmatch(tkn)) == NULL) {
  111.         mlwrite("[No such Function]");
  112.         execstr = oldestr;
  113.         return(FALSE);
  114.     }
  115.     
  116.     /* save the arguments and go execute the command */
  117.     oldcle = clexec;        /* save old clexec flag */
  118.     clexec = TRUE;            /* in cline execution */
  119.     status = (*fnc)(f, n);        /* call the function */
  120.     cmdstatus = status;        /* save the status */
  121.     clexec = oldcle;        /* restore clexec flag */
  122.     execstr = oldestr;
  123.     return(status);
  124. }
  125.  
  126. /* token:    chop a token off a string
  127.         return a pointer past the token
  128. */
  129.  
  130. char *token(src, tok, size)
  131.  
  132. char *src, *tok;    /* source string, destination token string */
  133. int size;        /* maximum size of token */
  134.  
  135. {
  136.     register int quotef;    /* is the current string quoted? */
  137.     register char c;    /* temporary character */
  138.  
  139.     /* first scan past any whitespace in the source string */
  140.     while (*src == ' ' || *src == '\t')
  141.         ++src;
  142.  
  143.     /* scan through the source string */
  144.     quotef = FALSE;
  145.     while (*src) {
  146.         /* process special characters */
  147.         if (*src == '~') {
  148.             ++src;
  149.             if (*src == 0)
  150.                 break;
  151.             switch (*src++) {
  152.                 case 'r':    c = 13; break;
  153.                 case 'n':    c = 10; break;
  154.                 case 'l':    c = 10; break;
  155.                 case 't':    c = 9;  break;
  156.                 case 'b':    c = 8;  break;
  157.                 case 'f':    c = 12; break;
  158.                 default:    c = *(src-1);
  159.             }
  160.             if (--size > 0) *tok++ = c;
  161.         } else {
  162.             /* check for the end of the token */
  163.             if (quotef) {
  164.                 if (*src == '"')
  165.                     break;
  166.             } else {
  167.                 if (*src == ' ' || *src == '\t')
  168.                     break;
  169.             }
  170.  
  171.             /* set quote mode if qoute found */
  172.             if (*src == '"')
  173.                 quotef = TRUE;
  174.  
  175.             /* record the character */
  176.             c = *src++;
  177.             if (--size > 0) *tok++ = c;
  178.         }
  179.     }
  180.  
  181.     /* terminate the token and exit */
  182.     if (*src)
  183.         ++src;
  184.     *tok = 0;
  185.     return(src);
  186. }
  187.  
  188. macarg(tok)    /* get a macro line argument */
  189.  
  190. char *tok;    /* buffer to place argument */
  191.  
  192. {
  193.     int savcle;    /* buffer to store original clexec */
  194.     int status;
  195.  
  196.     savcle = clexec;    /* save execution mode */
  197.     clexec = TRUE;        /* get the argument */
  198.     status = nextarg("", tok, NSTRING, ctoec('\n'));
  199.     clexec = savcle;    /* restore execution mode */
  200.     return(status);
  201. }
  202.  
  203. /*    nextarg:    get the next argument    */
  204.  
  205. nextarg(prompt, buffer, size, terminator)
  206.  
  207. char *prompt;        /* prompt to use if we must be interactive */
  208. char *buffer;        /* buffer to put token into */
  209. int size;        /* size of the buffer */
  210. int terminator;        /* terminating char to be used on interactive fetch */
  211.  
  212. {
  213.     register char *sp;    /* return pointer from getval */
  214.  
  215.     /* if we are interactive, go get it! */
  216.     if (clexec == FALSE)
  217.         return(getstring(prompt, buffer, size, terminator));
  218.  
  219.     /* grab token and advance past */
  220.     execstr = token(execstr, buffer, size);
  221.  
  222.     /* evaluate it */
  223.     if ((sp = getval(buffer)) == NULL) return(FALSE);
  224.     strcpy(buffer, sp);
  225.     return(TRUE);
  226. }
  227.  
  228. /*    storemac:    Set up a macro buffer and flag to store all
  229.             executed command lines there            */
  230.  
  231. storemac(f, n)
  232.  
  233. int f;        /* default flag */
  234. int n;        /* macro number to use */
  235.  
  236. {
  237.     register BUFFER *bp;        /* pointer to macro buffer */
  238.     char bname[NBUFN];        /* name of buffer to use */
  239.  
  240.     /* must have a numeric argument to this function */
  241.     if (f == FALSE) {
  242.         mlwrite("No macro specified");
  243.         return(FALSE);
  244.     }
  245.  
  246.     /* range check the macro number */
  247.     if (n < 1 || n > 40) {
  248.         mlwrite("Macro number out of range");
  249.         return(FALSE);
  250.     }
  251.  
  252.     /* construct the macro buffer name */
  253.     strcpy(bname, "[Macro xx]");
  254.     bname[7] = '0' + (n / 10);
  255.     bname[8] = '0' + (n % 10);
  256.  
  257.     /* set up the new macro buffer */
  258.     if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  259.         mlwrite("Can not create macro");
  260.         return(FALSE);
  261.     }
  262.  
  263.     /* and make sure it is empty */
  264.     bclear(bp);
  265.  
  266.     /* and set the macro store pointers to it */
  267.     mstore = TRUE;
  268.     bstore = bp;
  269.     return(TRUE);
  270. }
  271.  
  272. #if    PROC
  273. /*    storeproc:    Set up a procedure buffer and flag to store all
  274.             executed command lines there            */
  275.  
  276. storeproc(f, n)
  277.  
  278. int f;        /* default flag */
  279. int n;        /* macro number to use */
  280.  
  281. {
  282.     register BUFFER *bp;        /* pointer to macro buffer */
  283.     register int status;        /* return status */
  284.     char bname[NBUFN];        /* name of buffer to use */
  285.  
  286.     /* a numeric argument means its a numbered macro */
  287.     if (f == TRUE)
  288.         return(storemac(f, n));
  289.  
  290.     /* get the name of the procedure */
  291.         if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
  292.                 return(status);
  293.  
  294.     /* construct the macro buffer name */
  295.     bname[0] = '[';
  296.     strcat(bname, "]");
  297.  
  298.     /* set up the new macro buffer */
  299.     if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  300.         mlwrite("Can not create macro");
  301.         return(FALSE);
  302.     }
  303.  
  304.     /* and make sure it is empty */
  305.     bclear(bp);
  306.  
  307.     /* and set the macro store pointers to it */
  308.     mstore = TRUE;
  309.     bstore = bp;
  310.     return(TRUE);
  311. }
  312.  
  313. /*    execproc:    Execute a procedure                */
  314.  
  315. execproc(f, n)
  316.  
  317. int f, n;    /* default flag and numeric arg */
  318.  
  319. {
  320.         register BUFFER *bp;        /* ptr to buffer to execute */
  321.         register int status;        /* status return */
  322.         char bufn[NBUFN+2];        /* name of buffer to execute */
  323.  
  324.     /* find out what buffer the user wants to execute */
  325.         if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
  326.                 return(status);
  327.  
  328.     /* construct the buffer name */
  329.     bufn[0] = '[';
  330.     strcat(bufn, "]");
  331.  
  332.     /* find the pointer to that buffer */
  333.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  334.         mlwrite("No such procedure");
  335.                 return(FALSE);
  336.         }
  337.  
  338.     /* and now execute it as asked */
  339.     while (n-- > 0)
  340.         if ((status = dobuf(bp)) != TRUE)
  341.             return(status);
  342.     return(TRUE);
  343. }
  344. #endif
  345.  
  346. /*    execbuf:    Execute the contents of a buffer of commands    */
  347.  
  348. execbuf(f, n)
  349.  
  350. int f, n;    /* default flag and numeric arg */
  351.  
  352. {
  353.         register BUFFER *bp;        /* ptr to buffer to execute */
  354.         register int    s;        /* status */
  355.  
  356. #if    BCOMPL
  357.         BUFFER *getdefb();
  358.  
  359.     /* make a completion for a buffer name */
  360.     bp = getdefb();
  361.     bp = tenexbuf(TRUE, "Execute buffer", bp ? bp->b_bname: "main");
  362. #else
  363.         char            bufn[NBUFN];
  364.  
  365.     /* find out what buffer the user wants to execute */
  366.         if ((s = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
  367.         return (s);
  368.  
  369.     /* find the pointer to that buffer */
  370.         bp=bfind(bufn, TRUE, 0);
  371. #endif
  372.  
  373.         if (bp == NULL) {
  374.         mlwrite("No such buffer");
  375.                 return(FALSE);
  376.         }
  377.  
  378.     /* and now execute it as asked */
  379.     while (n-- > 0)
  380.         if ((s = dobuf(bp)) != TRUE)
  381.             return(s);
  382.     return(TRUE);
  383. }
  384.  
  385. /*    dobuf:    execute the contents of the buffer pointed to
  386.         by the passed BP
  387.  
  388.     Directives start with a "!" and include:
  389.  
  390.     !endm        End a macro
  391.     !if (cond)    conditional execution
  392.     !else
  393.     !endif
  394.     !return        Return (terminating current macro)
  395.     !goto <label>    Jump to a label in the current macro
  396.     !force        Force macro to continue...even if command fails
  397.     !while (cond)    Execute a loop if the condition is true
  398.     !endwhile
  399.     
  400.     Line Labels begin with a "*" as the first nonblank char, like:
  401.  
  402.     *LBL01
  403. */
  404.  
  405. dobuf(bp)
  406.  
  407. BUFFER *bp;    /* buffer to execute */
  408.  
  409. {
  410.         register int status;    /* status return */
  411.     register LINE *lp;    /* pointer to line to execute */
  412.     register LINE *hlp;    /* pointer to line header */
  413.     register LINE *glp;    /* line to goto */
  414.     LINE *mp;        /* Macro line storage temp */
  415.     int dirnum;        /* directive index */
  416.     int linlen;        /* length of line to execute */
  417.     int i;            /* index */
  418.     int force;        /* force TRUE result? */
  419.     WINDOW *wp;        /* ptr to windows to scan */
  420.     WHBLOCK *whlist;    /* ptr to !WHILE list */
  421.     WHBLOCK *scanner;    /* ptr during scan */
  422.     WHBLOCK *whtemp;    /* temporary ptr to a WHBLOCK */
  423.     char *einit;        /* initial value of eline */
  424.     char *eline;        /* text of line to execute */
  425.     char tkn[NSTRING];    /* buffer to evaluate an expresion in */
  426.  
  427. #if    DEBUGM
  428.     char *sp;            /* temp for building debug string */
  429.     register char *ep;    /* ptr to end of outline */
  430. #endif
  431.  
  432.     /* clear IF level flags/while ptr */
  433.     execlevel = 0;
  434.     whlist = NULL;
  435.     scanner = NULL;
  436.  
  437.     /* scan the buffer to execute, building WHILE header blocks */
  438.     hlp = bp->b_linep;
  439.     lp = hlp->l_fp;
  440.     while (lp != hlp) {
  441.         /* scan the current line */
  442.         eline = lp->l_text;
  443.         i = lp->l_used;
  444.  
  445.         /* trim leading whitespace */
  446.         while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
  447.             ++eline;
  448.  
  449.         /* if theres nothing here, don't bother */
  450.         if (i <= 0)
  451.             goto nxtscan;
  452.  
  453.         /* if is a while directive, make a block... */
  454.         if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
  455.             whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  456.             if (whtemp == NULL) {
  457. noram:                mlwrite("%%Out of memory during while scan");
  458. failexit:            freewhile(scanner);
  459.                 freewhile(whlist);
  460.                 return(FALSE);
  461.             }
  462.             whtemp->w_begin = lp;
  463.             whtemp->w_type = BTWHILE;
  464.             whtemp->w_next = scanner;
  465.             scanner = whtemp;
  466.         }
  467.  
  468.         /* if is a BREAK directive, make a block... */
  469.         if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
  470.             if (scanner == NULL) {
  471.                 mlwrite("%%!BREAK outside of any !WHILE loop");
  472.                 goto failexit;
  473.             }
  474.             whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  475.             if (whtemp == NULL)
  476.                 goto noram;
  477.             whtemp->w_begin = lp;
  478.             whtemp->w_type = BTBREAK;
  479.             whtemp->w_next = scanner;
  480.             scanner = whtemp;
  481.         }
  482.  
  483.         /* if it is an endwhile directive, record the spot... */
  484.         if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
  485.             if (scanner == NULL) {
  486.                 mlwrite("%%!ENDWHILE with no preceding !WHILE in '%s'",
  487.                     bp->b_bname);
  488.                 goto failexit;
  489.             }
  490.             /* move top records from the scanner list to the
  491.                whlist until we have moved all BREAK records
  492.                and one WHILE record */
  493.             do {
  494.                 scanner->w_end = lp;
  495.                 whtemp = whlist;
  496.                 whlist = scanner;
  497.                 scanner = scanner->w_next;
  498.                 whlist->w_next = whtemp;
  499.             } while (whlist->w_type == BTBREAK);
  500.         }
  501.  
  502. nxtscan:    /* on to the next line */
  503.         lp = lp->l_fp;
  504.     }
  505.  
  506.     /* while and endwhile should match! */
  507.     if (scanner != NULL) {
  508.         mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'",
  509.             bp->b_bname);
  510.         goto failexit;
  511.     }
  512.  
  513.     /* let the first command inherit the flags from the last one..*/
  514.     thisflag = lastflag;
  515.  
  516.     /* starting at the beginning of the buffer */
  517.     hlp = bp->b_linep;
  518.     lp = hlp->l_fp;
  519.     while (lp != hlp) {
  520.         /* allocate eline and copy macro line to it */
  521.         linlen = lp->l_used;
  522.         if ((einit = eline = malloc(linlen+1)) == NULL) {
  523.             mlwrite("%%Out of Memory during macro execution");
  524.             freewhile(whlist);
  525.             return(FALSE);
  526.         }
  527.         bytecopy(eline, lp->l_text, linlen);
  528.         eline[linlen] = 0;    /* make sure it ends */
  529.  
  530.         /* trim leading whitespace */
  531.         while (*eline == ' ' || *eline == '\t')
  532.             ++eline;
  533.  
  534.         /* dump comments and blank lines */
  535.         if (*eline == ';' || *eline == 0)
  536.             goto onward;
  537.  
  538. #if    DEBUGM
  539.         /* if $debug == TRUE, every line to execute
  540.            gets echoed and a key needs to be pressed to continue
  541.            ^G will abort the command */
  542.     
  543.         if (macbug) {
  544.             strcpy(outline, "<<<");
  545.     
  546.             /* debug macro name */
  547.             strcat(outline, bp->b_bname);
  548.             strcat(outline, ":");
  549.     
  550.             /* debug if levels */
  551.             strcat(outline, itoa(execlevel));
  552.             strcat(outline, ":");
  553.  
  554.             /* and lastly the line */
  555.             strcat(outline, eline);
  556.             strcat(outline, ">>>");
  557.     
  558.             /* change all '%' to ':' so mlwrite won't expect arguments */
  559.             sp = outline;
  560.             while (*sp)
  561.             if (*sp++ == '%') {
  562.                 /* advance to the end */
  563.                 ep = --sp;
  564.                 while (*ep++)
  565.                     ;
  566.                 /* null terminate the string one out */
  567.                 *(ep + 1) = 0;
  568.                 /* copy backwards */
  569.                 while(ep-- > sp)
  570.                     *(ep + 1) = *ep;
  571.  
  572.                 /* and advance sp past the new % */
  573.                 sp += 2;                    
  574.             }
  575.     
  576.             /* write out the debug line */
  577.             mlforce(outline);
  578.             update(TRUE);
  579.     
  580.             /* and get the keystroke */
  581.             if (get1key() == abortc) {
  582.                 mlforce("[Macro aborted]");
  583.                 freewhile(whlist);
  584.                 return(FALSE);
  585.             }
  586.         }
  587. #endif
  588.  
  589.         /* Parse directives here.... */
  590.         dirnum = -1;
  591.         if (*eline == '!') {
  592.             /* Find out which directive this is */
  593.             ++eline;
  594.             for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
  595.                 if (strncmp(eline, dname[dirnum],
  596.                             strlen(dname[dirnum])) == 0)
  597.                     break;
  598.  
  599.             /* and bitch if it's illegal */
  600.             if (dirnum == NUMDIRS) {
  601.                 mlwrite("%%Unknown Directive");
  602.                 freewhile(whlist);
  603.                 return(FALSE);
  604.             }
  605.  
  606.             /* service only the !ENDM macro here */
  607.             if (dirnum == DENDM) {
  608.                 mstore = FALSE;
  609.                 bstore = NULL;
  610.                 goto onward;
  611.             }
  612.  
  613.             /* restore the original eline....*/
  614.             --eline;
  615.         }
  616.  
  617.         /* if macro store is on, just salt this away */
  618.         if (mstore) {
  619.             /* allocate the space for the line */
  620.             linlen = strlen(eline);
  621.             if ((mp=lalloc(linlen)) == NULL) {
  622.                 mlwrite("Out of memory while storing macro");
  623.                 return (FALSE);
  624.             }
  625.     
  626.             /* copy the text into the new line */
  627.             for (i=0; i<linlen; ++i)
  628.                 lputc(mp, i, eline[i]);
  629.     
  630.             /* attach the line to the end of the buffer */
  631.                    bstore->b_linep->l_bp->l_fp = mp;
  632.             mp->l_bp = bstore->b_linep->l_bp;
  633.             bstore->b_linep->l_bp = mp;
  634.             mp->l_fp = bstore->b_linep;
  635.             goto onward;
  636.         }
  637.     
  638.  
  639.         force = FALSE;
  640.  
  641.         /* dump comments */
  642.         if (*eline == '*')
  643.             goto onward;
  644.  
  645.         /* now, execute directives */
  646.         if (dirnum != -1) {
  647.             /* skip past the directive */
  648.             while (*eline && *eline != ' ' && *eline != '\t')
  649.                 ++eline;
  650.             execstr = eline;
  651.  
  652.             switch (dirnum) {
  653.             case DIF:    /* IF directive */
  654.                 /* grab the value of the logical exp */
  655.                 if (execlevel == 0) {
  656.                     if (macarg(tkn) != TRUE)
  657.                         goto eexec;
  658.                     if (stol(tkn) == FALSE)
  659.                         ++execlevel;
  660.                 } else
  661.                     ++execlevel;
  662.                 goto onward;
  663.  
  664.             case DWHILE:    /* WHILE directive */
  665.                 /* grab the value of the logical exp */
  666.                 if (execlevel == 0) {
  667.                     if (macarg(tkn) != TRUE)
  668.                         goto eexec;
  669.                     if (stol(tkn) == TRUE)
  670.                         goto onward;
  671.                 }
  672.                 /* drop down and act just like !BREAK */
  673.  
  674.             case DBREAK:    /* BREAK directive */
  675.                 if (dirnum == DBREAK && execlevel)
  676.                     goto onward;
  677.  
  678.                 /* jump down to the endwhile */
  679.                 /* find the right while loop */
  680.                 whtemp = whlist;
  681.                 while (whtemp) {
  682.                     if (whtemp->w_begin == lp)
  683.                         break;
  684.                     whtemp = whtemp->w_next;
  685.                 }
  686.             
  687.                 if (whtemp == NULL) {
  688.                     mlwrite("%%Internal While loop error");
  689.                     freewhile(whlist);
  690.                     return(FALSE);
  691.                 }
  692.             
  693.                 /* reset the line pointer back.. */
  694.                 lp = whtemp->w_end;
  695.                 goto onward;
  696.  
  697.             case DELSE:    /* ELSE directive */
  698.                 if (execlevel == 1)
  699.                     --execlevel;
  700.                 else if (execlevel == 0 )
  701.                     ++execlevel;
  702.                 goto onward;
  703.  
  704.             case DENDIF:    /* ENDIF directive */
  705.                 if (execlevel)
  706.                     --execlevel;
  707.                 goto onward;
  708.  
  709.             case DGOTO:    /* GOTO directive */
  710.                 /* .....only if we are currently executing */
  711.                 if (execlevel == 0) {
  712.  
  713.                     /* grab label to jump to */
  714.                     eline = token(eline, golabel, NPAT);
  715.                     linlen = strlen(golabel);
  716.                     glp = hlp->l_fp;
  717.                     while (glp != hlp) {
  718.                         if (*glp->l_text == '*' &&
  719.                             (strncmp(&glp->l_text[1], golabel,
  720.                                     linlen) == 0)) {
  721.                             lp = glp;
  722.                             goto onward;
  723.                         }
  724.                         glp = glp->l_fp;
  725.                     }
  726.                     mlwrite("%%No such label");
  727.                     freewhile(whlist);
  728.                     return(FALSE);
  729.                 }
  730.                 goto onward;
  731.     
  732.             case DRETURN:    /* RETURN directive */
  733.                 if (execlevel == 0)
  734.                     goto eexec;
  735.                 goto onward;
  736.  
  737.             case DENDWHILE:    /* ENDWHILE directive */
  738.                 if (execlevel) {
  739.                     --execlevel;
  740.                     goto onward;
  741.                 } else {
  742.                     /* find the right while loop */
  743.                     whtemp = whlist;
  744.                     while (whtemp) {
  745.                         if (whtemp->w_type == BTWHILE &&
  746.                             whtemp->w_end == lp)
  747.                             break;
  748.                         whtemp = whtemp->w_next;
  749.                     }
  750.         
  751.                     if (whtemp == NULL) {
  752.                         mlwrite("%%Internal While loop error");
  753.                         freewhile(whlist);
  754.                         return(FALSE);
  755.                     }
  756.         
  757.                     /* reset the line pointer back.. */
  758.                     lp = whtemp->w_begin->l_bp;
  759.                     goto onward;
  760.                 }
  761.  
  762.             case DFORCE:    /* FORCE directive */
  763.                 force = TRUE;
  764.  
  765.             }
  766.         }
  767.  
  768.         /* execute the statement */
  769.         status = docmd(eline);
  770.         if (force)        /* force the status */
  771.             status = TRUE;
  772.  
  773.         /* check for a command error */
  774.         if (status != TRUE) {
  775.             /* look if buffer is showing */
  776.             wp = wheadp;
  777.             while (wp != NULL) {
  778.                 if (wp->w_bufp == bp) {
  779.                     /* and point it */
  780.                     wp->w_dotp = lp;
  781.                     wp->w_doto = 0;
  782.                     wp->w_flag |= WFHARD;
  783.                 }
  784.                 wp = wp->w_wndp;
  785.             }
  786.             /* in any case set the buffer . */
  787.             bp->b_dotp = lp;
  788.             bp->b_doto = 0;
  789.             free(einit);
  790.             execlevel = 0;
  791.             freewhile(whlist);
  792.             return(status);
  793.         }
  794.  
  795. onward:        /* on to the next line */
  796.         free(einit);
  797.         lp = lp->l_fp;
  798.     }
  799.  
  800. eexec:    /* exit the current function */
  801.     execlevel = 0;
  802.     freewhile(whlist);
  803.         return(TRUE);
  804. }
  805.  
  806. makelit(s, len)    /* expand all "%" to "%%" */
  807. char *s;
  808. int len;
  809. {
  810.     register char *sp;    /* temp for expanding string */
  811.     register char *ep;    /* ptr to end of string to expand */
  812.     int templen;
  813.  
  814.     sp = s;
  815.     len -= 2;
  816.     while(*sp && len-- > 0)
  817.         if (*sp++ == '%') {
  818.             /* advance to the end */
  819.             ep = --sp;
  820.             templen = len+1;
  821.             while(*ep++ != '\0' && templen-- >= 0) ;
  822.             /* null terminate the string one out */
  823.             *(ep+1) = '\0';
  824.             /* copy backwards */
  825.             while(ep-- > sp)
  826.                 *(ep+1) = *ep;
  827.             /* and advance sp past the new % */
  828.             sp += 2;
  829.             --len;
  830.         }
  831.     *sp = '\0';
  832. }
  833.  
  834. freewhile(wp)    /* free a list of while block pointers */
  835.  
  836. WHBLOCK *wp;    /* head of structure to free */
  837.  
  838. {
  839.     if (wp == NULL)
  840.         return;
  841.     if (wp->w_next)
  842.         freewhile(wp->w_next);
  843.     free(wp);
  844. }
  845.  
  846. execfile(f, n)    /* execute a series of commands in a file */
  847.  
  848. int f, n;    /* default flag and numeric arg to pass on to file */
  849.  
  850. {
  851.     register int status;    /* return status of name query */
  852.     char fname[NSTRING];    /* name of file to execute */
  853.     char *fspec;        /* full file spec */
  854.  
  855.     if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
  856.         return(status);
  857.  
  858. #if    1
  859.     /* look up the path for the file */
  860.     fspec = flook(fname, TRUE);
  861.  
  862.     /* if it isn't around */
  863.     if (fspec == NULL)
  864.         return(FALSE);
  865.  
  866. #endif
  867.     /* otherwise, execute it */
  868.     while (n-- > 0)
  869.         if ((status=dofile(fspec)) != TRUE)
  870.             return(status);
  871.  
  872.     return(TRUE);
  873. }
  874.  
  875. /*    dofile:    yank a file into a buffer and execute it
  876.         if there are no errors, delete the buffer on exit */
  877.  
  878. dofile(fname)
  879.  
  880. char *fname;    /* file name to execute */
  881.  
  882. {
  883.     register BUFFER *bp;    /* buffer to place file to exeute */
  884.     register BUFFER *cb;    /* temp to hold current buf while we read */
  885.     register int status;    /* results of various calls */
  886.     char bname[NBUFN];    /* name of buffer */
  887.  
  888.     makename(bname, fname);        /* derive the name of the buffer */
  889.     if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  890.         return(FALSE);
  891.  
  892.     bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  893.     cb = curbp;        /* save the old buffer */
  894.     curbp = bp;        /* make this one current */
  895.     /* and try to read in the file to execute */
  896.     if ((status = readin(fname, FALSE, FALSE)) != TRUE) {
  897.         curbp = cb;    /* restore the current buffer */
  898.         return(status);
  899.     }
  900.  
  901.     /* go execute it! */
  902.     curbp = cb;        /* restore the current buffer */
  903.     if ((status = dobuf(bp)) != TRUE)
  904.         return(status);
  905.  
  906.     /* if not displayed, remove the now unneeded buffer and exit */
  907.     if (bp->b_nwnd == 0)
  908.         zotbuf(bp);
  909.     return(TRUE);
  910. }
  911.  
  912. /*    cbuf:    Execute the contents of a numbered buffer    */
  913.  
  914. cbuf(f, n, bufnum)
  915.  
  916. int f, n;    /* default flag and numeric arg */
  917. int bufnum;    /* number of buffer to execute */
  918.  
  919. {
  920.         register BUFFER *bp;        /* ptr to buffer to execute */
  921.         register int status;        /* status return */
  922.     char bufname[12];
  923.  
  924.     /* make the buffer name */
  925.     strcpy(bufname, "[Macro xx]");
  926.     bufname[7] = '0' + (bufnum / 10);
  927.     bufname[8] = '0' + (bufnum % 10);
  928.  
  929.     /* find the pointer to that buffer */
  930.         if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
  931.             mlwrite("Macro not defined");
  932.                 return(FALSE);
  933.         }
  934.  
  935.     /* and now execute it as asked */
  936.     while (n-- > 0)
  937.         if ((status = dobuf(bp)) != TRUE)
  938.             return(status);
  939.     return(TRUE);
  940. }
  941.  
  942. cbuf1(f, n)
  943.  
  944. {
  945.     cbuf(f, n, 1);
  946. }
  947.  
  948. cbuf2(f, n)
  949.  
  950. {
  951.     cbuf(f, n, 2);
  952. }
  953.  
  954. cbuf3(f, n)
  955.  
  956. {
  957.     cbuf(f, n, 3);
  958. }
  959.  
  960. cbuf4(f, n)
  961.  
  962. {
  963.     cbuf(f, n, 4);
  964. }
  965.  
  966. cbuf5(f, n)
  967.  
  968. {
  969.     cbuf(f, n, 5);
  970. }
  971.  
  972. cbuf6(f, n)
  973.  
  974. {
  975.     cbuf(f, n, 6);
  976. }
  977.  
  978. cbuf7(f, n)
  979.  
  980. {
  981.     cbuf(f, n, 7);
  982. }
  983.  
  984. cbuf8(f, n)
  985.  
  986. {
  987.     cbuf(f, n, 8);
  988. }
  989.  
  990. cbuf9(f, n)
  991.  
  992. {
  993.     cbuf(f, n, 9);
  994. }
  995.  
  996. cbuf10(f, n)
  997.  
  998. {
  999.     cbuf(f, n, 10);
  1000. }
  1001.  
  1002. cbuf11(f, n)
  1003.  
  1004. {
  1005.     cbuf(f, n, 11);
  1006. }
  1007.  
  1008. cbuf12(f, n)
  1009.  
  1010. {
  1011.     cbuf(f, n, 12);
  1012. }
  1013.  
  1014. cbuf13(f, n)
  1015.  
  1016. {
  1017.     cbuf(f, n, 13);
  1018. }
  1019.  
  1020. cbuf14(f, n)
  1021.  
  1022. {
  1023.     cbuf(f, n, 14);
  1024. }
  1025.  
  1026. cbuf15(f, n)
  1027.  
  1028. {
  1029.     cbuf(f, n, 15);
  1030. }
  1031.  
  1032. cbuf16(f, n)
  1033.  
  1034. {
  1035.     cbuf(f, n, 16);
  1036. }
  1037.  
  1038. cbuf17(f, n)
  1039.  
  1040. {
  1041.     cbuf(f, n, 17);
  1042. }
  1043.  
  1044. cbuf18(f, n)
  1045.  
  1046. {
  1047.     cbuf(f, n, 18);
  1048. }
  1049.  
  1050. cbuf19(f, n)
  1051.  
  1052. {
  1053.     cbuf(f, n, 19);
  1054. }
  1055.  
  1056. cbuf20(f, n)
  1057.  
  1058. {
  1059.     cbuf(f, n, 20);
  1060. }
  1061.  
  1062. cbuf21(f, n)
  1063.  
  1064. {
  1065.     cbuf(f, n, 21);
  1066. }
  1067.  
  1068. cbuf22(f, n)
  1069.  
  1070. {
  1071.     cbuf(f, n, 22);
  1072. }
  1073.  
  1074. cbuf23(f, n)
  1075.  
  1076. {
  1077.     cbuf(f, n, 23);
  1078. }
  1079.  
  1080. cbuf24(f, n)
  1081.  
  1082. {
  1083.     cbuf(f, n, 24);
  1084. }
  1085.  
  1086. cbuf25(f, n)
  1087.  
  1088. {
  1089.     cbuf(f, n, 25);
  1090. }
  1091.  
  1092. cbuf26(f, n)
  1093.  
  1094. {
  1095.     cbuf(f, n, 26);
  1096. }
  1097.  
  1098. cbuf27(f, n)
  1099.  
  1100. {
  1101.     cbuf(f, n, 27);
  1102. }
  1103.  
  1104. cbuf28(f, n)
  1105.  
  1106. {
  1107.     cbuf(f, n, 28);
  1108. }
  1109.  
  1110. cbuf29(f, n)
  1111.  
  1112. {
  1113.     cbuf(f, n, 29);
  1114. }
  1115.  
  1116. cbuf30(f, n)
  1117.  
  1118. {
  1119.     cbuf(f, n, 30);
  1120. }
  1121.  
  1122. cbuf31(f, n)
  1123.  
  1124. {
  1125.     cbuf(f, n, 31);
  1126. }
  1127.  
  1128. cbuf32(f, n)
  1129.  
  1130. {
  1131.     cbuf(f, n, 32);
  1132. }
  1133.  
  1134. cbuf33(f, n)
  1135.  
  1136. {
  1137.     cbuf(f, n, 33);
  1138. }
  1139.  
  1140. cbuf34(f, n)
  1141.  
  1142. {
  1143.     cbuf(f, n, 34);
  1144. }
  1145.  
  1146. cbuf35(f, n)
  1147.  
  1148. {
  1149.     cbuf(f, n, 35);
  1150. }
  1151.  
  1152. cbuf36(f, n)
  1153.  
  1154. {
  1155.     cbuf(f, n, 36);
  1156. }
  1157.  
  1158. cbuf37(f, n)
  1159.  
  1160. {
  1161.     cbuf(f, n, 37);
  1162. }
  1163.  
  1164. cbuf38(f, n)
  1165.  
  1166. {
  1167.     cbuf(f, n, 38);
  1168. }
  1169.  
  1170. cbuf39(f, n)
  1171.  
  1172. {
  1173.     cbuf(f, n, 39);
  1174. }
  1175.  
  1176. cbuf40(f, n)
  1177.  
  1178. {
  1179.     cbuf(f, n, 40);
  1180. }
  1181.  
  1182.  
  1183.