#ifndef lint static char rcsid[] = "$Header: command.c,v 1.4 86/05/05 14:08:32 root Exp $"; #endif /* command.c decodes command. Uses binary search in array * of struct cmd. */ #include "fmtr.h" #define HUGE 1000 #define PLUS '+' #define MINUS '-' #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MIN(x,y) ((x) < (y) ? (x) : (y)) /* cmdtype is upper case version of command. All commands of * interest to us are either ce, ul, or else equivalent to * fi or nf */ enum cmdtype { CE, /* center */ UL, /* underline */ FI, /* fill mode */ NF, /* no fill mode */ PPS, /* start preprocessor statements */ PPE, /* end preprocessor statements */ PS, /* start pic statements, special case .PS < file */ ME_DS, /* start display in me macros */ MM_DS, /* start display in mm macros */ MS_DS, /* start display in ms macros */ DE, /* end display (me or mm) */ OTHER } cmd, getcmd(); int len; struct cmd { char *name; enum cmdtype type; } cmd_table[50] = { "ce", CE, /* basic nroff requests */ "ul", UL, "nf", NF, "fi", FI, "TS", PPS, /* preprocessor start and end */ "TE", PPE, "EQ", PPS, "EN", PPE, "PS", PS, /* special because of .PS < file */ "PE", PPE, "IS", PPS, /* ideal, if you have it! */ "IE", PPE, "G1", PPS, /* grap */ "G2", PPE, "DS", MM_DS, /* ms macros */ "ID", MM_DS, "CD", MM_DS, "LD", MM_DS, "DE", DE, "(b", ME_DS, /* me macros of the display variety */ ")b", DE, "(c", ME_DS, ")c", DE, "(l", ME_DS, ")l", DE, "(z", ME_DS, ")z", DE, (char *) NULL, OTHER }; int val; /* both are set in getval() */ char argtype; /* and used in setparam() */ /* command() takes a line starting with some form of the command start * sequence (period or apostrophe, optionally preceded by \&), and * calls getcmd() to return an integer representing the command name, * and then takes appropriate action. * * In all cases it produces a break and prints out the command line as is. */ command(line) char line[]; { cmd = getcmd(line); if (cmd != OTHER) switch (cmd) { case CE: getval(line); /* only need getval() with CE and UL */ ce_val = setparam(ce_val, 1, 0, HUGE); break; case UL: getval(line); ul_val = setparam(ul_val, 1, 0, HUGE); break; case NF: nf_val = 1; break; case FI: if (in_preproc == 0 && in_display == 0) nf_val = 0; break; case ME_DS: case MM_DS: if (index(line, 'F') == NULL) { in_display = 1; nf_val = 1; } break; case DE: in_display = 0; nf_val = 0; break; case PPS: in_preproc = 1; nf_val = 1; break; case PPE: in_preproc = 0; if (in_display == 0) nf_val = 0; break; case PS: if (index(line, '<') == NULL) { /* not .PS < file */ in_preproc = 1; nf_val = 1; } break; default: fprintf(stderr, "program bug: got cmd = %d\n", cmd); break; } n_brk(); puts(line); } enum cmdtype getcmd(line) /* gets command type by binary search */ char *line; /* stolen from K & R p. 125 with minor changes */ { int high, low, mid, cond; char *cp; low = 0; high = len - 1; cp = (*line == '\\') ? line + 3 : line + 1; while (low <= high) { mid = (low + high)/2; if ((cond = strncmp(cp, cmd_table[mid].name, 2)) < 0) high = mid - 1; else if (cond > 0) low = mid + 1; else return(cmd_table[mid].type); } return(OTHER); } mk_table(sarray, earray) char *sarray, *earray; { int mycmp(); char *cp, *malloc(), *strncpy(); struct cmd *cmdptr; if (len == 0) { /* find end */ cmdptr = cmd_table; while (cmdptr->name) cmdptr++; /* now pointing to NULL ending defined */ len = cmdptr - cmd_table; } else cmdptr = cmd_table + len; if (sarray) for (cp = sarray; *cp; cp += 3) { cmdptr->name = malloc(3); (void) strncpy(cmdptr->name, cp + 1, 2); cmdptr->type = NF; cmdptr++; } if (earray) for (cp = earray; *cp; cp += 3) { cmdptr->name = malloc(3); (void) strncpy(cmdptr->name, cp + 1, 2); cmdptr->type = FI; cmdptr++; } len = cmdptr - cmd_table; qsort((char *) cmd_table, len, sizeof cmd_table[0], mycmp); } mycmp(s1, s2) struct cmd *s1, *s2; { return(strcmp(s1->name, s2->name)); } /* getval() gets value of argument preceded by optional sign. Here we are following the nroff rules: commands are exactly two letters long followed by optional spaces before arguments. */ getval(line) char *line; { char *cp; if (*line == '\\') /* don't test for z_flag, since otherwise */ cp = line + 5; /* we would not be here */ else cp = line + 3; for ( ; isspace(*cp); *cp++) ; argtype = *cp; if (argtype == PLUS || argtype == MINUS) cp++; val = atoi(cp); } /* setparam() sets parameter. May be set to param if present and legal, * otherwise to def_val, if absent, less than min_val or greater than * max_val. */ setparam(param, def_val, min_val, max_val) int param, def_val, min_val, max_val; { if (argtype == '\0') return(def_val); else if (argtype == PLUS) param += val; else if (argtype == MINUS) param -= val; else param = val; param = MAX(param, min_val); param = MIN(param, max_val); return(param); } #ifdef DEBUG print_tab() /* prints table, useful while debugging */ { struct cmd *cmdptr; for (cmdptr = cmd_table; cmdptr < cmd_table + len; cmdptr++) printf("%s\n", cmdptr->name); } #endif