4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
38 #include <sys/varargs.h>
41 * Deroff command -- strip troff, eqn, and Tbl sequences from a file.
42 * Has three flags argument, -w, to cause output one word per line
43 * rather than in the original format.
44 * -mm (or -ms) causes the corresponding macro's to be interpreted
45 * so that just sentences are output
46 * -ml also gets rid of lists.
47 * -i causes deroff to ignore .so and .nx commands.
48 * Deroff follows .so and .nx commands, removes contents of macro
49 * definitions, equations (both .EQ ... .EN and $...$),
50 * Tbl command sequences, and Troff backslash constructions.
52 * All input is through the C macro; the most recently read character
56 #define C ((c = getc(infile)) == EOF ? eof() : \
57 ((c == ldelim) && (filesp == files) ? skeqn() : c))
58 #define C1 ((c = getc(infile)) == EOF ? eof() : c)
59 #define SKIP while (C != '\n')
60 #define SKIP_TO_COM SKIP; SKIP; pc = c; \
61 while ((C != '.') || (pc != '\n') || \
81 static int wordflag
= NO
;
82 static int msflag
= NO
;
83 static int iflag
= NO
;
86 static int inmacro
= NO
;
87 static int intable
= NO
;
89 static size_t linesize
= MAXLINESZ
;
91 static char chars
[128]; /* SPECIAL, APOS, DIGIT, or LETTER */
93 static char *line
= NULL
;
97 static int ldelim
= NOCHAR
;
98 static int rdelim
= NOCHAR
;
105 static char fname
[50];
106 static FILE *files
[15];
107 static FILE **filesp
;
110 static void backsl(void);
111 static void comline(void);
112 static char *copys(char *);
113 static int eof(void);
114 static void eqn(void);
115 static void fatal(const char *, ...);
116 static void fatal_msg(char *);
117 static void getfname(void);
118 static void macro(void);
119 static FILE *opn(char *);
120 static void putmac(char *, int);
121 static void putwords(int);
122 static void regline(int, int);
123 static void sce(void);
124 static int skeqn(void);
125 static void sdis(char, char);
126 static void stbl(void);
127 static void tbl(void);
128 static void usage(void);
129 static void work(void) __NORETURN
;
132 main(int ac
, char **av
)
138 (void) setlocale(LC_ALL
, "");
139 #if !defined(TEXT_DOMAIN)
140 #define TEXT_DOMAIN "SYS_TEST"
142 (void) textdomain(TEXT_DOMAIN
);
145 while ((optchar
= getopt(argc
, argv
, "wim:")) != EOF
) {
154 else if (*optarg
== 's')
156 else if (*optarg
== 'l')
175 infile
= opn(argv
[optind
++]);
179 for (i
= 'a'; i
<= 'z'; ++i
)
181 for (i
= 'A'; i
<= 'Z'; ++i
)
183 for (i
= '0'; i
<= '9'; ++i
)
195 while ((c
= getc(infile
)) != rdelim
) {
198 } else if (c
== '"') {
199 while ((c
= getc(infile
)) != '"') {
202 } else if (c
== '\\') {
203 if ((c
= getc(infile
)) == EOF
) {
217 /* Functions calling opn() should ensure 'p' is non-null */
224 if ((fd
= fopen(p
, "r")) == NULL
)
225 fatal(gettext("Cannot open file %s: %s\n"), p
, strerror(errno
));
236 (void) fclose(infile
);
237 if (filesp
> files
) {
239 } else if (optind
< argc
) {
240 infile
= opn(argv
[optind
++]);
259 static struct chain
*namechain
= NULL
;
264 for (p
= fname
; ((*p
= c
) != '\n') && (c
!= ' ') && (c
!= '\t') &&
273 /* see if this name has already been used */
274 for (q
= namechain
; q
; q
= q
->nextp
)
275 if (strcmp(fname
, q
->datap
) != 0) {
280 q
= (struct chain
*)calloc(1, sizeof (*namechain
));
281 q
->nextp
= namechain
;
282 q
->datap
= copys(fname
);
288 * Functions calling fatal() should ensure 'format' and
289 * arguments are non-null.
292 fatal(const char *format
, ...)
296 assert(format
!= NULL
);
297 (void) fputs(gettext("deroff: "), stderr
);
298 va_start(alist
, format
);
299 (void) vfprintf(stderr
, format
, alist
);
303 /* Functions calling fatal_msg() should ensure 's' is non-null */
308 (void) fprintf(stderr
, gettext("deroff: %s\n"), s
);
315 (void) fputs(gettext(
316 "usage: deroff [ -w ] [ -m (m s l) ] [ -i ] "
317 "[ file ] ... \n"), stderr
);
325 if ((C
== '.') || (c
== '\''))
334 regline(int macline
, int cnst
)
338 if ((line
= (char *)malloc(linesize
* sizeof (char))) == NULL
) {
339 fatal_msg(gettext("Cannot allocate memory"));
349 if (c
== '%') { /* no blank for hyphenation char */
357 * We're just about to add another character to the line
358 * buffer so ensure we don't overrun it.
360 if (++lindx
>= linesize
- 1) {
361 linesize
= linesize
* 2;
362 if ((line
= (char *)realloc(line
,
363 linesize
* sizeof (char))) == NULL
) {
364 fatal_msg(gettext("Cannot allocate memory"));
367 if (intable
&& (c
== 'T')) {
369 if ((c
== '{') || (c
== '}')) {
370 line
[lindx
- 1] = ' ';
380 if (line
[0] != '\0') {
383 } else if (macline
) {
395 putmac(char *s
, int cnst
)
400 while ((*s
== ' ') || (*s
== '\t')) {
401 (void) putchar(*s
++);
403 for (t
= s
; (*t
!= ' ') && (*t
!= '\t') && (*t
!= '\0'); ++t
)
407 if ((t
> s
+ cnst
) && (chars
[s
[0]] == LETTER
) &&
408 (chars
[s
[1]] == LETTER
)) {
413 (void) putchar(*s
++);
419 (void) putchar('\n');
425 putwords(int macline
) /* break into words for -w option */
430 for (p1
= line
; ; ) {
431 /* skip initial specials ampersands and apostrophes */
432 while (chars
[*p1
] < DIGIT
) {
437 for (p
= p1
; (i
= chars
[*p
]) != SPECIAL
; ++p
) {
442 if ((!macline
&& (nlet
> 1)) /* MDM definition of word */ ||
443 (macline
&& (nlet
> 2) && (chars
[p1
[0]] == LETTER
) &&
444 (chars
[p1
[1]] == LETTER
))) {
445 /* delete trailing ampersands and apostrophes */
446 while ((p
[-1] == '\'') || (p
[-1] == '&')) {
450 (void) putchar(*p1
++);
452 (void) putchar('\n');
467 while ((C
== ' ') || (c
== '\t'))
470 if ((c1
= c
) == '\n')
473 if ((c1
== '.') && (c2
!= '.'))
478 if ((c1
== 'E') && (c2
== 'Q') && (filesp
== files
)) {
480 } else if ((c1
== 'T') && ((c2
== 'S') || (c2
== 'C') ||
481 (c2
== '&')) && (filesp
== files
)) {
487 } else if ((c1
== 'T') && (c2
== 'E')) {
489 } else if (!inmacro
&& (c1
== 'd') && (c2
== 'e')) {
491 } else if (!inmacro
&& (c1
== 'i') && (c2
== 'g')) {
493 } else if (!inmacro
&& (c1
== 'a') && (c2
== 'm')) {
495 } else if ((c1
== 's') && (c2
== 'o')) {
501 infile
= *++filesp
= opn(fname
);
504 } else if ((c1
== 'n') && (c2
== 'x')) {
509 if (fname
[0] == '\0') {
512 if (infile
!= stdin
) {
513 (void) fclose(infile
);
515 infile
= *filesp
= opn(fname
);
517 } else if ((c1
== 'h') && (c2
== 'w')) {
519 } else if (msflag
&& (c1
== 'T') && (c2
== 'L')) {
522 } else if (msflag
&& (c1
== 'N') && (c2
== 'R')) {
524 } else if (msflag
&& (c1
== 'A') && ((c2
== 'U') || (c2
== 'I'))) {
531 } else if (msflag
&& (c1
== 'F') && (c2
== 'S')) {
534 } else if (msflag
&& (c1
== 'S') && (c2
== 'H')) {
537 } else if (msflag
&& (c1
== 'N') && (c2
== 'H')) {
540 } else if (msflag
&& (c1
== 'O') && (c2
== 'K')) {
543 } else if (msflag
&& (c1
== 'N') && (c2
== 'D')) {
545 } else if (msflag
&& (mac
== MM
) && (c1
== 'H') &&
546 ((c2
== ' ') || (c2
== 'U'))) {
548 } else if (msflag
&& (mac
== MM
) && (c2
== 'L')) {
549 if (disp
|| (c1
== 'R')) {
555 } else if (msflag
&& ((c1
== 'D') || (c1
== 'N') ||
556 (c1
== 'K') || (c1
== 'P')) && (c2
== 'S')) {
557 sdis(c1
, 'E'); /* removed RS-RE */
558 } else if (msflag
&& (c1
== 'K' && c2
== 'F')) {
560 } else if (msflag
&& (c1
== 'n') && (c2
== 'f')) {
562 } else if (msflag
&& (c1
== 'c') && (c2
== 'e')) {
565 if ((c1
== '.') && (c2
== '.')) {
570 if ((c1
<= 'Z') && msflag
) {
588 } while ((C
!= '.') || (C
!= '.') || (C
== '.'));
602 sdis(char a1
, char a2
)
612 if ((c1
= C
) == '\n')
614 if ((c2
= C
) == '\n')
616 if ((c1
== a1
) && (c2
== a2
)) {
620 (void) putchar('\n');
622 } else if ((a1
== 'D') && (c1
== 'E') && (c2
== 'Q')) {
646 if ((c
!= 'T') || (C
!= 'E')) {
649 while ((C
!= '.') || (pc
!= '\n') ||
650 (C
!= 'T') || (C
!= 'E')) {
668 if ((C1
== '.') || (c
== '\'')) {
669 while ((C1
== ' ') || (c
== '\t'))
671 if ((c
== 'E') && (C1
== 'N')) {
673 if (msflag
&& dflg
) {
683 } else if (c
== 'd') { /* look for delim */
684 if ((C1
== 'e') && (C1
== 'l')) {
685 if ((C1
== 'i') && (C1
== 'm')) {
688 if (((c1
= c
) == '\n') ||
689 ((c2
= C1
) == '\n') ||
690 ((c1
== 'o') && (c2
== 'f') &&
718 backsl(void) /* skip over a complete backslash construction */
730 while ((C
>= '0') && (c
<= '9'))
732 (void) ungetc(c
, infile
);
752 (void) C
; /* discard argument number */
763 if ((bdelim
= C
) == '\n')
765 while ((C
!= '\n') && (c
!= bdelim
))
786 if ((t0
= t
= calloc((unsigned)(strlen(s
) + 1), sizeof (*t
))) == NULL
)
787 fatal_msg(gettext("Cannot allocate memory"));
801 for (ap
= a
; C
!= '\n'; ap
++) {
814 for (i
= 0; i
< n
; ) {