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