home *** CD-ROM | disk | FTP | other *** search
- /*
- * Command processor for NRO text processor
- *
- * Originally by Stephen L. Browning, 5723 North Parker Avenue
- * Indianapolis, Indiana 46220
- *
- * Transformed beyond immediate recognition, and
- * adapted for Amiga by Olaf Seibert, KosmoSoft
- *
- * Vossendijk 149-1 (study) Beek 5 (home)
- * 5634 TN Nijmegen 5815 CS Merselo
- * The Netherlands The Netherlands
- * Phone:
- * (...-31)80561045 (...-31)4786205
- * or 080-561045 04786-205
- *
- * This program is NOT in the public domain. It may, however
- * be distributed only at no charge, and this notice must be
- * included unaltered.
- */
-
- #include <stdio.h>
- #include "nro.h"
- #include "nroxtrn.h"
-
- uchar *skipbl();
- uchar *skipwd();
-
- /*
- * Communicating the current file through a global
- * variable is a bit of a kludge. We could as well use
- * it everywhere instead of passing it as a parameter
- * all the time. But that would not be very `structured',
- * whatever that may be.
- */
-
- comand(word)
- uchar *word;
- {
- int ct, val;
- int spval;
- uchar argtyp, chr;
- uchar *macexp;
-
- val = getcmdwrd(word, infile);
- if (word[0] == env.c2chr) {
- env.dontbrk = TRUE;
- word++;
- } else if (word[0] == env.cmdchr) {
- word++;
- } else if (val > 0) {
- putbak(' ');
- pbstr(word);
- return;
- }
-
- ct = comtyp(word, &macexp);
-
- if (ct == UNKNOWN) {
- error("nro: unrecognized command %s\n", word);
- env.dontbrk = FALSE;
- return;
- }
- if (! (ct & NOARGS))
- val = getval(&argtyp, infile); /* Eat more of line */
-
- switch (ct & ~NOARGS) {
- case BO: /* Bold face */
- set(&env.boval, val, argtyp, 1, -1, HUGE);
- if (env.boval) env.reqmode |= FXBO;
- else env.reqmode &= ~FXBO;
- if (dc.bsflg != BSAMIGA)
- env.cuval = env.ulval = 0;
- break;
- case BP: /* Begin page */
- if (pg.lineno > 0) space(pg.plval);
- set(&pg.curpag, val, argtyp, pg.curpag+1, -HUGE, HUGE);
- pg.newpag = pg.curpag;
- break;
- case BR: /* Break */
- dobrk();
- break;
- case BS: /* Backspaces in output: 0=No, Amiga; 1=Yes; 2=Use CR */
- set(&dc.bsflg, val, argtyp, 1, 0, 2);
- break;
- case C2: /* No-break command character */
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
- if (iseol(chr)) env.c2chr = C2CHAR;
- else { env.c2chr = chr; ct = 0; }
- break;
- case CC: /* Command character */
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
- if (iseol(chr)) env.cmdchr = CMDCHAR;
- else { env.cmdchr = chr; ct = 0; }
- break;
- case CE: /* Center */
- dobrk();
- set(&env.ceval, val, argtyp, 1, -1, HUGE);
- break;
- case COMMENT:
- while (chr = ngetc(infile), isnteol(chr));
- break;
- case CU: /* Continuous underline */
- set(&env.cuval, val, argtyp, 1, -1, HUGE);
- if (env.cuval) env.reqmode |= FXUL;
- else env.reqmode &= ~FXUL;
- if (dc.bsflg != BSAMIGA)
- env.ulval = env.boval = 0;
- break;
- case DE: /* Define macro */
- defmac(word, infile);
- break;
- case EF: /* Even footer */
- gettl(infile, pg.efoot, NULL, &pg.eflim[0], NULL);
- break;
- case EH: /* Even header */
- gettl(infile, pg.ehead, NULL, &pg.ehlim[0], NULL);
- break;
- case EL: /* Else */
- doel(infile);
- break;
- case EN: /* End macro definition */
- error("nro: missing .de command\n");
- break;
- case EV: /* Environment switch */
- if (isdigit(argtyp)) { /* Supplied argument: push */
- if (dc.envsp >= ENVSTACK-1) {
- error("nro: cannot push environment.\n"); break;
- }
- spval = dc.envstack[dc.envsp]; /* Current environment */
- dc.envstack[++dc.envsp] = val; /* Save number on stack*/
- storenv(spval); /* Save current envir. */
- loadenv(val); /* Get new one */
- } else { /* Pop an environment */
- if ((int) dc.envsp <= 0) {
- error("*** nro: cannot pop environment.\n"); break;
- }
- spval = dc.envstack[dc.envsp]; /* Current environment */
- val = dc.envstack[--dc.envsp]; /* Number of old env */
- if (argtyp == '-') freenv(spval);/* Dump current environ*/
- else storenv(spval); /* ..or save it */
- loadenv(val); /* Get old one back */
- }
- break;
- case FI: /* Fill */
- dobrk();
- env.fill = YES;
- break;
- case FO: /* Footer */
- gettl(infile, pg.efoot, pg.ofoot, &pg.eflim[0], &pg.oflim[0]);
- break;
- case HE: /* Header */
- gettl(infile, pg.ehead, pg.ohead, &pg.ehlim[0], &pg.ohlim[0]);
- break;
- case IE:
- case IF:
- doieif(infile, ct & ~NOARGS);
- break;
- case IN: /* Indenting */
- dobrk();
- set(&env.inval, val, argtyp, 0, 0, env.tmval-1);
- env.tival = env.inval;
- break;
- case IT: /* Italic face */
- set(&env.itval, val, argtyp, 1, -1, HUGE);
- if (env.itval) env.reqmode |= FXIT;
- else env.reqmode &= ~FXIT;
- if (dc.bsflg != BSAMIGA)
- error("nro: italics cannot be done by overstrike :-)\n");
- break;
- case JU: /* Justify */
- env.juval = YES;
- break;
- case LS: /* Line spacing */
- set(&env.lsval, val, argtyp, 1, 1, HUGE);
- break;
- case M1: /* Set topmost margin */
- set(&pg.m1val, val, argtyp, 2, 0, HUGE);
- break;
- case M2: /* Set second top margin */
- set(&pg.m2val, val, argtyp, 2, 0, HUGE);
- break;
- case M3: /* Set first bottom margin */
- set(&pg.m3val, val, argtyp, 2, 0, HUGE);
- pg.bottom = pg.plval - pg.m4val - pg.m3val;
- break;
- case M4: /* Set bottom-most margin */
- set(&pg.m4val, val, argtyp, 2, 0, HUGE);
- pg.bottom = pg.plval - pg.m4val - pg.m3val;
- break;
- case MACRO: /* Macro expansion */
- maceval(macexp, infile);
- break;
- case NE: /* Need n lines */
- /* dobrk(); */
- if ((pg.bottom-pg.lineno+1) < (val*env.lsval)) space(pg.plval);
- break;
- case NF: /* No fill */
- dobrk();
- env.fill = NO;
- break;
- case NJ: /* No justify */
- env.juval = NO;
- break;
- case NR: /* Set number register */
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
- if (!isalpha(chr)) {
- error("nro: invalid or missing number register name\n");
- } else {
- ct = tolower(chr) - 'a';
- val = getval(&chr, infile);
- set(&dc.nr[ct], val, chr, 0, -HUGE, HUGE);
- }
- ct = 0;
- break;
- case OF: /* Odd footer */
- gettl(infile, pg.ofoot, NULL, &pg.oflim[0], NULL);
- break;
- case OH: /* Odd header */
- gettl(infile, pg.ohead, NULL, &pg.ohlim[0], NULL);
- break;
- case PC: /* Page number character */
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
- if (iseol(chr)) env.pgchr = EOS;
- else { env.pgchr = chr; ct = 0; }
- break;
- case PL: /* Page length */
- set(&pg.plval, val, argtyp, PAGELEN,
- pg.m1val+pg.m2val+pg.m3val+pg.m4val+1, HUGE);
- pg.bottom = pg.plval - pg.m3val - pg.m4val;
- break;
- case PN: /* Page numbering mode */
- set(&env.pnflg, val, argtyp, PNARABIC, PNARABIC, PNUROMAN);
- break;
- case PO: /* Page offset */
- set(&pg.offset, val, argtyp, 0, 0, HUGE);
- break;
- case RM: /* Right margin */
- set(&env.rmval, val, argtyp, PAGEWIDTH, env.tival+1, HUGE);
- env.tmval = env.rmval;
- break;
- case SO: /* Source file */
- if (getcmdwrd(word, infile) == EOF) break;
- skipeol(infile);
- ct = NOARGS;
- if (dc.flevel+1 >= NFILES) {
- error("nro: .so commands nested too deeply\n");
- break;
- }
- if ((sofile[dc.flevel+1] = fopen(word, "r")) == NULL) {
- error("nro: unable to open %s\n", word);
- break;
- }
- if (verbose > 2) error("nro: processing file '%s'\n", word);
- sopbb[dc.flevel] = mac.pbb; /* Stack push back stacks */
- mac.pbb = mac.ppb + 1;
- dc.flevel++;
- infile = sofile[dc.flevel];
- break;
- case SP: /* Space */
- set(&spval, val, argtyp, 1, 0, HUGE);
- space(spval * env.lsval);
- break;
- case TA: /* Tab settings */
- tabs(infile);
- break;
- case TI: /* Temporary indent */
- dobrk();
- set(&env.tival, val, argtyp, 0, 0, env.tmval);
- break;
- case TM: /* Terminal Message */
- fflush(stdout);
- if (env.dontbrk == FALSE || pout != stdout) {
- while (val = ngetc(infile), isnteol(val) && val != EOF)
- putc(val, stderr);
- putc('\n', stderr);
- fflush(stderr);
- } else ct = 0; /* Skip rest of command line */
- break;
- case UL: /* Underline */
- set(&env.ulval, val, argtyp, -1, 1, HUGE);
- if (env.ulval) env.reqmode |= FXUL;
- else env.reqmode &= ~FXUL;
- if (dc.bsflg != BSAMIGA)
- env.cuval = env.boval = 0;
- break;
- case UN: /* Undefine macro */
- undefmac(word, infile);
- break;
- }
- env.dontbrk = FALSE;
-
- if (argtyp != STRINGTYP && !(ct & NOARGS)) skipeol(infile);
-
- return;
- }
-
-
- /*
- * Decodes nro command and returns its associated
- * value.
- */
-
- comtyp(line, macdef)
- uchar *line;
- uchar **macdef;
- {
- uchar c1, c2;
-
- /*
- * First check to see if the command is a macro.
- * If it is, return expansion in macdef.
- * Note that upper and lower case characters are handled
- * differently for macro names, but not for normal command names.
- */
-
- if ((*macdef = getmac(line)) != NULL) {
- return MACRO | NOARGS;
- }
-
- c1 = tolower(*line++);
- c2 = tolower(*line );
-
- switch (c1) {
- case '"':
- case '*':
- return COMMENT | NOARGS;
- case 'b':
- if (c2 == 'o') return BO;
- else if (c2 == 'p') return BP;
- else if (c2 == 'r') return BR;
- else if (c2 == 's') return BS;
- break;
- case 'c':
- if (c2 == '2') return C2 | NOARGS;
- else if (c2 == 'c') return CC | NOARGS;
- else if (c2 == 'e') return CE;
- else if (c2 == 'u') return CU;
- break;
- case 'd':
- if (c2 == 'e') return DE | NOARGS;
- break;
- case 'e':
- if (c2 == 'f') return EF | NOARGS;
- else if (c2 == 'h') return EH | NOARGS;
- else if (c2 == 'l') return EL | NOARGS;
- else if (c2 == 'n') return EN;
- else if (c2 == 'v') return EV;
- break;
- case 'f':
- if (c2 == 'i') return FI;
- else if (c2 == 'o') return FO | NOARGS;
- break;
- case 'h':
- if (c2 == 'e') return HE | NOARGS;
- break;
- case 'i':
- if (c2 == 'e') return IE | NOARGS;
- else if (c2 == 'f') return IF | NOARGS;
- else if (c2 == 'n') return IN;
- else if (c2 == 't') return IT;
- break;
- case 'j':
- if (c2 == 'u') return JU;
- break;
- case 'l':
- if (c2 == 's') return LS;
- break;
- case 'm':
- if (c2 == '1') return M1;
- else if (c2 == '2') return M2;
- else if (c2 == '3') return M3;
- else if (c2 == '4') return M4;
- break;
- case 'n':
- if (c2 == 'e') return NE;
- else if (c2 == 'f') return NF;
- else if (c2 == 'j') return NJ;
- else if (c2 == 'r') return NR | NOARGS;
- break;
- case 'o':
- if (c2 == 'f') return OF | NOARGS;
- else if (c2 == 'h') return OH | NOARGS;
- break;
- case 'p':
- if (c2 == 'c') return PC | NOARGS;
- else if (c2 == 'l') return PL;
- else if (c2 == 'n') return PN;
- else if (c2 == 'o') return PO;
- break;
- case 'r':
- if (c2 == 'm') return RM;
- break;
- case 's':
- if (c2 == 'o') return SO | NOARGS;
- else if (c2 == 'p') return SP;
- break;
- case 't':
- if (c2 == 'a') return TA | NOARGS;
- else if (c2 == 'i') return TI;
- else if (c2 == 'm') return TM | NOARGS;
- break;
- case 'u':
- if (c2 == 'l') return UL;
- else if (c2 == 'n') return UN | NOARGS;
- }
- return UNKNOWN;
- }
-
-
- /*
- * Retrieves optional argument following nro command.
- * returns positive integer value with sign (if any)
- * saved in character addressed by pargtyp.
- * In case of a string, puts in a quote.
- * It won't read the character it doesn't understand,
- * i.e. semicolons and newlines, and garbage.
- */
-
- getval(pargtyp, infile)
- uchar *pargtyp;
- register FILE *infile;
- {
- register uchar chr, operator = '+';
- short digit;
- register int val, cumval;
-
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
-
- *pargtyp = chr;
- if (chr == '+' || chr == '-' || chr == '/' || chr == '*')
- chr = ngetc(infile);
- else if (chr == STRINGTYP)
- return 1;
-
- cumval = 0;
-
- again:
- val = 0;
-
- if (chr == '(') { /* Parenthesized subexpression */
- val = getval(&digit, infile); /* Dummy argtype pointer */
- chr = ngetc(infile);
- if (chr != ')')
- error("nro: missing close parenthesis in expression\n");
- else
- chr = ngetc(infile); /* Get next operator or anything */
- if (*pargtyp == '(') *pargtyp = '0';
- } else { /* Try to collect a number from the input */
- while ((digit = atod(chr)) >= 0) {
- val = 10 * val + digit;
- chr = ngetc(infile);
- }
- }
-
- /* Check if we need to evaluate an operator */
- if (operator) {
- switch (operator) {
- case '+': cumval += val; break;
- case '-': cumval -= val; break;
- case '*': cumval *= val; break;
- case '/':
- if (val != 0) cumval /= val;
- else error("nro: division by zero\n");
- break;
- case '%':
- if (val != 0) cumval %= val;
- else error("nro: modulo by zero\n");
- break;
- case '<': cumval = cumval < val; break;
- case '=': cumval = cumval == val; break;
- case '>': cumval = cumval > val; break;
- case '&': cumval = cumval & val; break;
- case '|': cumval = cumval | val; break;
- }
- operator = '\0';
- }
-
- /* See if there is more to come */
- switch (chr) {
- case '+': case '-': case '*': case '/': case '%':
- case '<': case '=': case '>':
- case '&': case '|':
- operator = chr;
- chr = ngetc(infile);
- goto again;
- default:
- putbak(chr); /* Put back what we can't interpret */
-
- return cumval;
- }
- }
-
-
- /*
- * Convert string to decimal.
- * processes only positive values.
- */
-
- ctod(p)
- uchar *p;
- {
- int val, d;
-
- val = 0;
- while (*p != EOS) {
- d = atod(*p++);
- if (d == -1) return val;
- val = 10 * val + d;
- }
- return val;
- }
-
-
- /*
- * Convert ascii character to decimal.
- */
-
- atod(c)
- uchar c;
- {
- return ((c < '0') || (c > '9')) ? -1 : c-'0';
- }
-
-
- /*
- * Get non-blank word from the input file.
- * Returns the number of spaces skipped before the word,
- * or EOF on end of file.
- * It won't read past a newline or semicolon,
- * but will skip the first space following the word.
- */
-
- getcmdwrd(to, infile)
- register uchar *to;
- register FILE *infile;
- {
- register short chr;
- int skipped = 0;
- short length = 0;
-
-
- chr = ngetc(infile);
- if (chr == EOF) {
- *to = EOS;
- return EOF;
- }
-
- /* Skip spaces */
-
- while (isspace(chr)) {
- chr = ngetc(infile);
- skipped++;
- }
-
- while (isntspace(chr) && isnteol(chr) && chr != EOF &&
- chr != MORETXT && length < MAXWORD-3) {
- *to++ = chr;
- length++;
- chr = ngetc(infile);
- }
-
- if (iseol(chr) || chr == MORETXT) putbak(chr);
-
- *to = EOS;
- if (length >= MAXWORD-3) error("nro: command word buffer overflow\n");
-
- return skipped;
- }
-
-
- /*
- * Skip the rest of the current input line
- */
-
- skipeol(infile)
- FILE *infile;
- {
- int chr;
-
- while ((chr = ngetc(infile)) != '\n' && chr != MORETXT &&
- chr != EOF);
- }
-
-
- /*
- * Process an IF or IE request
- */
-
- doieif(infile, request)
- FILE *infile;
- int request;
- {
- uchar *strp;
- short negation;
- int chr, val;
- uchar delim;
- uchar string[MAXWORD];
-
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
- if (chr == '!') {
- negation = TRUE;
- chr = ngetc(infile);
- } else
- negation = FALSE;
-
- switch (chr) {
- case 'e': /* Even page number */
- val = (pg.curpag % 2) == 0;
- break;
- case 'o': /* Odd page number */
- val = (pg.curpag % 2) != 0;
- break;
- case 'n': /* Nro(ff) is formatter */
- val = TRUE; break;
- case 't': /* Troff certainly not */
- val = FALSE; break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case '+': case '-': case '(':
- /* Must be an expression */
- putbak(chr);
- chr = getval(&string[0], infile);
- val = 0;
- set(&val, chr, string[0], 0, -HUGE, HUGE);
- val = val > 0;
- break;
- default: /* String comparison */
- delim = chr;
- strp = string; /* Collect first string */
- while ((chr = ngetc(infile)) != delim &&
- strp < string + sizeof(string) - 2)
- *strp++ = chr;
- *strp = EOS;
- val = TRUE;
-
- strp = string; /* Compare with second string */
- while ((chr = ngetc(infile)) != delim) {
- if (*strp++ != chr) val = FALSE;
- }
- if (*strp != EOS) val = FALSE;
- break;
- }
- if (negation) val = !val;
- if (request == IE) env.lastie = val;
-
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
-
- if (val) { /* Condition is true. Don't skip any text */
- if (chr != BEGIF) putbak(chr);
- } else { /* Need to skip some text, maybe even very much */
- if (chr == BEGIF) /* Skip until end of line */
- dc.iflvl = 1;
- while (isnteol(chr)) chr = ngetc(infile);
- }
- }
-
-
- /*
- * Process an EL request
- */
-
- doel(infile)
- FILE *infile;
- {
- int chr, val;
-
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
-
- /* Toggle last remembered condition */
- val = env.lastie = !env.lastie;
-
- if (val) { /* Condition is true. Don't skip any text */
- if (chr != BEGIF) putbak(chr);
- } else { /* Need to skip some text, maybe even very much */
- if (chr == BEGIF) /* Skip until end of line */
- dc.iflvl = 1;
- while (isnteol(chr)) chr = ngetc(infile);
- }
- }
-
-
- /*
- * Process a TA request
- */
-
- tabs(infile)
- FILE *infile;
- {
- int chr, val, i, j;
-
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
-
- if (iseol(chr) || chr == EOF) { /* No arguments */
- for (i=0; i<MAXTAB; i++)
- env.tabstop[i] = NOTAB;
- return;
- }
-
- i = env.inval;
-
- for (;;) { /* Collect the values */
- putbak(chr);
- val = getval((uchar *)&chr, infile);
-
- if (*(uchar *)&chr == '+') { /* Saves a temporary uchar :-) */
- val += i;
- }
-
- /* Find where to insert the tab */
- i=0;
- while (i<MAXTAB && env.tabstop[i] < val) i++;
-
- if (i < MAXTAB && env.tabstop[i] != val) {
- /* Insert the tab */
- for (j=MAXTAB-1; j > i; j--)
- env.tabstop[j] = env.tabstop[j-1];
-
- env.tabstop[i] = val;
- }
- i = val;
-
- while ((chr = ngetc(infile)) == ' ' || chr == '\t');
- if (iseol(chr) || chr == MORETXT || chr == EOF) break;
- }
- }
-
-
-
- /*
- * Loadenv - get an environment
- */
-
- loadenv(number)
- int number;
- {
- struct environ *envp;
- short freeit = env.dontbrk;
-
- if (number < 0 || number >= NUMENV) return ERR;
-
- envp = environ[number];
-
- if (envp) { /* It't there. Copy it. */
- env = *envp;
- if (freeit) { /* We may free the saved image of it, */
- freenv(number); /* if we are tight on memory. */
- }
- } else { /* It isn't. Just use default values. */
- initenv();
- }
-
- return OK;
- }
-
- /*
- * Storenv - save an environment
- */
-
- storenv(number)
- int number;
- {
- struct environ *envp;
-
- if (number < 0 || number >= NUMENV) return ERR;
-
- envp = environ[number];
-
- if (envp == NULL) { /* Never saw this guy before */
- if ((envp = (struct environ *)malloc(sizeof(*envp))) == NULL) {
- error("*** nro: cannot allocate environment #%d\n", number);
- return ERR;
- } else if (verbose > 2)
- error("nro: allocated environment #%d\n", number);
- environ[number] = envp;
- }
-
- *envp = env;
-
- return OK;
- }
-
-
- /*
- * Freenv - throw an environment away
- */
-
- freenv(number)
- int number;
- {
- struct environ *envp;
-
- if (number < 0 || number >= NUMENV) return ERR;
-
- envp = environ[number];
-
- if (envp) {
- free(envp);
- environ[number] = NULL;
- if (verbose > 2) error("nro: freed environment #%d\n", number);
- }
-
- return OK;
- }
-
-
- /*
- * End current filled line
- */
-
- dobrk()
- {
- if (!env.dontbrk) { /* Breaks may be disabled by using .'xx */
- if (env.outp > 0) {
- #ifdef CPM
- env.outbuf[env.outp++] = '\r';
- env.outbuf[env.outp++] = '\n';
- env.outbuf[env.outp ] = EOS;
- #else CPM
- env.outbuf[env.outp++] = '\n';
- env.outbuf[env.outp ] = EOS;
- #endif CPM
- if (env.ceval != 0) /* Centering */
- center(env.outbuf);
- put(env.outbuf);
- }
- env.outp = 0;
- env.outw = 0;
- env.outwds = 0;
- }
- }
-
-
-
- /*
- * Define a macro
- */
-
- defmac(word, infile)
- uchar *word;
- FILE *infile;
- {
- uchar line[MAXLINE];
-
- getcmdwrd(word, infile);
- skipeol(infile);
-
- if (word[0] == EOS && verbose)
- error("nro: appending to macro definition\n");
-
- while (getlin(line, infile) != EOF) {
- if (line[0] == env.cmdchr && line[1] == 'e' && line[2] == 'n')
- break;
- if (putmac(word, line) == ERR) {
- error("*** nro: macro definition table full\n");
- }
- word[0] = EOS;
- }
- }
-
-
- /*
- * Put macro definition into table.
- * If name == "", concatenate this definition to the previous one.
- */
-
- putmac(name, def)
- uchar *name;
- uchar *def;
- {
- int lenofname, lenofdef;
-
- lenofname = strlen(name);
- lenofdef = strlen(def);
-
- if ((lenofname && mac.lastp >= mac.mxmdef) ||
- (mac.emb + lenofname + lenofdef + 2 > &mac.mb[mac.macbuf])) {
- return ERR;
- }
- if (lenofname) {
- ++mac.lastp;
- mac.mnames[mac.lastp] = mac.emb;
- strcpy(mac.emb, name);
- mac.emb += lenofname + 1;
- } else
- mac.emb--;
-
- strcpy(mac.emb, def);
- mac.emb += lenofdef + 1;
- return OK;
- }
-
-
-
- /*
- * Get macro definition from table
- */
-
- uchar *getmac(name)
- uchar *name;
- {
- register int i;
- register uchar *name1, *mname;
-
-
- for (i = mac.lastp; i > 0; --i) { /*V1.5*/
- name1 = name;
- mname = mac.mnames[i];
- while (*(name1++) == *(mname++)) {
- if (name1[-1] == EOS) return mname;
- }
- }
- return NULL;
- }
-
-
- /*
- * Delete macro definition from table
- */
-
- undefmac(word, infile)
- uchar *word;
- FILE *infile;
- {
- register int i;
- register uchar *name, *mname;
-
- getcmdwrd(word, infile);
- skipeol(infile);
-
- for (i = mac.lastp; i >= 0; --i) {
- name = word;
- mname = mac.mnames[i];
- while (*(name++) == *(mname++)) {
- if (name[-1] == EOS) {
- mac.lastp = i-1;
- mac.emb = mac.mnames[i];
- return OK;
- }
- }
- }
- return ERR;
- }
-
-
-
- /*
- * Evaluate macro expansion for re-evaluation
- */
-
- maceval(macdef, infile)
- register uchar *macdef;
- FILE *infile;
- {
- uchar *argp[10];
- int i;
- uchar c;
- uchar line[MAXLINE];
- register uchar *linep = line;
-
- *linep++ = EOS;
- getlin(linep, infile);
- /*
- * Initialize argp array to substitute empty string
- * string for any undefined argument
- */
- for (i=0; i<10; ++i) argp[i] = line;
-
- for (i=0; i<10; ++i) {
- linep = skipbl(linep);
- if (iseol(*linep) || *linep == MORETXT || *linep == EOS) break;
- if (*linep == '\'' || *linep == '"') {
- c = *linep++;
- argp[i] = linep;
- while (*linep != c && isnteol(*linep) && *linep != EOS)
- linep++;
- *linep++ = EOS;
- } else {
- argp[i] = linep;
- linep = skipwd(linep);
- *linep++ = EOS;
- }
- }
-
- /* First push back any remaining text or commands */
-
- if (*linep == MORETXT) pbstr(linep+1);
-
- /* Now push back macro body */
-
- for (i=strlen(macdef)-1; i>=0; --i) {
- /* Need we substitute an argument? */
- if (i > 0 && macdef[i-1] == '$') {
- if (!isdigit(macdef[i]) || macdef[i-2] == '$') {
- /* Re-evaluate escape characters from macro body */
- putbak(macdef[i] | NOGUARD);
- } else {
- /* but not of any arguments */
- pbstr(argp[macdef[i]-'0']);
- --i;
- }
- } else {
- putbak(macdef[i] | NOGUARD);
- }
- }
- }
-
-
- /*
- * Push back string into input stream for re-evaluation
- */
-
- pbstr(p)
- register uchar p[];
- {
- register int i;
-
- for (i=strlen(p)-1; i>=0; --i) {
- putbak(p[i]);
- }
- }
-
-
-
- /*
- * Push character back into input stream
- */
-
- putbak(c)
- int c;
- {
- if (mac.ppb < mac.pbb) {
- mac.ppb = mac.pbb;
- *mac.ppb = c;
- } else {
- if (mac.ppb >= mac.pbbend-2) {
- error("*** nro: push back buffer overflow\n");
- }
- *++mac.ppb = c;
- }
-
- /* Avoid evaluating escaped escape characters twice */
- if (c == ESCCHAR)
- *++mac.ppb = ESCCHAR;
- }
-
-
-
- /*
- * Get header or footer title
- */
-
- gettl(infile, line1, line2, limit1, limit2)
- FILE *infile;
- uchar *line1, *line2;
- int limit1[], limit2[];
- {
- uchar c;
-
- while (c = ngetc(infile), isspace(c));
-
- line1[0] = c;
- if (isnteol(c)) getlin(line1+1, infile);
- limit1[LEFT] = env.inval;
- limit1[RIGHT] = env.rmval;
- if (line2) {
- strcpy(line2, line1);
- limit2[LEFT] = limit1[LEFT];
- limit2[RIGHT] = limit1[RIGHT];
- }
- }
-
-
-
- /*
- * Set parameter and check range
- */
-
- set(param, val, type, defval, minval, maxval)
- int *param;
- int val;
- uchar type;
- int defval, minval, maxval;
- {
- switch(type) {
- case '+':
- *param += val; break;
- case '-':
- *param -= val; break;
- case '*':
- *param *= val; break;
- case '/':
- if (val != 0) *param /= val;
- else error ("nro: division by zero modification\n");
- break;
- case '%':
- if (val != 0) *param %= val;
- else error ("nro: modulo by zero modification\n");
- break;
- default:
- *param = isdigit(type)? val : defval;
- break;
- }
- if (*param < minval)
- *param = minval;
- else if (*param > maxval)
- *param = maxval;
- }
-
-
-
- /*
- * Skip blanks and tabs in character buffer.
- * return pointer to first non-space char.
- */
-
- uchar *skipbl(p)
- uchar *p;
- {
- while (isspace(*p)) ++p;
- return p;
- }
-
-
- /*
- * Skip over word and punctuation
- */
-
- uchar *skipwd(p)
- uchar *p;
- {
- while (isntspace(*p) && isnteol(*p) && *p != EOS)
- ++p;
- return p;
- }
-
-
-
- /*
- * Space vertically n lines
- */
-
- space(n)
- int n;
- {
- dobrk();
- if (pg.lineno > pg.bottom) return;
- if (pg.lineno == 0) phead();
- skip(min(n, pg.bottom+1-pg.lineno));
- pg.lineno += n;
- if (pg.lineno > pg.bottom) pfoot();
- }
-
-