static char sccsid
[] = "@(#)deroff.c 4.5 (Berkeley) 84/12/18";
* 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)
#define SKIP while(C != '\n')
#define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c
char *mactab
[] = {"-ms", "-mm", "-me", "-ma"};
int msflag
; /* processing a source written using a mac package */
int mac
; /* which package */
int keepblock
; /* keep blocks of text; normally false when msflag */
char chars
[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
* Flags for matching conditions other than
#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 */
for(argc
= ac
- 1, argv
= av
+ 1;
&& (argv
[0][1] != '\0') );
for(p
= argv
[0]+1; *p
; ++p
) {
case 'm': mac
= MM
; p
++; break;
case 's': mac
= MS
; p
++; break;
case 'e': mac
= ME
; p
++; break;
case 'a': mac
= MA
; p
++; break;
case 'l': disp
= YES
; p
++; break;
default: errflg
++; break;
fatal("usage: deroff [ -w ] [ -k] [ -m (a e m s l) ] [ file ] ... \n",
printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
msflag
, mactab
[mac
], keepblock
, disp
);
while((c
= getc(infile
)) != rdelim
)
while( (c
= getc(infile
)) != '"')
if((c
= getc(infile
)) == EOF
)
if( (fd
= fopen(p
, "r")) == NULL
) {
fprintf(stderr
, "Deroff: ");
register struct chain
*q
;
static struct chain
*namechain
= NULL
;
for(p
= fname
; (*p
=c
)!= '\n' && c
!=' ' && c
!='\t' && c
!='\\' ; ++p
)
/* see if this name has already been used */
for(q
= namechain
; q
; q
= q
->nextp
)
if( ! strcmp(fname
, q
->datap
))
q
= (struct chain
*) calloc(1, sizeof(*chainblock
));
fprintf(stderr
, "Deroff: ");
printf("Starting work with `%c'\n", c
);
if(c
== '.' || c
== '\'')
} while(C
!='.' || C
!='.' || C
=='.'); /* look for .. */
if(c
!= 'T' || C
!= 'E'){
while(C
!= '.' || pc
!= '\n' || C
!= 'T' || C
!= 'E')pc
=c
;
if(C1
== '.' || c
== '\'')
while(C1
==' ' || c
=='\t')
else if(c
== 'd') /* look for delim */
if((c1
=c
)=='\n' || (c2
=C1
)=='\n'
|| (c1
=='o' && c2
=='f' && C1
=='f') )
if(c
!= '\n') while(C1
!= '\n'){
if(chars
[c
] == PUNCT
)last
= c
;
else if(c
!= ' ')last
= 0;
backsl() /* skip over a complete backslash construction */
while(C
>='0' && c
<='9') ;
C
; /* discard argument number */
while(C
!='\n' && c
!=bdelim
)
if( (t0
= t
= calloc( (unsigned)(strlen(s
)+1), sizeof(*t
) ) ) == NULL
)
fatal("Cannot allocate memory", (char *) NULL
);
for(ap
=a
;C
!= '\n';ap
++){
else if(c
== 'P' || C
== 'P'){
if(chars
[c2
] == PUNCT
)putchar(c2
);
if(C
== '.' && c1
== '\n'){
else { SKIP
; c
='\n'; continue;}
else { SKIP
; c
='\n';continue; }
else if(c
== '\n' && p1
!= line
){
if(wordflag
)msputwords(NO
);
* 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 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.
while(*s
==' ' || *s
=='\t')
for(t
= s
; *t
!=' ' && *t
!='\t' && *t
!='\0' ; ++t
)
if(t
>s
+const && chars
[ s
[0] ]==LETTER
&& chars
[ s
[1] ]==LETTER
){
else if(found
&& chars
[ s
[0] ] == PUNCT
&& s
[1] == '\0')
if(msflag
&& chars
[last
] == PUNCT
){
* put out words (for the -w option) with ms and mm conventions
int macline
; /* is this is a macro line */
* skip initial specials ampersands and apostrophes
while( chars
[*p1
] < DIGIT
)
if(*p1
++ == '\0') return;
for(p
= p1
; (i
=chars
[*p
]) != SPECIAL
; ++p
)
if (nlet
> 1 && chars
[p1
[0]] == LETTER
) {
* delete trailing ampersands and apostrophes
while( (i
=chars
[p
[-1]]) == PUNCT
|| i
== APOS
)
* 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++; }
for (argno
= 0; *cp
; argno
++){
for (np
= cp
; *np
; np
++){
case '"': if(inquote
&& np
[1] == '"'){
*np
= ' '; /* bye bye " */
* cp points at the first char in the arg
* np points one beyond the last char in the arg
if ((argconcat
== 0) || (argconcat
!= argno
)) {
printf("[%d,%d: ", argno
, np
- cp
);
for (p
= cp
; p
< np
; p
++) {
* Determine if the argument merits being printed
* const is the cut off point below which something
if ( ( (np
- cp
) > const)
|| (chars
[cp
[0]] == LETTER
)) ){
for (cp
= cp
; cp
< np
; cp
++){
if(found
&& (np
- cp
== 1) && chars
[*cp
] == PUNCT
){
if(msflag
&& chars
[last
] == PUNCT
)
* put out words (for the -w option) with ms and mm conventions
* Skip over a nested set of macros
* Possible arguments to noblock are:
* fi end of unfilled text
* NE undocumented match to NS (for mm?)
* LE mm only: matches RL or *L (for lists)
} else if(a1
== 'L' && c2
== 'L'){
* equations (EQ) nested within a display
else if(c1
== 'E' && c2
== 'Q'){
if ( (mac
== ME
&& a1
== ')')
|| (mac
!= ME
&& a1
== 'D') ) {
* turning on filling is done by the paragraphing
else if(a1
== 'f') { /* .fi */
if ( (mac
== ME
&& (c2
== 'h' || c2
== 'p'))
||(mac
!= ME
&& (c1
== 'P' || c2
== 'P')) ) {
outtbl(){ intable
= NO
; }
infile
= *++filesp
= opn( fname
);
if(fname
[0] == '\0') exit(0);
infile
= *filesp
= opn(fname
);
skiptocom(){ SKIP_TO_COM
; return(COMX
); }
while(C
!= '\n')putchar(c
);
while(C
!= '\n')putchar(c
);
while(C
!= '\n')putchar(c
);
while(C
!= '\n')putchar(c
);
else if (wordflag
) /* save the tag */
* only called for -me .pp or .sh, when parag is on
PP(c12
); /* eats the line */
* Start of a section heading; output the section name if doing words
if(msflag
&& mac
==MM
&& c2
=='L'){
else if(c1
=='.' && c2
=='.'){
* Process the arguments to the macro
static struct mactab
*mactab
= (struct mactab
*)0;
buildtab(&mactab
, &tabsize
);
if(parag
&& mac
==MM
&& c1
== 'P' && c2
== '\n'){
if (mac
== ME
&& (c2
== ' ' || c2
== '\t') )
* binary search through the table of macros
else if (mp
->macname
> c12
)
printf("preliminary hit macro %c%c ", c1
, c2
);
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;
switch( (*(mp
->func
))(c12
) ) {
return(p1
->macname
- p2
->macname
);
for (; mp
->macname
; mp
++, i
++)
struct mactab
*macfill(dst
, src
)
struct mactab
*p
, *p1
, *p2
;
size
= sizetab(troffmactab
);
size
+= sizetab(ppmactab
);
p1
= p2
= (struct mactab
*)0;
case ME
: p1
= memactab
; break;
case MS
: p1
= msmactab
; break;
case MA
: p1
= manmactab
; break;
back
= (struct mactab
*)calloc(size
+2, sizeof(struct mactab
));
p
= macfill(back
, troffmactab
);
p
= macfill(p
, ppmactab
);
qsort(back
, size
, sizeof(struct mactab
), macsort
);
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 */
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 */
* 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 */
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 */
struct mactab memactab
[] = {
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
),
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
),