+
+#ifdef DEBUG
+_C1()
+{
+ return(C1get);
+}
+_C()
+{
+ return(Cget);
+}
+#endif DEBUG
+\f
+/*
+ * Macro processing
+ *
+ * Macro table definitions
+ */
+#define reg register
+typedef int pacmac; /* compressed macro name */
+int argconcat = 0; /* concat arguments together (-me only) */
+
+#define tomac(c1, c2) ((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
+#define frommac(src, c1, c2) (((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
+
+struct mactab{
+ int condition;
+ pacmac macname;
+ int (*func)();
+};
+struct mactab troffmactab[];
+struct mactab ppmactab[];
+struct mactab msmactab[];
+struct mactab mmmactab[];
+struct mactab memactab[];
+struct mactab manmactab[];
+/*
+ * macro table initialization
+ */
+#define M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
+
+/*
+ * Put out a macro line, using ms and mm conventions.
+ */
+msputmac(s, constant)
+ register char *s;
+ int constant;
+{
+ register char *t;
+ register found;
+ int last;
+ found = 0;
+
+ if (wordflag) {
+ msputwords(YES);
+ return;
+ }
+ while(*s)
+ {
+ while(*s==' ' || *s=='\t')
+ putchar(*s++);
+ for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
+ ;
+ if(*s == '\"')s++;
+ if(t>s+constant && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){
+ while(s < t)
+ if(*s == '\"')s++;
+ else
+ putchar(*s++);
+ last = *(t-1);
+ found++;
+ }
+ else if(found && chars[ s[0] ] == PUNCT && s[1] == '\0')
+ putchar(*s++);
+ else{
+ last = *(t-1);
+ s = t;
+ }
+ }
+ putchar('\n');
+ if(msflag && chars[last] == PUNCT){
+ putchar(last);
+ putchar('\n');
+ }
+}
+/*
+ * put out words (for the -w option) with ms and mm conventions
+ */
+msputwords(macline)
+ int macline; /* is this is a macro line */
+{
+ register char *p, *p1;
+ int i, nlet;
+
+ for(p1 = line ; ;) {
+ /*
+ * skip initial specials ampersands and apostrophes
+ */
+ while( chars[*p1] < DIGIT)
+ if(*p1++ == '\0') return;
+ nlet = 0;
+ for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
+ if(i == LETTER) ++nlet;
+
+ if (nlet > 1 && chars[p1[0]] == LETTER) {
+ /*
+ * delete trailing ampersands and apostrophes
+ */
+ while( (i=chars[p[-1]]) == PUNCT || i == APOS )
+ --p;
+ while(p1 < p)
+ putchar(*p1++);
+ putchar('\n');
+ } else {
+ p1 = p;
+ }
+ }
+}
+/*
+ * put out a macro using the me conventions
+ */
+#define SKIPBLANK(cp) while(*cp == ' ' || *cp == '\t') { cp++; }
+#define SKIPNONBLANK(cp) while(*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
+
+meputmac(cp, constant)
+ reg char *cp;
+ int constant;
+{
+ reg char *np;
+ int found;
+ int argno;
+ int last;
+ int inquote;
+
+ if (wordflag) {
+ meputwords(YES);
+ return;
+ }
+ for (argno = 0; *cp; argno++){
+ SKIPBLANK(cp);
+ inquote = (*cp == '"');
+ if (inquote)
+ cp++;
+ for (np = cp; *np; np++){
+ switch(*np){
+ case '\n':
+ case '\0': break;
+ case '\t':
+ case ' ': if (inquote) {
+ continue;
+ } else {
+ goto endarg;
+ }
+ case '"': if(inquote && np[1] == '"'){
+ strcpy(np, np + 1);
+ np++;
+ continue;
+ } else {
+ *np = ' '; /* bye bye " */
+ goto endarg;
+ }
+ default: continue;
+ }
+ }
+ endarg: ;
+ /*
+ * cp points at the first char in the arg
+ * np points one beyond the last char in the arg
+ */
+ if ((argconcat == 0) || (argconcat != argno)) {
+ putchar(' ');
+ }
+#ifdef FULLDEBUG
+ {
+ char *p;
+ printf("[%d,%d: ", argno, np - cp);
+ for (p = cp; p < np; p++) {
+ putchar(*p);
+ }
+ printf("]");
+ }
+#endif FULLDEBUG
+ /*
+ * Determine if the argument merits being printed
+ *
+ * constant is the cut off point below which something
+ * is not a word.
+ */
+ if ( ( (np - cp) > constant)
+ && ( inquote
+ || (chars[cp[0]] == LETTER)) ){
+ for (cp = cp; cp < np; cp++){
+ putchar(*cp);
+ }
+ last = np[-1];
+ found++;
+ } else
+ if(found && (np - cp == 1) && chars[*cp] == PUNCT){
+ putchar(*cp);
+ } else {
+ last = np[-1];
+ }
+ cp = np;
+ }
+ if(msflag && chars[last] == PUNCT)
+ putchar(last);
+ putchar('\n');
+}
+/*
+ * put out words (for the -w option) with ms and mm conventions
+ */
+meputwords(macline)
+ int macline;
+{
+ msputwords(macline);
+}
+/*
+ *
+ * Skip over a nested set of macros
+ *
+ * Possible arguments to noblock are:
+ *
+ * fi end of unfilled text
+ * PE pic ending
+ * DE display ending
+ *
+ * for ms and mm only:
+ * KE keep ending
+ *
+ * NE undocumented match to NS (for mm?)
+ * LE mm only: matches RL or *L (for lists)
+ *
+ * for me:
+ * ([lqbzcdf]
+ */
+
+noblock(a1, a2)
+ char a1, a2;
+{
+ register int c1,c2;
+ register int eqnf;
+ int lct;
+ lct = 0;
+ eqnf = 1;
+ SKIP;
+ while(1){
+ while(C != '.')
+ if(c == '\n')
+ continue;
+ else
+ SKIP;
+ if((c1=C) == '\n')
+ continue;
+ if((c2=C) == '\n')
+ continue;
+ if(c1==a1 && c2 == a2){
+ SKIP;
+ if(lct != 0){
+ lct--;
+ continue;
+ }
+ if(eqnf)
+ putchar('.');
+ putchar('\n');
+ return;
+ } else if(a1 == 'L' && c2 == 'L'){
+ lct++;
+ SKIP;
+ }
+ /*
+ * equations (EQ) nested within a display
+ */
+ else if(c1 == 'E' && c2 == 'Q'){
+ if ( (mac == ME && a1 == ')')
+ || (mac != ME && a1 == 'D') ) {
+ eqn();
+ eqnf=0;
+ }
+ }
+ /*
+ * turning on filling is done by the paragraphing
+ * macros
+ */
+ else if(a1 == 'f') { /* .fi */
+ if ( (mac == ME && (c2 == 'h' || c2 == 'p'))
+ ||(mac != ME && (c1 == 'P' || c2 == 'P')) ) {
+ SKIP;
+ return;
+ }
+ } else {
+ SKIP;
+ }
+ }
+}
+
+EQ()
+{
+ eqn();
+ return(0);
+}
+domacro()
+{
+ macro();
+ return(0);
+}
+PS()
+{
+ for (C; c == ' ' || c == '\t'; C);
+ if (c == '<') { /* ".PS < file" -- don't expect a .PE */
+ SKIP;
+ return(0);
+ }
+ if (!msflag) {
+ inpic();
+ } else {
+ noblock('P', 'E');
+ }
+ return(0);
+}
+
+skip()
+{
+ SKIP;
+ return(0);
+}
+
+intbl()
+{
+ if(msflag){
+ stbl();
+ }
+ else tbl();
+ return(0);
+}
+
+outtbl(){ intable = NO; }
+
+so()
+{
+ getfname();
+ if( fname[0] )
+ infile = *++filesp = opn( fname );
+ return(0);
+}
+nx()
+{
+ getfname();
+ if(fname[0] == '\0') exit(0);
+ if(infile != stdin)
+ fclose(infile);
+ infile = *filesp = opn(fname);
+ return(0);
+}
+skiptocom(){ SKIP_TO_COM; return(COMX); }
+
+PP(c12)
+ pacmac c12;
+{
+ int c1, c2;
+
+ frommac(c12, c1, c2);
+ printf(".%c%c",c1,c2);
+ while(C != '\n')putchar(c);
+ putchar('\n');
+ return(0);
+}
+AU()
+{
+ if(mac==MM) {
+ return(0);
+ } else {
+ SKIP_TO_COM;
+ return(COMX);
+ }
+}
+
+SH(c12)
+ pacmac c12;
+{
+ int c1, c2;
+
+ frommac(c12, c1, c2);
+
+ if(parag){
+ printf(".%c%c",c1,c2);
+ while(C != '\n')putchar(c);
+ putchar(c);
+ putchar('!');
+ while(1){
+ while(C != '\n')putchar(c);
+ putchar('\n');
+ if(C == '.')
+ return(COM);
+ putchar('!');
+ putchar(c);
+ }
+ /*NOTREACHED*/
+ } else {
+ SKIP_TO_COM;
+ return(COMX);
+ }
+}
+
+UX()
+{
+ if(wordflag)
+ printf("UNIX\n");
+ else
+ printf("UNIX ");
+ return(0);
+}
+
+MMHU(c12)
+ pacmac c12;
+{
+ int c1, c2;
+
+ frommac(c12, c1, c2);
+ if(parag){
+ printf(".%c%c",c1,c2);
+ while(C != '\n')putchar(c);
+ putchar('\n');
+ } else {
+ SKIP;
+ }
+ return(0);
+}
+
+mesnblock(c12)
+ pacmac c12;
+{
+ int c1, c2;
+
+ frommac(c12, c1, c2);
+ noblock(')',c2);
+ return(0);
+}
+mssnblock(c12)
+ pacmac c12;
+{
+ int c1, c2;
+
+ frommac(c12, c1, c2);
+ noblock(c1,'E');
+ return(0);
+}
+nf()
+{
+ noblock('f','i');
+ return(0);
+}
+
+ce()
+{
+ sce();
+ return(0);
+}
+
+meip(c12)
+ pacmac c12;
+{
+ if(parag)
+ mepp(c12);
+ else if (wordflag) /* save the tag */
+ regline(meputmac, ONE);
+ else {
+ SKIP;
+ }
+ return(0);
+}
+/*
+ * only called for -me .pp or .sh, when parag is on
+ */
+mepp(c12)
+ pacmac c12;
+{
+ PP(c12); /* eats the line */
+ return(0);
+}
+/*
+ * Start of a section heading; output the section name if doing words
+ */
+mesh(c12)
+ pacmac c12;
+{
+ if (parag)
+ mepp(c12);
+ else if (wordflag)
+ defcomline(c12);
+ else {
+ SKIP;
+ }
+ return(0);
+}
+/*
+ * process a font setting
+ */
+mefont(c12)
+ pacmac c12;
+{
+ argconcat = 1;
+ defcomline(c12);
+ argconcat = 0;
+ return(0);
+}
+manfont(c12)
+ pacmac c12;
+{
+ return(mefont(c12));
+}
+manpp(c12)
+ pacmac c12;
+{
+ return(mepp(c12));
+}
+
+defcomline(c12)
+ pacmac c12;
+{
+ int c1, c2;
+
+ frommac(c12, c1, c2);
+ if(msflag && mac==MM && c2=='L'){
+ if(disp || c1 == 'R') {
+ noblock('L','E');
+ } else {
+ SKIP;
+ putchar('.');
+ }
+ }
+ else if(c1=='.' && c2=='.'){
+ if(msflag){
+ SKIP;
+ return;
+ }
+ while(C == '.')
+ /*VOID*/;
+ }
+ ++inmacro;
+ /*
+ * Process the arguments to the macro
+ */
+ switch(mac){
+ default:
+ case MM:
+ case MS:
+ if(c1 <= 'Z' && msflag)
+ regline(msputmac, ONE);
+ else
+ regline(msputmac, TWO);
+ break;
+ case ME:
+ regline(meputmac, ONE);
+ break;
+ }
+ --inmacro;
+}
+
+comline()
+{
+ reg int c1;
+ reg int c2;
+ pacmac c12;
+ reg int mid;
+ int lb, ub;
+ int hit;
+ static int tabsize = 0;
+ static struct mactab *mactab = (struct mactab *)0;
+ reg struct mactab *mp;
+
+ if (mactab == 0){
+ buildtab(&mactab, &tabsize);
+ }
+com:
+ while(C==' ' || c=='\t')
+ ;
+comx:
+ if( (c1=c) == '\n')
+ return;
+ c2 = C;
+ if(c1=='.' && c2 !='.')
+ inmacro = NO;
+ if(msflag && c1 == '['){
+ refer(c2);
+ return;
+ }
+ if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
+ printf(".P\n");
+ return;
+ }
+ if(c2 == '\n')
+ return;
+ /*
+ * Single letter macro
+ */
+ if (mac == ME && (c2 == ' ' || c2 == '\t') )
+ c2 = ' ';
+ c12 = tomac(c1, c2);
+ /*
+ * binary search through the table of macros
+ */
+ lb = 0;
+ ub = tabsize - 1;
+ while(lb <= ub){
+ mid = (ub + lb) / 2;
+ mp = &mactab[mid];
+ if (mp->macname < c12)
+ lb = mid + 1;
+ else if (mp->macname > c12)
+ ub = mid - 1;
+ else {
+ hit = 1;
+#ifdef FULLDEBUG
+ printf("preliminary hit macro %c%c ", c1, c2);
+#endif FULLDEBUG
+ switch(mp->condition){
+ case NONE: hit = YES; break;
+ case FNEST: hit = (filesp == files); break;
+ case NOMAC: hit = !inmacro; break;
+ case MAC: hit = inmacro; break;
+ case PARAG: hit = parag; break;
+ case NBLK: hit = !keepblock; break;
+ default: hit = 0;
+ }
+ if (hit) {
+#ifdef FULLDEBUG
+ printf("MATCH\n");
+#endif FULLDEBUG
+ switch( (*(mp->func))(c12) ) {
+ default: return;
+ case COMX: goto comx;
+ case COM: goto com;
+ }
+ }
+#ifdef FULLDEBUG
+ printf("FAIL\n");
+#endif FULLDEBUG
+ break;
+ }
+ }
+ defcomline(c12);
+}
+
+int macsort(p1, p2)
+ struct mactab *p1, *p2;
+{
+ return(p1->macname - p2->macname);
+}
+
+int sizetab(mp)
+ reg struct mactab *mp;
+{
+ reg int i;
+ i = 0;
+ if (mp){
+ for (; mp->macname; mp++, i++)
+ /*VOID*/ ;
+ }
+ return(i);
+}
+
+struct mactab *macfill(dst, src)
+ reg struct mactab *dst;
+ reg struct mactab *src;
+{
+ if (src) {
+ while(src->macname){
+ *dst++ = *src++;
+ }
+ }
+ return(dst);
+}
+
+buildtab(r_back, r_size)
+ struct mactab **r_back;
+ int *r_size;
+{
+ int size;
+
+ struct mactab *p, *p1, *p2;
+ struct mactab *back;
+
+ size = sizetab(troffmactab);
+ size += sizetab(ppmactab);
+ p1 = p2 = (struct mactab *)0;
+ if (msflag){
+ switch(mac){
+ case ME: p1 = memactab; break;
+ case MM: p1 = msmactab;
+ p2 = mmmactab; break;
+
+ case MS: p1 = msmactab; break;
+ case MA: p1 = manmactab; break;
+ default: break;
+ }
+ }
+ size += sizetab(p1);
+ size += sizetab(p2);
+ back = (struct mactab *)calloc(size+2, sizeof(struct mactab));
+
+ p = macfill(back, troffmactab);
+ p = macfill(p, ppmactab);
+ p = macfill(p, p1);
+ p = macfill(p, p2);
+
+ qsort(back, size, sizeof(struct mactab), macsort);
+ *r_size = size;
+ *r_back = back;
+}
+
+/*
+ * troff commands
+ */
+struct mactab troffmactab[] = {
+ M(NONE, '\\','"', skip), /* comment */
+ M(NOMAC, 'd','e', domacro), /* define */
+ M(NOMAC, 'i','g', domacro), /* ignore till .. */
+ M(NOMAC, 'a','m', domacro), /* append macro */
+ M(NBLK, 'n','f', nf), /* filled */
+ M(NBLK, 'c','e', ce), /* centered */
+
+ M(NONE, 's','o', so), /* source a file */
+ M(NONE, 'n','x', nx), /* go to next file */
+
+ M(NONE, 't','m', skip), /* print string on tty */
+ M(NONE, 'h','w', skip), /* exception hyphen words */
+ M(NONE, 0,0, 0)
+};
+/*
+ * Preprocessor output
+ */
+struct mactab ppmactab[] = {
+ M(FNEST, 'E','Q', EQ), /* equation starting */
+ M(FNEST, 'T','S', intbl), /* table starting */
+ M(FNEST, 'T','C', intbl), /* alternative table? */
+ M(FNEST, 'T','&', intbl), /* table reformatting */
+ M(NONE, 'T','E', outtbl),/* table ending */
+ M(NONE, 'P','S', PS), /* picture starting */
+ M(NONE, 0,0, 0)
+};
+/*
+ * Particular to ms and mm
+ */
+struct mactab msmactab[] = {
+ M(NONE, 'T','L', skiptocom), /* title follows */
+ M(NONE, 'F','S', skiptocom), /* start footnote */
+ M(NONE, 'O','K', skiptocom), /* Other kws */
+
+ M(NONE, 'N','R', skip), /* undocumented */
+ M(NONE, 'N','D', skip), /* use supplied date */
+
+ M(PARAG, 'P','P', PP), /* begin parag */
+ M(PARAG, 'I','P', PP), /* begin indent parag, tag x */
+ M(PARAG, 'L','P', PP), /* left blocked parag */
+
+ M(NONE, 'A','U', AU), /* author */
+ M(NONE, 'A','I', AU), /* authors institution */
+
+ M(NONE, 'S','H', SH), /* section heading */
+ M(NONE, 'S','N', SH), /* undocumented */
+ M(NONE, 'U','X', UX), /* unix */
+
+ M(NBLK, 'D','S', mssnblock), /* start display text */
+ M(NBLK, 'K','S', mssnblock), /* start keep */
+ M(NBLK, 'K','F', mssnblock), /* start float keep */
+ M(NONE, 0,0, 0)
+};
+
+struct mactab mmmactab[] = {
+ M(NONE, 'H',' ', MMHU), /* -mm ? */
+ M(NONE, 'H','U', MMHU), /* -mm ? */
+ M(PARAG, 'P',' ', PP), /* paragraph for -mm */
+ M(NBLK, 'N','S', mssnblock), /* undocumented */
+ M(NONE, 0,0, 0)
+};
+
+struct mactab memactab[] = {
+ M(PARAG, 'p','p', mepp),
+ M(PARAG, 'l','p', mepp),
+ M(PARAG, 'n','p', mepp),
+ M(NONE, 'i','p', meip),
+
+ M(NONE, 's','h', mesh),
+ M(NONE, 'u','h', mesh),
+
+ M(NBLK, '(','l', mesnblock),
+ M(NBLK, '(','q', mesnblock),
+ M(NBLK, '(','b', mesnblock),
+ M(NBLK, '(','z', mesnblock),
+ M(NBLK, '(','c', mesnblock),
+
+ M(NBLK, '(','d', mesnblock),
+ M(NBLK, '(','f', mesnblock),
+ M(NBLK, '(','x', mesnblock),
+
+ M(NONE, 'r',' ', mefont),
+ M(NONE, 'i',' ', mefont),
+ M(NONE, 'b',' ', mefont),
+ M(NONE, 'u',' ', mefont),
+ M(NONE, 'q',' ', mefont),
+ M(NONE, 'r','b', mefont),
+ M(NONE, 'b','i', mefont),
+ M(NONE, 'b','x', mefont),
+ M(NONE, 0,0, 0)
+};
+
+
+struct mactab manmactab[] = {
+ M(PARAG, 'B','I', manfont),
+ M(PARAG, 'B','R', manfont),
+ M(PARAG, 'I','B', manfont),
+ M(PARAG, 'I','R', manfont),
+ M(PARAG, 'R','B', manfont),
+ M(PARAG, 'R','I', manfont),
+
+ M(PARAG, 'P','P', manpp),
+ M(PARAG, 'L','P', manpp),
+ M(PARAG, 'H','P', manpp),
+ M(NONE, 0,0, 0)
+};