File: [local] / src / usr.bin / deroff / deroff.c (download)
Revision 1.8, Tue Oct 27 23:59:37 2009 UTC (14 years, 7 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_5_6_BASE, OPENBSD_5_6, OPENBSD_5_5_BASE, OPENBSD_5_5, OPENBSD_5_4_BASE, OPENBSD_5_4, OPENBSD_5_3_BASE, OPENBSD_5_3, OPENBSD_5_2_BASE, OPENBSD_5_2, OPENBSD_5_1_BASE, OPENBSD_5_1, OPENBSD_5_0_BASE, OPENBSD_5_0, OPENBSD_4_9_BASE, OPENBSD_4_9, OPENBSD_4_8_BASE, OPENBSD_4_8, OPENBSD_4_7_BASE, OPENBSD_4_7 Changes since 1.7: +1 -15 lines
rcsid[] and sccsid[] and copyright[] are essentially unmaintained (and
unmaintainable). these days, people use source. these id's do not provide
any benefit, and do hurt the small install media
(the 33,000 line diff is essentially mechanical)
ok with the idea millert, ok dms
|
/* $OpenBSD: deroff.c,v 1.8 2009/10/27 23:59:37 deraadt Exp $ */
/*-
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (C) Caldera International Inc. 2001-2002.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code and documentation must retain the above
* copyright notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed or owned by Caldera
* International, Inc.
* 4. Neither the name of Caldera International, Inc. nor the names of other
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
* INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
* INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
* Deroff command -- strip troff, eqn, and Tbl sequences from
* a file. Has two flags argument, -w, to cause output one word per line
* rather than in the original format.
* -mm (or -ms) causes the corresponding macro's to be interpreted
* so that just sentences are output
* -ml also gets rid of lists.
* Deroff follows .so and .nx commands, removes contents of macro
* definitions, equations (both .EQ ... .EN and $...$),
* Tbl command sequences, and Troff backslash constructions.
*
* All input is through the Cget macro;
* the most recently read character is in c.
*
* Modified by Robert Henry to process -me and -man macros.
*/
#define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
#define C1get ( (c=getc(infile)) == EOF ? eof() : c)
#ifdef DEBUG
# define C _C()
# define C1 _C1()
#else /* not DEBUG */
# define C Cget
# define C1 C1get
#endif /* not DEBUG */
#define SKIP while (C != '\n')
#define SKIP_TO_COM SKIP; SKIP; pc=c; while (C != '.' || pc != '\n' || C > 'Z')pc=c
#define YES 1
#define NO 0
#define MS 0 /* -ms */
#define MM 1 /* -mm */
#define ME 2 /* -me */
#define MA 3 /* -man */
#ifdef DEBUG
char *mactab[] = { "-ms", "-mm", "-me", "-ma" };
#endif /* DEBUG */
#define ONE 1
#define TWO 2
#define NOCHAR -2
#define SPECIAL 0
#define APOS 1
#define PUNCT 2
#define DIGIT 3
#define LETTER 4
#define MAXFILES 20
int iflag;
int wordflag;
int msflag; /* processing a source written using a mac package */
int mac; /* which package */
int disp;
int parag;
int inmacro;
int intable;
int keepblock; /* keep blocks of text; normally false when msflag */
char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
char line[LINE_MAX];
char *lp;
int c;
int pc;
int ldelim;
int rdelim;
char fname[PATH_MAX];
FILE *files[MAXFILES];
FILE **filesp;
FILE *infile;
int argc;
char **argv;
/*
* Macro processing
*
* Macro table definitions
*/
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)(); /* XXX - args */
};
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}
/*
* Flags for matching conditions other than
* the macro name
*/
#define NONE 0
#define FNEST 1 /* no nested files */
#define NOMAC 2 /* no macro */
#define MAC 3 /* macro */
#define PARAG 4 /* in a paragraph */
#define MSF 5 /* msflag is on */
#define NBLK 6 /* set if no blocks to be kept */
/*
* Return codes from macro minions, determine where to jump,
* how to repeat/reprocess text
*/
#define COMX 1 /* goto comx */
#define COM 2 /* goto com */
int skeqn(void);
int eof(void);
int _C1(void);
int _C(void);
int EQ(void);
int domacro(void);
int PS(void);
int skip(void);
int intbl(void);
int outtbl(void);
int so(void);
int nx(void);
int skiptocom(void);
int PP(pacmac);
int AU(void);
int SH(pacmac);
int UX(void);
int MMHU(pacmac);
int mesnblock(pacmac);
int mssnblock(pacmac);
int nf(void);
int ce(void);
int meip(pacmac);
int mepp(pacmac);
int mesh(pacmac);
int mefont(pacmac);
int manfont(pacmac);
int manpp(pacmac);
int macsort(const void *, const void *);
int sizetab(struct mactab *);
void getfname(void);
void textline(char *, int);
void work(void);
void regline(void (*)(char *, int), int);
void macro(void);
void tbl(void);
void stbl(void);
void eqn(void);
void backsl(void);
void sce(void);
void refer(int);
void inpic(void);
void msputmac(char *, int);
void msputwords(int);
void meputmac(char *, int);
void meputwords(int);
void noblock(char, char);
void defcomline(pacmac);
void comline(void);
void buildtab(struct mactab **, int *);
FILE *opn(char *);
struct mactab *macfill(struct mactab *, struct mactab *);
__dead void usage(void);
int
main(int ac, char **av)
{
int i, ch;
int errflg = 0;
int kflag = NO;
iflag = NO;
wordflag = NO;
msflag = NO;
mac = ME;
disp = NO;
parag = NO;
inmacro = NO;
intable = NO;
ldelim = NOCHAR;
rdelim = NOCHAR;
keepblock = YES;
while ((ch = getopt(ac, av, "ikpwm:")) != -1) {
switch (ch) {
case 'i':
iflag = YES;
break;
case 'k':
kflag = YES;
break;
case 'm':
msflag = YES;
keepblock = NO;
switch (optarg[0]) {
case 'm':
mac = MM;
break;
case 's':
mac = MS;
break;
case 'e':
mac = ME;
break;
case 'a':
mac = MA;
break;
case 'l':
disp = YES;
break;
default:
errflg++;
break;
}
if (errflg == 0 && optarg[1] != '\0')
errflg++;
break;
case 'p':
parag = YES;
break;
case 'w':
wordflag = YES;
kflag = YES;
break;
default:
errflg++;
}
}
argc = ac - optind;
argv = av + optind;
if (kflag)
keepblock = YES;
if (errflg)
usage();
#ifdef DEBUG
printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
msflag, mactab[mac], keepblock, disp);
#endif /* DEBUG */
if (argc == 0) {
infile = stdin;
} else {
infile = opn(argv[0]);
--argc;
++argv;
}
files[0] = infile;
filesp = &files[0];
for (i = 'a'; i <= 'z' ; ++i)
chars[i] = LETTER;
for (i = 'A'; i <= 'Z'; ++i)
chars[i] = LETTER;
for (i = '0'; i <= '9'; ++i)
chars[i] = DIGIT;
chars['\''] = APOS;
chars['&'] = APOS;
chars['.'] = PUNCT;
chars[','] = PUNCT;
chars[';'] = PUNCT;
chars['?'] = PUNCT;
chars[':'] = PUNCT;
work();
exit(0);
}
int
skeqn(void)
{
while ((c = getc(infile)) != rdelim) {
if (c == EOF)
c = eof();
else if (c == '"') {
while ((c = getc(infile)) != '"') {
if (c == EOF ||
(c == '\\' && (c = getc(infile)) == EOF))
c = eof();
}
}
}
if (msflag)
return((c = 'x'));
return((c = ' '));
}
FILE *
opn(char *p)
{
FILE *fd;
if ((fd = fopen(p, "r")) == NULL)
err(1, "fopen %s", p);
return(fd);
}
int
eof(void)
{
if (infile != stdin)
fclose(infile);
if (filesp > files)
infile = *--filesp;
else if (argc > 0) {
infile = opn(argv[0]);
--argc;
++argv;
} else
exit(0);
return(C);
}
void
getfname(void)
{
char *p;
struct chain {
struct chain *nextp;
char *datap;
} *q;
static struct chain *namechain= NULL;
while (C == ' ')
; /* nothing */
for (p = fname ; p - fname < sizeof(fname) && (*p = c) != '\n' &&
c != ' ' && c != '\t' && c != '\\'; ++p)
C;
*p = '\0';
while (c != '\n')
C;
/* see if this name has already been used */
for (q = namechain ; q; q = q->nextp)
if (strcmp(fname, q->datap) == 0) {
fname[0] = '\0';
return;
}
q = (struct chain *) malloc(sizeof(struct chain));
if (q == NULL)
err(1, NULL);
q->nextp = namechain;
q->datap = strdup(fname);
if (q->datap == NULL)
err(1, NULL);
namechain = q;
}
/*ARGSUSED*/
void
textline(char *str, int constant)
{
if (wordflag) {
msputwords(0);
return;
}
puts(str);
}
void
work(void)
{
for (;;) {
C;
#ifdef FULLDEBUG
printf("Starting work with `%c'\n", c);
#endif /* FULLDEBUG */
if (c == '.' || c == '\'')
comline();
else
regline(textline, TWO);
}
}
void
regline(void (*pfunc)(char *, int), int constant)
{
line[0] = c;
lp = line;
while (lp - line < sizeof(line)) {
if (c == '\\') {
*lp = ' ';
backsl();
}
if (c == '\n')
break;
if (intable && c == 'T') {
*++lp = C;
if (c == '{' || c == '}') {
lp[-1] = ' ';
*lp = C;
}
} else {
*++lp = C;
}
}
*lp = '\0';
if (line[0] != '\0')
(*pfunc)(line, constant);
}
void
macro(void)
{
if (msflag) {
do {
SKIP;
} while (C!='.' || C!='.' || C=='.'); /* look for .. */
if (c != '\n')
SKIP;
return;
}
SKIP;
inmacro = YES;
}
void
tbl(void)
{
while (C != '.')
; /* nothing */
SKIP;
intable = YES;
}
void
stbl(void)
{
while (C != '.')
; /* nothing */
SKIP_TO_COM;
if (c != 'T' || C != 'E') {
SKIP;
pc = c;
while (C != '.' || pc != '\n' || C != 'T' || C != 'E')
pc = c;
}
}
void
eqn(void)
{
int c1, c2;
int dflg;
char last;
last=0;
dflg = 1;
SKIP;
for (;;) {
if (C1 == '.' || c == '\'') {
while (C1 == ' ' || c == '\t')
;
if (c == 'E' && C1 == 'N') {
SKIP;
if (msflag && dflg) {
putchar('x');
putchar(' ');
if (last) {
putchar(last);
putchar('\n');
}
}
return;
}
} else if (c == 'd') {
/* look for delim */
if (C1 == 'e' && C1 == 'l')
if (C1 == 'i' && C1 == 'm') {
while (C1 == ' ')
; /* nothing */
if ((c1 = c) == '\n' ||
(c2 = C1) == '\n' ||
(c1 == 'o' && c2 == 'f' && C1=='f')) {
ldelim = NOCHAR;
rdelim = NOCHAR;
} else {
ldelim = c1;
rdelim = c2;
}
}
dflg = 0;
}
if (c != '\n')
while (C1 != '\n') {
if (chars[c] == PUNCT)
last = c;
else if (c != ' ')
last = 0;
}
}
}
/* skip over a complete backslash construction */
void
backsl(void)
{
int bdelim;
sw:
switch (C) {
case '"':
SKIP;
return;
case 's':
if (C == '\\')
backsl();
else {
while (C >= '0' && c <= '9')
; /* nothing */
ungetc(c, infile);
c = '0';
}
--lp;
return;
case 'f':
case 'n':
case '*':
if (C != '(')
return;
case '(':
if (msflag) {
if (C == 'e') {
if (C == 'm') {
*lp = '-';
return;
}
}
else if (c != '\n')
C;
return;
}
if (C != '\n')
C;
return;
case '$':
C; /* discard argument number */
return;
case 'b':
case 'x':
case 'v':
case 'h':
case 'w':
case 'o':
case 'l':
case 'L':
if ((bdelim = C) == '\n')
return;
while (C != '\n' && c != bdelim)
if (c == '\\')
backsl();
return;
case '\\':
if (inmacro)
goto sw;
default:
return;
}
}
void
sce(void)
{
char *ap;
int n, i;
char a[10];
for (ap = a; C != '\n'; ap++) {
*ap = c;
if (ap == &a[9]) {
SKIP;
ap = a;
break;
}
}
if (ap != a)
n = atoi(a);
else
n = 1;
for (i = 0; i < n;) {
if (C == '.') {
if (C == 'c') {
if (C == 'e') {
while (C == ' ')
; /* nothing */
if (c == '0') {
SKIP;
break;
} else
SKIP;
}
else
SKIP;
} else if (c == 'P' || C == 'P') {
if (c != '\n')
SKIP;
break;
} else if (c != '\n')
SKIP;
} else {
SKIP;
i++;
}
}
}
void
refer(int c1)
{
int c2;
if (c1 != '\n')
SKIP;
for (c2 = -1;;) {
if (C != '.')
SKIP;
else {
if (C != ']')
SKIP;
else {
while (C != '\n')
c2 = c;
if (c2 != -1 && chars[c2] == PUNCT)
putchar(c2);
return;
}
}
}
}
void
inpic(void)
{
int c1;
char *p1;
SKIP;
p1 = line;
c = '\n';
for (;;) {
c1 = c;
if (C == '.' && c1 == '\n') {
if (C != 'P') {
if (c == '\n')
continue;
else {
SKIP;
c = '\n';
continue;
}
}
if (C != 'E') {
if (c == '\n')
continue;
else {
SKIP;
c = '\n';
continue;
}
}
SKIP;
return;
}
else if (c == '\"') {
while (C != '\"') {
if (c == '\\') {
if (C == '\"')
continue;
ungetc(c, infile);
backsl();
} else
*p1++ = c;
}
*p1++ = ' ';
}
else if (c == '\n' && p1 != line) {
*p1 = '\0';
if (wordflag)
msputwords(NO);
else {
puts(line);
putchar('\n');
}
p1 = line;
}
}
}
#ifdef DEBUG
int
_C1(void)
{
return(C1get);
}
int
_C(void)
{
return(Cget);
}
#endif /* DEBUG */
/*
* Put out a macro line, using ms and mm conventions.
*/
void
msputmac(char *s, int constant)
{
char *t;
int found;
int last;
last = 0;
found = 0;
if (wordflag) {
msputwords(YES);
return;
}
while (*s) {
while (*s == ' ' || *s == '\t')
putchar(*s++);
for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t)
; /* nothing */
if (*s == '\"')
s++;
if (t > s + constant && chars[(unsigned char)s[0]] == LETTER &&
chars[(unsigned char)s[1]] == LETTER) {
while (s < t)
if (*s == '\"')
s++;
else
putchar(*s++);
last = *(t-1);
found++;
} else if (found && chars[(unsigned char)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
*/
void
msputwords(int macline)
{
char *p, *p1;
int i, nlet;
for (p1 = line;;) {
/*
* skip initial specials ampersands and apostrophes
*/
while (chars[(unsigned char)*p1] < DIGIT)
if (*p1++ == '\0')
return;
nlet = 0;
for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p)
if (i == LETTER)
++nlet;
if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) {
/*
* delete trailing ampersands and apostrophes
*/
while ((i = chars[(unsigned char)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++; }
void
meputmac(char *cp, int constant)
{
char *np;
int found;
int argno;
int last;
int inquote;
last = 0;
found = 0;
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] == '"') {
memmove(np, np + 1, strlen(np));
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[(unsigned char)cp[0]] == LETTER))) {
for (cp = cp; cp < np; cp++)
putchar(*cp);
last = np[-1];
found++;
} else if (found && (np - cp == 1) &&
chars[(unsigned char)*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
*/
void
meputwords(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]
*/
void
noblock(char a1, char a2)
{
int c1,c2;
int eqnf;
int lct;
lct = 0;
eqnf = 1;
SKIP;
for (;;) {
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;
}
}
}
int
EQ(void)
{
eqn();
return(0);
}
int
domacro(void)
{
macro();
return(0);
}
int
PS(void)
{
for (C; c == ' ' || c == '\t'; C)
; /* nothing */
if (c == '<') { /* ".PS < file" -- don't expect a .PE */
SKIP;
return(0);
}
if (!msflag)
inpic();
else
noblock('P', 'E');
return(0);
}
int
skip(void)
{
SKIP;
return(0);
}
int
intbl(void)
{
if (msflag)
stbl();
else
tbl();
return(0);
}
int
outtbl(void)
{
intable = NO;
return(0);
}
int
so(void)
{
if (!iflag) {
getfname();
if (fname[0]) {
if (++filesp - &files[0] > MAXFILES)
err(1, "too many nested files (max %d)",
MAXFILES);
infile = *filesp = opn(fname);
}
}
return(0);
}
int
nx(void)
{
if (!iflag) {
getfname();
if (fname[0] == '\0')
exit(0);
if (infile != stdin)
fclose(infile);
infile = *filesp = opn(fname);
}
return(0);
}
int
skiptocom(void)
{
SKIP_TO_COM;
return(COMX);
}
int
PP(pacmac c12)
{
int c1, c2;
frommac(c12, c1, c2);
printf(".%c%c", c1, c2);
while (C != '\n')
putchar(c);
putchar('\n');
return(0);
}
int
AU(void)
{
if (mac == MM)
return(0);
SKIP_TO_COM;
return(COMX);
}
int
SH(pacmac c12)
{
int c1, c2;
frommac(c12, c1, c2);
if (parag) {
printf(".%c%c", c1, c2);
while (C != '\n')
putchar(c);
putchar(c);
putchar('!');
for (;;) {
while (C != '\n')
putchar(c);
putchar('\n');
if (C == '.')
return(COM);
putchar('!');
putchar(c);
}
/*NOTREACHED*/
} else {
SKIP_TO_COM;
return(COMX);
}
}
int
UX(void)
{
if (wordflag)
printf("UNIX\n");
else
printf("UNIX ");
return(0);
}
int
MMHU(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);
}
int
mesnblock(pacmac c12)
{
int c1, c2;
frommac(c12, c1, c2);
noblock(')', c2);
return(0);
}
int
mssnblock(pacmac c12)
{
int c1, c2;
frommac(c12, c1, c2);
noblock(c1, 'E');
return(0);
}
int
nf(void)
{
noblock('f', 'i');
return(0);
}
int
ce(void)
{
sce();
return(0);
}
int
meip(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
*/
int
mepp(pacmac c12)
{
PP(c12); /* eats the line */
return(0);
}
/*
* Start of a section heading; output the section name if doing words
*/
int
mesh(pacmac c12)
{
if (parag)
mepp(c12);
else if (wordflag)
defcomline(c12);
else
SKIP;
return(0);
}
/*
* process a font setting
*/
int
mefont(pacmac c12)
{
argconcat = 1;
defcomline(c12);
argconcat = 0;
return(0);
}
int
manfont(pacmac c12)
{
return(mefont(c12));
}
int
manpp(pacmac c12)
{
return(mepp(c12));
}
void
defcomline(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;
}
void
comline(void)
{
int c1;
int c2;
pacmac c12;
int mid;
int lb, ub;
int hit;
static int tabsize = 0;
static struct mactab *mactab = (struct mactab *)0;
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(const void *p1, const void *p2)
{
struct mactab *t1 = (struct mactab *)p1;
struct mactab *t2 = (struct mactab *)p2;
return(t1->macname - t2->macname);
}
int
sizetab(struct mactab *mp)
{
int i;
i = 0;
if (mp) {
for (; mp->macname; mp++, i++)
/*VOID*/ ;
}
return(i);
}
struct mactab *
macfill(struct mactab *dst, struct mactab *src)
{
if (src) {
while (src->macname)
*dst++ = *src++;
}
return(dst);
}
__dead void
usage(void)
{
extern char *__progname;
fprintf(stderr, "usage: %s [-ikpw] [-m a | e | l | m | s] [file ...]\n", __progname);
exit(1);
}
void
buildtab(struct mactab **r_back, int *r_size)
{
int size;
struct mactab *p, *p1, *p2;
struct mactab *back;
size = sizetab(troffmactab) + sizetab(ppmactab);
p1 = p2 = NULL;
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));
if (back == NULL)
err(1, NULL);
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)
};