Path: utzoo!utgpu!cs.utexas.edu!usc!rpi!think.com!cayman!pgf From: pgf@cayman.COM (Paul Fox) Newsgroups: alt.sources Subject: Vile 06/17 - vi feel-alike (multi-window) Message-ID: <4525@cayman.COM> Date: 7 Jun 91 22:09:32 GMT Organization: Cayman Systems Inc., Cambridge Ma Lines: 2353 Submitted-by: pgf@cayman.com Archive-name: Vile/part06 #!/bin/sh # this is vileshar.06 (part 6 of Vile) # do not concatenate these parts, unpack them in order with /bin/sh # file evar.h continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 6; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 echo 'x - continuing file evar.h' sed 's/^X//' << 'SHAR_EOF' >> 'evar.h' && X /* list of recognized environment variables */ X char *envars[] = { X "fillcol", /* current fill column */ X "pagelen", /* number of lines used by editor */ X "curcol", /* current column pos of cursor */ X "curline", /* current line in file */ X "ram", /* ram in use by malloc */ X "flicker", /* flicker supression */ X "curwidth", /* current screen width */ X "cbufname", /* current buffer name */ X "cfname", /* current file name */ X "sres", /* current screen resolution */ X "debug", /* macro debugging */ X "status", /* returns the status of the last command */ X "palette", /* current palette string */ X "asave", /* # of chars between auto-saves */ X "acount", /* # of chars until next auto-save */ X "lastkey", /* last keyboard char struck */ X "curchar", /* current character under the cursor */ X "discmd", /* display commands on command line */ X "version", /* current version number */ X "progname", /* returns current prog name - "vile" */ X "seed", /* current random number seed */ X "disinp", /* display command line input characters */ X "wline", /* # of lines in current window */ X "cwline", /* current screen line in window */ X "target", /* target for line moves */ X "search", /* search pattern */ X "replace", /* replacement pattern */ X "match", /* last matched magic pattern */ X "kill", /* kill buffer (read only) */ X "cmode", /* mode of current buffer */ X "gmode", /* global modes */ X "tpause", /* length to pause for paren matching */ X "pending", /* type ahead pending flag */ X "lwidth", /* width of current line */ X "line", /* text of current line */ }; X #define NEVARS sizeof(envars) / sizeof(char *) X /* and its preprocesor definitions */ X #define EVFILLCOL 0 #define EVPAGELEN 1 #define EVCURCOL 2 #define EVCURLINE 3 #define EVRAM 4 #define EVFLICKER 5 #define EVCURWIDTH 6 #define EVCBUFNAME 7 #define EVCFNAME 8 #define EVSRES 9 #define EVDEBUG 10 #define EVSTATUS 11 #define EVPALETTE 12 #define EVASAVE 13 #define EVACOUNT 14 #define EVLASTKEY 15 #define EVCURCHAR 16 #define EVDISCMD 17 #define EVVERSION 18 #define EVPROGNAME 19 #define EVSEED 20 #define EVDISINP 21 #define EVWLINE 22 #define EVCWLINE 23 #define EVTARGET 24 #define EVSEARCH 25 #define EVREPLACE 26 #define EVMATCH 27 #define EVKILL 28 #define EVCMODE 29 #define EVGMODE 30 #define EVTPAUSE 31 #define EVPENDING 32 #define EVLWIDTH 33 #define EVLINE 34 X /* list of recognized user functions */ X typedef struct UFUNC { X char *f_name; /* name of function */ X int f_type; /* 1 = monamic, 2 = dynamic */ } UFUNC; X #define NILNAMIC 0 #define MONAMIC 1 #define DYNAMIC 2 #define TRINAMIC 3 X UFUNC funcs[] = { X "add", DYNAMIC, /* add two numbers together */ X "sub", DYNAMIC, /* subtraction */ X "tim", DYNAMIC, /* multiplication */ X "div", DYNAMIC, /* division */ X "mod", DYNAMIC, /* mod */ X "neg", MONAMIC, /* negate */ X "cat", DYNAMIC, /* concatinate string */ X "lef", DYNAMIC, /* left string(string, len) */ X "rig", DYNAMIC, /* right string(string, pos) */ X "mid", TRINAMIC, /* mid string(string, pos, len) */ X "not", MONAMIC, /* logical not */ X "equ", DYNAMIC, /* logical equality check */ X "les", DYNAMIC, /* logical less than */ X "gre", DYNAMIC, /* logical greater than */ X "seq", DYNAMIC, /* string logical equality check */ X "sle", DYNAMIC, /* string logical less than */ X "sgr", DYNAMIC, /* string logical greater than */ X "ind", MONAMIC, /* evaluate indirect value */ X "and", DYNAMIC, /* logical and */ X "or", DYNAMIC, /* logical or */ X "len", MONAMIC, /* string length */ X "upp", MONAMIC, /* uppercase string */ X "low", MONAMIC, /* lower case string */ X "tru", MONAMIC, /* Truth of the universe logical test */ X "asc", MONAMIC, /* char to integer conversion */ X "chr", MONAMIC, /* integer to char conversion */ X "gtk", NILNAMIC, /* get 1 charater */ X "rnd", MONAMIC, /* get a random number */ X "abs", MONAMIC, /* absolute value of a number */ X "sin", DYNAMIC, /* find the index of one string in another */ X "env", MONAMIC, /* retrieve a system environment var */ X "bin", MONAMIC, /* loopup what function name is bound to a key */ }; X #define NFUNCS sizeof(funcs) / sizeof(UFUNC) X /* and its preprocesor definitions */ X #define UFADD 0 #define UFSUB 1 #define UFTIMES 2 #define UFDIV 3 #define UFMOD 4 #define UFNEG 5 #define UFCAT 6 #define UFLEFT 7 #define UFRIGHT 8 #define UFMID 9 #define UFNOT 10 #define UFEQUAL 11 #define UFLESS 12 #define UFGREATER 13 #define UFSEQUAL 14 #define UFSLESS 15 #define UFSGREAT 16 #define UFIND 17 #define UFAND 18 #define UFOR 19 #define UFLENGTH 20 #define UFUPPER 21 #define UFLOWER 22 #define UFTRUTH 23 #define UFASCII 24 #define UFCHR 25 #define UFGTKEY 26 #define UFRND 27 #define UFABS 28 #define UFSINDEX 29 #define UFENV 30 #define UFBIND 31 X #endif SHAR_EOF echo 'File evar.h is complete' && chmod 0444 evar.h || echo 'restore of evar.h failed' Wc_c="`wc -c < 'evar.h'`" test 5247 -eq "$Wc_c" || echo 'evar.h: original size 5247, current size' "$Wc_c" # ============= exec.c ============== echo 'x - extracting exec.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'exec.c' && /* This file is for functions dealing with execution of X commands, command lines, buffers, files and startup files X X written 1986 by Daniel Lawrence */ X #include #include "estruct.h" #include "edef.h" X /* namedcmd: execute a named command even if it is not bound */ X namedcmd(f, n) int f, n; { X char *fnp; /* ptr to the name of the cmd to exec */ X LINE *fromline; /* first linespec */ X LINE *toline; /* second linespec */ X char lspec[NLINE]; X int cpos = 0; X int s,c,isdfl,zero,flags; X char *kbd_engl(); X CMDFUNC *cfp; /* function to execute */ X extern CMDFUNC f_gomark; X X /* prompt the user to type a named command */ X mlwrite(": "); X X /* and now get the function name to execute */ #if NeWS X newsimmediateon() ; #endif X X while(1) { X c = tgetc(); X if (c == '\r') { X lspec[cpos] = 0; X fnp = NULL; X break; X } else if (c == kcod2key(abortc)) { /* Bell, abort */ X isabortc: X lspec[0] = '\0'; X return FALSE; X } else if (isbackspace(c)) { X if (cpos != 0) { X TTputc('\b'); X TTputc(' '); X TTputc('\b'); X --ttcol; X --cpos; X } else { X lspec[0] = '\0'; X lineinput = FALSE; X return FALSE; X } X X } else if (c == kcod2key(killc)) { /* ^U, kill */ X iskillc: X while (cpos != 0) { X TTputc('\b'); X TTputc(' '); X TTputc('\b'); X --cpos; X --ttcol; X } X } else if (islinespecchar(c) || X /* special test for 'a style mark references */ X (cpos > 0 && X lspec[cpos-1] == '\'' && X (islower(c) || (c == '\'') ) X ) X ) { X lspec[cpos++] = c; X TTputc(c); X ++ttcol; X } else { X int status; X tungetc(c); X lspec[cpos] = 0; X status = kbd_engl_stat(&fnp); X if (status == TRUE) { X break; X } else if (status == SORTOFTRUE) { X fnp = NULL; X continue; X } else { X return status; X } X } X TTflush(); X } X X /* parse the accumulated lspec */ X if (rangespec(lspec,&fromline,&toline,&isdfl,&zero) != TRUE) { X mlwrite("[Improper line range]"); X return FALSE; X } X X /* if range given, and it wasn't "0" and the buffer's empty */ X if (!isdfl && !zero && (lforw(curbp->b_linep) == curbp->b_linep)) { X mlwrite("[No range possible in empty buffer]", fnp); X return FALSE; X } X #if NeWS X newsimmediateoff() ; #endif X X /* did we get a name? */ X if (fnp == NULL) { X if (isdfl) { /* no range, no function */ X mlwrite("[No such function]"); X return FALSE; X } else { /* range, no function */ X cfp = &f_gomark; X fnp = ""; X } X } else if ((cfp = engl2fnc(fnp)) == NULL) { /* bad function */ X mlwrite("[No such function %s]",fnp); X return FALSE; X } X flags = cfp->c_flags; X X /* bad arguments? */ #ifdef EXRC_FILES seems like we need one more check here -- is it from a .exrc file? X cmd not ok in .exrc empty file X if (!(flags & EXRCOK) && (lforw(curbp->b_linep) == curbp->b_linep)) { X mlwrite("[Can't use the \"%s\" command in a %s file.]", X cmdnames[cmdidx].name, EXRC); X return FALSE; X } #endif X X /* was: if (!(flags & (ZERO | EXRCOK)) && fromline == NULL ) { */ X if (zero) { X extern CMDFUNC f_lineputafter, f_opendown, f_insfile; X extern CMDFUNC f_lineputbefore, f_openup; X if (!(flags & ZERO)) { X mlwrite("[Can't use address 0 with \"%s\" command]", fnp); X return FALSE; X } X /* we're positioned at fromline == curbp->b_linep, so commands X must be willing to go _down_ from there. Seems easiest X to special case the commands that prefer going up */ X if (cfp == &f_insfile) { X /* works okay -- acts down normally */ X } else if (cfp == &f_lineputafter) { X cfp = &f_lineputbefore; X fromline = lforw(fromline); X } else if (cfp == &f_opendown) { X cfp = &f_openup; X fromline = lforw(fromline); X } else { X mlwrite("[Configuration error: ZERO]"); X return FALSE; X } X flags = cfp->c_flags; X toline = fromline; X } X X /* if we're not supposed to have a line no., and the line no. isn't X the current line, and there's more than one line */ X if (!(flags & FROM) && fromline != curwp->w_dotp && X (lforw(curbp->b_linep) != curbp->b_linep) && X (lforw(lforw(curbp->b_linep)) != curbp->b_linep) ) { X mlwrite("[Can't use address with \"%s\" command.]", fnp); X return FALSE; X } X /* if we're not supposed to have a second line no., and the line no. X isn't the same as the first line no., and there's more than X one line */ X if (!(flags & TO) && toline != fromline && X (lforw(curbp->b_linep) != curbp->b_linep) && X (lforw(lforw(curbp->b_linep)) != curbp->b_linep) ) { X mlwrite("[Can't use a range with \"%s\" command.]", fnp); X return FALSE; X } #ifdef NEEDED X if (!(flags & EXTRA) && *scan) { X mlwrite("[Extra characters after \"%s\" command.]", X cmdnames[cmdidx].name); X return FALSE; X } #endif #ifdef NEEDED X if ((flags & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!'))) { X build = scan; #ifndef CRUNCH /* what is this for? -pgf */ X if ((flags & PLUS) && *build == '+') { X while (*build && !(isspace(*build))) { X build++; X } X while (*build && isspace(*build)) { X build++; X } X } #endif /* not CRUNCH */ X for (; *build; build++) { X if (isspace(*build)) { X mlwrite("[Too many %s to \"%s\" command.]", X (flags & XFILE) ? "filenames" : "arguments", X cmdnames[cmdidx].name); X return FALSE; X } X } X } #endif /* NEEDED */ X X /* some commands have special default ranges */ X if (isdfl) { X if (flags & DFLALL) { X extern CMDFUNC f_operwrite, f_filewrite, f_operglobals, X f_globals, f_opervglobals, f_vglobals; X if (cfp == &f_operwrite) { X cfp = &f_filewrite; #if GLOBALS X } else if (cfp == &f_operglobals) { X cfp = &f_globals; X } else if (cfp == &f_opervglobals) { X cfp = &f_vglobals; #endif X } else { X mlwrite("[Configuration error: DFLALL]"); X return FALSE; X } X } else if (flags & DFLNONE) { X extern CMDFUNC f_operfilter, f_spawn; X if (cfp == &f_operfilter) { X cfp = &f_spawn; X setmark(); /* not that it matters */ X } else { X mlwrite("[Configuration error: DFLNONE]"); X return FALSE; X } X fromline = toline = NULL; X } X } X #ifdef NEEDED X /* write a newline if called from visual mode */ X if ((flags & NL) && !exmode /* && !exwrote */) { X TTputc('\n'); X /* exrefresh(); */ X } #endif X X if (toline || fromline) { /* assume it's an absolute motion */ X /* we could probably do better */ X curwp->w_ldmkp = curwp->w_dotp; X curwp->w_ldmko = curwp->w_doto; X } X if (toline) { X curwp->w_dotp = toline; X firstnonwhite(); X setmark(); X } X if (fromline) { X curwp->w_dotp = fromline; X firstnonwhite(); X if (!toline) X setmark(); X } X X /* and then execute the command */ X isnamedcmd = TRUE; X havemotion = &f_gomark; X fulllineregions = TRUE; X X s = execute(cfp,f,n); X X havemotion = NULL; X isnamedcmd = FALSE; X fulllineregions = FALSE; X X return s; } X /* parse an ex-style line spec -- code culled from elvis, file ex.c, by X Steve Kirkendall */ char * linespec(s, markptr) register char *s; /* start of the line specifier */ LINE **markptr; /* where to store the mark's value */ { X long num; X LINE *lp; /* where the linespec takes us */ X register char *t; X int status; X X setmark(); X lp = NULL; X X /* parse each ;-delimited clause of this linespec */ X do X { X /* skip an initial ';', if any */ X if (*s == ';') X s++; X X /* skip leading spaces */ X while (isspace(*s)) X s++; X X /* dot means current position */ X if (*s == '.') { X s++; X lp = curwp->w_dotp; X } else if (*s == '$') { /* '$' means the last line */ X s++; X status = gotoeob(TRUE,1); X if (status) lp = curwp->w_dotp; X } else if (isdigit(*s)) { X /* digit means an absolute line number */ X for (num = 0; isdigit(*s); s++) { X num = num * 10 + *s - '0'; X } X status = gotoline(TRUE,num); X if (status) lp = curwp->w_dotp; X } else if (*s == '\'') { X /* appostrophe means go to a set mark */ X s++; X status = gonmmark(*s); X if (status) lp = curwp->w_dotp; X s++; X } #if PATTERNS X else if (*s == '/' || *s == '?') { /* slash means do a search */ X /* put a '\0' at the end of the search pattern */ X t = parseptrn(s); X X /* search for the pattern */ X lp &= ~(BLKSIZE - 1); X if (*s == '/') { X pfetch(markline(lp)); X if (plen > 0) X lp += plen - 1; X lp = m_fsrch(lp, s); X } else { X lp = m_bsrch(lp, s); X } X X /* adjust command string pointer */ X s = t; X } #endif X X /* if linespec was faulty, quit now */ X if (!lp) { X *markptr = lp; X swapmark(); X return s; X } X X /* maybe add an offset */ X t = s; X if (*t == '-' || *t == '+') { X s++; X for (num = 0; *s >= '0' && *s <= '9'; s++) { X num = num * 10 + *s - '0'; X } X if (num == 0) X num = 1; X forwline(TRUE, (*t == '+') ? num : -num); X lp = curwp->w_dotp; X } X } while (*s == ';' || *s == '+' || *s == '-'); X X *markptr = lp; X swapmark(); X return s; } X /* parse an ex-style line range -- code culled from elvis, file ex.c, by X Steve Kirkendall */ rangespec(specp,fromlinep,tolinep,isdefaultp,zerop) char *specp; /* string containing a line range */ LINE **fromlinep; /* first linespec */ LINE **tolinep; /* second linespec */ int *isdefaultp; int *zerop; { X register char *scan; /* used to scan thru specp */ X LINE *fromline; /* first linespec */ X LINE *toline; /* second linespec */ X int noaddrallowed; X X *zerop = FALSE; X X /* ignore command lines that start with a double-quote */ X if (*specp == '"') { X *fromlinep = *tolinep = curwp->w_dotp; X return TRUE; X } X X /* permit extra colons at the start of the line */ X while (isspace(*specp) || *specp == ':') { X specp++; X } X X /* parse the line specifier */ X scan = specp; X if (lforw(curbp->b_linep) == curbp->b_linep) { X fromline = toline = NULL; X } else if (*scan == '%') { X /* '%' means all lines */ X fromline = lforw(curbp->b_linep); X toline = lback(curbp->b_linep); X scan++; X } else if (*scan == '0') { X fromline = toline = curbp->b_linep; /* _very_ top of buffer */ X *zerop = TRUE; X scan++; X } else { X scan = linespec(scan, &fromline); X if (!fromline) X fromline = curwp->w_dotp; X toline = fromline; X if (*scan == ',') { X scan++; X scan = linespec(scan, &toline); X } X if (!toline) { X /* faulty line spec -- fault already described */ X dbgwrite("null toline"); X return FALSE; X } X } X X *isdefaultp = (scan == specp); X X /* skip whitespace */ X while (isspace(*scan)) X scan++; X X if (*scan) { X dbgwrite("crud at end %s",specp); X return FALSE; X } X X *fromlinep = fromline; X *tolinep = toline; X X return TRUE; } X /* old namedcmd: execute a named command even if it is not bound */ onamedcmd(f, n) int f, n; /* command arguments [passed through to command executed] */ { X register char *fnp; /* ptr to the name of the cmd to exec */ X char *kbd_engl(); X int s; X X /* prompt the user to type a named command */ X mlwrite(": "); X X /* and now get the function name to execute */ #if NeWS X newsimmediateon() ; #endif X X fnp = kbd_engl(); X #if NeWS X newsimmediateoff() ; #endif X X if (fnp == NULL) { X mlwrite("[No such function]"); X return FALSE; X } X X /* and then execute the command */ X isnamedcmd = TRUE; X s = docmd(fnp,FALSE,f,n); X isnamedcmd = FALSE; X X return s; } X #if NEVER /* execcmd: Execute a command line command by name alone */ execcmd(f, n) int f, n; /* default Flag and Numeric argument */ { X register int status; /* status return */ X char cmdbuf[NSTRING]; /* string holding command to execute */ X X /* get the line wanted */ X cmdbuf[0] = 0; X if ((status = mlreply("cmd: ", cmdbuf, NSTRING)) != TRUE) X return status; X X execlevel = 0; X return docmd(cmdbuf,TRUE,f,n); } #endif X /* docmd: take a passed string as a command line and translate X it to be executed as a command. This function will be X used by execute-command-line and by all source and X startup files. X X format of the command line is: X X {# arg} {} X */ X docmd(cline,newcle,f,n) char *cline; /* command line to execute */ { X int status; /* return status of function */ X int flags; /* function flags */ X int oldcle; /* old contents of clexec flag */ X char *oldestr; /* original exec string */ X char tkn[NSTRING]; /* next token off of command line */ X CMDFUNC *cfp; X extern CMDFUNC f_godotplus; X X /* if we are scanning and not executing..go back here */ X if (execlevel) X return TRUE; X X oldestr = execstr; /* save last ptr to string to execute */ X execstr = cline; /* and set this one as current */ X X /* first set up the default command values */ X if (newcle == TRUE) { X f = FALSE; X n = 1; X } X X if ((status = macarg(tkn)) != TRUE) { /* and grab the first token */ X execstr = oldestr; X return status; X } X X /* process leadin argument */ X if (toktyp(tkn) != TKCMD) { X f = TRUE; X strcpy(tkn, tokval(tkn)); X n = atoi(tkn); X X /* and now get the command to execute */ X if ((status = macarg(tkn)) != TRUE) { X execstr = oldestr; X return status; X } X } X X /* and match the token to see if it exists */ X if ((cfp = engl2fnc(tkn)) == NULL) { X mlwrite("[No such function %s]",tkn); X execstr = oldestr; X return FALSE; X } X X /* save the arguments and go execute the command */ X oldcle = clexec; /* save old clexec flag */ X clexec = newcle; /* in cline execution */ X status = execute(cfp,f,n); X cmdstatus = status; /* save the status */ X clexec = oldcle; /* restore clexec flag */ X execstr = oldestr; X return status; } X /* token: chop a token off a string X return a pointer past the token */ X char * token(src, tok) char *src, *tok; /* source string, destination token string */ { X register int quotef; /* is the current string quoted? */ X X /* first scan past any whitespace in the source string */ X while (isspace(*src)) X ++src; X X /* scan through the source string */ X quotef = FALSE; X while (*src) { X /* process special characters */ X if (*src == '\\') { X ++src; X if (*src == 0) X break; X switch (*src++) { X case 'r': *tok++ = '\r'; break; X case 'n': *tok++ = '\n'; break; X case 't': *tok++ = '\t'; break; X case 'b': *tok++ = '\b'; break; X case 'f': *tok++ = '\f'; break; X default: *tok++ = *(src-1); X } X } else { X /* check for the end of the token */ X if (quotef) { X if (*src == '"') X break; X } else { X if (*src == ' ' || *src == '\t') X break; X } X X /* set quote mode if qoute found */ X if (*src == '"') X quotef = TRUE; X X /* record the character */ X *tok++ = *src++; X } X } X X /* terminate the token and exit */ X if (*src) X ++src; X *tok = 0; X return src; } X macarg(tok) /* get a macro line argument */ char *tok; /* buffer to place argument */ { X int savcle; /* buffer to store original clexec */ X X savcle = clexec; /* save execution mode */ X clexec = TRUE; /* get the argument */ X /* grab token and advance past */ X execstr = token(execstr, tok); X /* evaluate it */ X strcpy(tok, tokval(tok)); X clexec = savcle; /* restore execution mode */ X return TRUE; } X /* nextarg: get the next argument */ X nextarg(buffer) char *buffer; /* buffer to put token into */ { X /* grab token and advance past */ X execstr = token(execstr, buffer); X /* evaluate it */ X strcpy(buffer, tokval(buffer)); X return TRUE; } X /* storemac: Set up a macro buffer and flag to store all X executed command lines there */ X storemac(f, n) int f; /* default flag */ int n; /* macro number to use */ { X register struct BUFFER *bp; /* pointer to macro buffer */ X char bname[NBUFN]; /* name of buffer to use */ X X /* must have a numeric argument to this function */ X if (f == FALSE) { X mlwrite("No macro specified"); X return FALSE; X } X X /* range check the macro number */ X if (n < 1 || n > 40) { X mlwrite("[Macro number out of range]"); X return FALSE; X } X X /* construct the macro buffer name */ X strcpy(bname, "[Macro xx]"); X bname[7] = '0' + (n / 10); X bname[8] = '0' + (n % 10); X X /* set up the new macro buffer */ X if ((bp = bfind(bname, OK_CREAT, BFINVS)) == NULL) { X mlwrite("[Cannot create macro]"); X return FALSE; X } X X /* and make sure it is empty */ X bclear(bp); X X /* and set the macro store pointers to it */ X mstore = TRUE; X bstore = bp; X return TRUE; } X #if PROC /* storeproc: Set up a procedure buffer and flag to store all X executed command lines there */ X storeproc(f, n) int f; /* default flag */ int n; /* macro number to use */ { X register struct BUFFER *bp; /* pointer to macro buffer */ X register int status; /* return status */ X char bname[NBUFN]; /* name of buffer to use */ X X /* a numeric argument means its a numbered macro */ X if (f == TRUE) X return storemac(f, n); X X /* get the name of the procedure */ X bname[1] = 0; X if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE) X return status; X X /* construct the macro buffer name */ X bname[0] = '['; X strcat(bname, "]"); X X /* set up the new macro buffer */ X if ((bp = bfind(bname, OK_CREAT, BFINVS)) == NULL) { X mlwrite("[Can not create macro]"); X return FALSE; X } X X /* and make sure it is empty */ X bclear(bp); X X /* and set the macro store pointers to it */ X mstore = TRUE; X bstore = bp; X return TRUE; } X /* execproc: Execute a procedure */ X execproc(f, n) int f, n; /* default flag and numeric arg */ { X register BUFFER *bp; /* ptr to buffer to execute */ X register int status; /* status return */ X static char obufn[NBUFN+2]; /* name of buffer to execute */ X char bufn[NBUFN+2]; /* name of buffer to execute */ X X /* find out what buffer the user wants to execute */ X if ((status = mlreply("Execute procedure: ", obufn, NBUFN)) != TRUE) X return status; X X /* construct the buffer name */ X bufn[0] = '['; X strcat(bufn, obufn); X strcat(bufn, "]"); X X /* find the pointer to that buffer */ X if ((bp=bfind(bufn, NO_CREAT, 0)) == NULL) { X mlwrite("[No such procedure]"); X return FALSE; X } X X /* and now execute it as asked */ X while (n-- > 0) { X if ((status = dobuf(bp)) != TRUE) X return status; X } X return TRUE; } #endif X #if ! SMALLER /* execbuf: Execute the contents of a buffer of commands */ X execbuf(f, n) int f, n; /* default flag and numeric arg */ { X register BUFFER *bp; /* ptr to buffer to execute */ X register int status; /* status return */ X static char bufn[NSTRING]; /* name of buffer to execute */ X X /* find out what buffer the user wants to execute */ X if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE) X return status; X X /* find the pointer to that buffer */ X if ((bp=bfind(bufn, NO_CREAT, 0)) == NULL) { X mlwrite("No such buffer"); X return FALSE; X } X X /* and now execute it as asked */ X while (n-- > 0) { X if ((status = dobuf(bp)) != TRUE) X return status; X } X return TRUE; } #endif X /* dobuf: execute the contents of the buffer pointed to X by the passed BP X X Directives start with a "!" and include: X #if SMALLER X !endm End a macro #else X !endm End a macro X !if (cond) conditional execution X !else X !endif X !return Return (terminating current macro) X !goto