void macroexpand (struct cpp_reader *pfile, struct definition *defn) { int nargs = defn->nargs; if (nargs >= 0) { enum cpp_token token; /* { dg-bogus "token" "uninitialized variable warning" } */ int i, rest_args; i = 0; rest_args = 0; do { if (rest_args) continue; if (i < nargs || (nargs == 0 && i == 0)) { /* if we are working on last arg which absorbs rest of args... */ if (i == nargs - 1 && defn->rest_args) rest_args = 1; token = macarg (pfile, rest_args); } else token = macarg (pfile, 0); if (token == CPP_EOF || token == CPP_POP) return; i++; } while (token == CPP_COMMA); } }
/* * docmd: * take a passed string as a command line and translate * it to be executed as a command. This function will be * used by execute-command-line and by all source and * startup files. Lastflag/thisflag is also updated. * * format of the command line is: * * {# arg} <command-name> {<argument string(s)>} * * char *cline; command line to execute */ int docmd(char *cline) { int f; /* default argument flag */ int n; /* numeric repeat value */ fn_t fnc; /* function to execute */ int status; /* return status of function */ int oldcle; /* old contents of clexec flag */ char *oldestr; /* original exec string */ char *tkn; /* next token off of command line */ tkn = alloca(NSTRING * sizeof(char)); /* if we are scanning and not executing..go back here */ if (execlevel) return TRUE; oldestr = execstr; /* save last ptr to string to execute */ execstr = cline; /* and set this one as current */ /* first set up the default command values */ f = FALSE; n = 1; lastflag = thisflag; thisflag = 0; if ((status = macarg(tkn)) != TRUE) { /* and grab the first token */ execstr = oldestr; return status; } /* process leadin argument */ if (gettyp(tkn) != TKCMD) { f = TRUE; strcpy(tkn, getval(tkn)); n = atoi(tkn); /* and now get the command to execute */ if ((status = macarg(tkn)) != TRUE) { execstr = oldestr; return status; } } /* and match the token to see if it exists */ if ((fnc = fncmatch(tkn)) == NULL) { mlwrite("(No such Function)"); execstr = oldestr; return FALSE; } /* save the arguments and go execute the command */ oldcle = clexec; /* save old clexec flag */ clexec = TRUE; /* in cline execution */ status = (*fnc) (f, n); /* call the function */ cmdstatus = status; /* save the status */ clexec = oldcle; /* restore clexec flag */ execstr = oldestr; return status; }
/* * dobuf: * execute the contents of the buffer pointed to * by the passed BP * * Directives start with a "!" and include: * * !endm End a macro * !if (cond) conditional execution * !else * !endif * !return Return (terminating current macro) * !goto <label> Jump to a label in the current macro * !force Force macro to continue...even if command fails * !while (cond) Execute a loop if the condition is true * !endwhile * * Line Labels begin with a "*" as the first nonblank char, like: * * *LBL01 * * struct buffer *bp; buffer to execute */ int dobuf(struct buffer *bp) { int status; /* status return */ struct line *lp; /* pointer to line to execute */ struct line *hlp; /* pointer to line header */ struct line *glp; /* line to goto */ struct line *mp; /* Macro line storage temp */ int dirnum; /* directive index */ int linlen; /* length of line to execute */ int i; /* index */ int c; /* temp character */ int force; /* force TRUE result? */ struct window *wp; /* ptr to windows to scan */ struct while_block *whlist; /* ptr to !WHILE list */ struct while_block *scanner; /* ptr during scan */ struct while_block *whtemp; /* temporary ptr to a struct while_block */ char *einit; /* initial value of eline */ char *eline; /* text of line to execute */ char *tkn; /* buffer to evaluate an expresion in */ #if DEBUGM char *sp; /* temp for building debug string */ char *ep; /* ptr to end of outline */ #endif tkn = alloca(NSTRING * sizeof(char)); /* clear IF level flags/while ptr */ execlevel = 0; whlist = NULL; scanner = NULL; /* scan the buffer to execute, building WHILE header blocks */ hlp = bp->b_linep; lp = hlp->l_fp; while (lp != hlp) { /* scan the current line */ eline = lp->l_text; i = lp->l_used; /* trim leading whitespace */ while (i-- > 0 && (*eline == ' ' || *eline == '\t')) ++eline; /* if theres nothing here, don't bother */ if (i <= 0) goto nxtscan; /* if is a while directive, make a block... */ if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') { whtemp = (struct while_block *)malloc(sizeof(struct while_block)); if (whtemp == NULL) { noram:mlwrite ("%%Out of memory during while scan"); failexit:freewhile (scanner); freewhile(whlist); return FALSE; } whtemp->w_begin = lp; whtemp->w_type = BTWHILE; whtemp->w_next = scanner; scanner = whtemp; } /* if is a BREAK directive, make a block... */ if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') { if (scanner == NULL) { mlwrite ("%%!BREAK outside of any !WHILE loop"); goto failexit; } whtemp = (struct while_block *)malloc(sizeof(struct while_block)); if (whtemp == NULL) goto noram; whtemp->w_begin = lp; whtemp->w_type = BTBREAK; whtemp->w_next = scanner; scanner = whtemp; } /* if it is an endwhile directive, record the spot... */ if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) { if (scanner == NULL) { mlwrite ("%%!ENDWHILE with no preceding !WHILE in '%s'", bp->b_bname); goto failexit; } /* move top records from the scanner list to the whlist until we have moved all BREAK records and one WHILE record */ do { scanner->w_end = lp; whtemp = whlist; whlist = scanner; scanner = scanner->w_next; whlist->w_next = whtemp; } while (whlist->w_type == BTBREAK); } nxtscan: /* on to the next line */ lp = lp->l_fp; } /* while and endwhile should match! */ if (scanner != NULL) { mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'", bp->b_bname); goto failexit; } /* let the first command inherit the flags from the last one.. */ thisflag = lastflag; /* starting at the beginning of the buffer */ hlp = bp->b_linep; lp = hlp->l_fp; while (lp != hlp) { /* allocate eline and copy macro line to it */ linlen = lp->l_used; if ((einit = eline = malloc(linlen + 1)) == NULL) { mlwrite("%%Out of Memory during macro execution"); freewhile(whlist); return FALSE; } strncpy(eline, lp->l_text, linlen); eline[linlen] = 0; /* make sure it ends */ /* trim leading whitespace */ while (*eline == ' ' || *eline == '\t') ++eline; /* dump comments and blank lines */ if (*eline == ';' || *eline == 0) goto onward; #if DEBUGM /* if $debug == TRUE, every line to execute gets echoed and a key needs to be pressed to continue ^G will abort the command */ if (macbug) { strcpy(outline, "<<<"); /* debug macro name */ strcat(outline, bp->b_bname); strcat(outline, ":"); /* debug if levels */ strcat(outline, itoa(execlevel)); strcat(outline, ":"); /* and lastly the line */ strcat(outline, eline); strcat(outline, ">>>"); /* change all '%' to ':' so mlwrite won't expect arguments */ sp = outline; while (*sp) if (*sp++ == '%') { /* advance to the end */ ep = --sp; while (*ep++); /* null terminate the string one out */ *(ep + 1) = 0; /* copy backwards */ while (ep-- > sp) *(ep + 1) = *ep; /* and advance sp past the new % */ sp += 2; } /* write out the debug line */ mlforce(outline); update(TRUE); /* and get the keystroke */ if ((c = get1key()) == abortc) { mlforce("(Macro aborted)"); freewhile(whlist); return FALSE; } if (c == metac) macbug = FALSE; } #endif /* Parse directives here.... */ dirnum = -1; if (*eline == '!') { /* Find out which directive this is */ ++eline; for (dirnum = 0; dirnum < NUMDIRS; dirnum++) if (strncmp(eline, dname[dirnum], strlen(dname[dirnum])) == 0) break; /* and bitch if it's illegal */ if (dirnum == NUMDIRS) { mlwrite("%%Unknown Directive"); freewhile(whlist); return FALSE; } /* service only the !ENDM macro here */ if (dirnum == DENDM) { mstore = FALSE; bstore = NULL; goto onward; } /* restore the original eline.... */ --eline; } /* if macro store is on, just salt this away */ if (mstore) { /* allocate the space for the line */ linlen = strlen(eline); if ((mp = lalloc(linlen)) == NULL) { mlwrite ("Out of memory while storing macro"); return FALSE; } /* copy the text into the new line */ for (i = 0; i < linlen; ++i) lputc(mp, i, eline[i]); /* attach the line to the end of the buffer */ bstore->b_linep->l_bp->l_fp = mp; mp->l_bp = bstore->b_linep->l_bp; bstore->b_linep->l_bp = mp; mp->l_fp = bstore->b_linep; goto onward; } force = FALSE; /* dump comments */ if (*eline == '*') goto onward; /* now, execute directives */ if (dirnum != -1) { /* skip past the directive */ while (*eline && *eline != ' ' && *eline != '\t') ++eline; execstr = eline; switch (dirnum) { case DIF: /* IF directive */ /* grab the value of the logical exp */ if (execlevel == 0) { if (macarg(tkn) != TRUE) goto eexec; if (stol(tkn) == FALSE) ++execlevel; } else ++execlevel; goto onward; case DWHILE: /* WHILE directive */ /* grab the value of the logical exp */ if (execlevel == 0) { if (macarg(tkn) != TRUE) goto eexec; if (stol(tkn) == TRUE) goto onward; } /* drop down and act just like !BREAK */ case DBREAK: /* BREAK directive */ if (dirnum == DBREAK && execlevel) goto onward; /* jump down to the endwhile */ /* find the right while loop */ whtemp = whlist; while (whtemp) { if (whtemp->w_begin == lp) break; whtemp = whtemp->w_next; } if (whtemp == NULL) { mlwrite ("%%Internal While loop error"); freewhile(whlist); return FALSE; } /* reset the line pointer back.. */ lp = whtemp->w_end; goto onward; case DELSE: /* ELSE directive */ if (execlevel == 1) --execlevel; else if (execlevel == 0) ++execlevel; goto onward; case DENDIF: /* ENDIF directive */ if (execlevel) --execlevel; goto onward; case DGOTO: /* GOTO directive */ /* .....only if we are currently executing */ if (execlevel == 0) { /* grab label to jump to */ eline = token(eline, golabel, NPAT); linlen = strlen(golabel); glp = hlp->l_fp; while (glp != hlp) { if (*glp->l_text == '*' && (strncmp (&glp->l_text[1], golabel, linlen) == 0)) { lp = glp; goto onward; } glp = glp->l_fp; } mlwrite("%%No such label"); freewhile(whlist); return FALSE; } goto onward; case DRETURN: /* RETURN directive */ if (execlevel == 0) goto eexec; goto onward; case DENDWHILE: /* ENDWHILE directive */ if (execlevel) { --execlevel; goto onward; } else { /* find the right while loop */ whtemp = whlist; while (whtemp) { if (whtemp->w_type == BTWHILE && whtemp->w_end == lp) break; whtemp = whtemp->w_next; } if (whtemp == NULL) { mlwrite ("%%Internal While loop error"); freewhile(whlist); return FALSE; } /* reset the line pointer back.. */ lp = whtemp->w_begin->l_bp; goto onward; } case DFORCE: /* FORCE directive */ force = TRUE; } } /* execute the statement */ status = docmd(eline); if (force) /* force the status */ status = TRUE; /* check for a command error */ if (status != TRUE) { /* look if buffer is showing */ wp = wheadp; while (wp != NULL) { if (wp->w_bufp == bp) { /* and point it */ wp->w_dotp = lp; wp->w_doto = 0; wp->w_flag |= WFHARD; } wp = wp->w_wndp; } /* in any case set the buffer . */ bp->b_dotp = lp; bp->b_doto = 0; free(einit); execlevel = 0; freewhile(whlist); return status; } onward: /* on to the next line */ free(einit); lp = lp->l_fp; } eexec: /* exit the current function */ execlevel = 0; freewhile(whlist); return TRUE; }
/* For the "operator" commands -- the following command is a motion, or * the operator itself is repeated. All operate on regions. */ int operator(int f, int n, OpsFunc fn, const char *str) { int c; int thiskey; int status; const CMDFUNC *cfp; /* function to execute */ char tok[NSTRING]; /* command incoming */ BUFFER *ourbp; #if OPT_MOUSE WINDOW *wp0 = curwp; #endif doingopcmd = TRUE; pre_op_dot = DOT; ourbp = curbp; if (havemotion != NULL) { cfp = havemotion; havemotion = NULL; } else { mlwrite("%s operation pending...",str); (void)update(FALSE); /* get the next command from the keyboard */ /* or a command line, as approp. */ if (clexec) { macarg(tok); /* get the next token */ if (!strcmp(tok,"lines")) cfp = &f_godotplus; else cfp = engl2fnc(tok); } else { thiskey = lastkey; c = kbd_seq(); #if OPT_MOUSE if (curwp != wp0) { unkeystroke(c); doingopcmd = FALSE; return FALSE; } #endif /* allow second chance for entering counts */ do_repeats(&c,&f,&n); if (thiskey == lastkey) cfp = &f_godotplus; else cfp = kcod2fnc(c); } if (cfp) mlerase(); else mlforce("[No such function]"); } if (!cfp) { doingopcmd = FALSE; return FALSE; } if ((cfp->c_flags & MOTION) == 0) { kbd_alarm(); doingopcmd = FALSE; return(ABORT); } /* motion is interpreted as affecting full lines */ if (regionshape == EXACT) { if (cfp->c_flags & FL) regionshape = FULLLINE; if (cfp->c_flags & RECT) regionshape = RECTANGLE; } /* and execute the motion */ status = execute(cfp, f,n); if (status != TRUE) { doingopcmd = FALSE; regionshape = EXACT; mlforce("[Motion failed]"); return FALSE; } opcmd = 0; MK = pre_op_dot; /* we've successfully set up a region */ if (!fn) { /* be defensive */ mlforce("BUG -- null func pointer in operator"); status = FALSE; } else { status = (fn)(); } if (ourbp == curbp) /* in case the func switched buffers on us */ swapmark(); if (regionshape == FULLLINE) (void)firstnonwhite(FALSE,1); regionshape = EXACT; doingopcmd = FALSE; haveregion = FALSE; return status; }
/* * Evaluate a function. * * @fname: name of function to evaluate. */ char *gtfun(char *fname) { int fnum; /* index to function to eval */ int status; /* return status */ char *tsp; /* temporary string pointer */ char arg1[NSTRING]; /* value of first argument */ char arg2[NSTRING]; /* value of second argument */ char arg3[NSTRING]; /* value of third argument */ static char result[2 * NSTRING]; /* string result */ /* look the function up in the function table */ fname[3] = 0; /* only first 3 chars significant */ mklower(fname); /* and let it be upper or lower case */ for (fnum = 0; fnum < ARRAY_SIZE(funcs); fnum++) if (strcmp(fname, funcs[fnum].f_name) == 0) break; /* return errorm on a bad reference */ if (fnum == ARRAY_SIZE(funcs)) return errorm; /* if needed, retrieve the first argument */ if (funcs[fnum].f_type >= MONAMIC) { if ((status = macarg(arg1)) != TRUE) return errorm; /* if needed, retrieve the second argument */ if (funcs[fnum].f_type >= DYNAMIC) { if ((status = macarg(arg2)) != TRUE) return errorm; /* if needed, retrieve the third argument */ if (funcs[fnum].f_type >= TRINAMIC) if ((status = macarg(arg3)) != TRUE) return errorm; } } /* and now evaluate it! */ switch (fnum) { case UFADD: return itoa(atoi(arg1) + atoi(arg2)); case UFSUB: return itoa(atoi(arg1) - atoi(arg2)); case UFTIMES: return itoa(atoi(arg1) * atoi(arg2)); case UFDIV: return itoa(atoi(arg1) / atoi(arg2)); case UFMOD: return itoa(atoi(arg1) % atoi(arg2)); case UFNEG: return itoa(-atoi(arg1)); case UFCAT: strcpy(result, arg1); return strcat(result, arg2); case UFLEFT: return strncpy(result, arg1, atoi(arg2)); case UFRIGHT: return (strcpy(result, &arg1[(strlen(arg1) - atoi(arg2))])); case UFMID: return (strncpy(result, &arg1[atoi(arg2) - 1], atoi(arg3))); case UFNOT: return ltos(stol(arg1) == FALSE); case UFEQUAL: return ltos(atoi(arg1) == atoi(arg2)); case UFLESS: return ltos(atoi(arg1) < atoi(arg2)); case UFGREATER: return ltos(atoi(arg1) > atoi(arg2)); case UFSEQUAL: return ltos(strcmp(arg1, arg2) == 0); case UFSLESS: return ltos(strcmp(arg1, arg2) < 0); case UFSGREAT: return ltos(strcmp(arg1, arg2) > 0); case UFIND: return strcpy(result, getval(arg1)); case UFAND: return ltos(stol(arg1) && stol(arg2)); case UFOR: return ltos(stol(arg1) || stol(arg2)); case UFLENGTH: return itoa(strlen(arg1)); case UFUPPER: return mkupper(arg1); case UFLOWER: return mklower(arg1); case UFTRUTH: return ltos(atoi(arg1) == 42); case UFASCII: return itoa((int) arg1[0]); case UFCHR: result[0] = atoi(arg1); result[1] = 0; return result; case UFGTKEY: result[0] = tgetc(); result[1] = 0; return result; case UFRND: return itoa((ernd() % abs(atoi(arg1))) + 1); case UFABS: return itoa(abs(atoi(arg1))); case UFSINDEX: return itoa(sindex(arg1, arg2)); case UFENV: #if ENVFUNC tsp = getenv(arg1); return tsp == NULL ? "" : tsp; #else return ""; #endif case UFBIND: return transbind(arg1); case UFEXIST: return ltos(fexist(arg1)); case UFFIND: tsp = flook(arg1, TRUE); return tsp == NULL ? "" : tsp; case UFBAND: return itoa(atoi(arg1) & atoi(arg2)); case UFBOR: return itoa(atoi(arg1) | atoi(arg2)); case UFBXOR: return itoa(atoi(arg1) ^ atoi(arg2)); case UFBNOT: return itoa(~atoi(arg1)); case UFXLATE: return xlat(arg1, arg2, arg3); } exit(-11); /* never should get here */ }