deroff.c revision 1.4 1 1.4 perry /* $NetBSD: deroff.c,v 1.4 2007/12/15 16:32:06 perry Exp $ */
2 1.1 perry
3 1.1 perry /* taken from: OpenBSD: deroff.c,v 1.6 2004/06/02 14:58:46 tom Exp */
4 1.1 perry
5 1.1 perry /*-
6 1.1 perry * Copyright (c) 1988, 1993
7 1.1 perry * The Regents of the University of California. All rights reserved.
8 1.1 perry *
9 1.1 perry * Redistribution and use in source and binary forms, with or without
10 1.1 perry * modification, are permitted provided that the following conditions
11 1.1 perry * are met:
12 1.1 perry * 1. Redistributions of source code must retain the above copyright
13 1.1 perry * notice, this list of conditions and the following disclaimer.
14 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 perry * notice, this list of conditions and the following disclaimer in the
16 1.1 perry * documentation and/or other materials provided with the distribution.
17 1.1 perry * 3. Neither the name of the University nor the names of its contributors
18 1.1 perry * may be used to endorse or promote products derived from this software
19 1.1 perry * without specific prior written permission.
20 1.1 perry *
21 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 1.1 perry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 1.1 perry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.1 perry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 1.1 perry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 1.1 perry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 1.1 perry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 1.1 perry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 1.1 perry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 1.1 perry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 1.1 perry * SUCH DAMAGE.
32 1.1 perry */
33 1.1 perry /*
34 1.1 perry * Copyright (C) Caldera International Inc. 2001-2002.
35 1.1 perry * All rights reserved.
36 1.1 perry *
37 1.1 perry * Redistribution and use in source and binary forms, with or without
38 1.1 perry * modification, are permitted provided that the following conditions
39 1.1 perry * are met:
40 1.1 perry * 1. Redistributions of source code and documentation must retain the above
41 1.1 perry * copyright notice, this list of conditions and the following disclaimer.
42 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright
43 1.1 perry * notice, this list of conditions and the following disclaimer in the
44 1.1 perry * documentation and/or other materials provided with the distribution.
45 1.1 perry * 3. All advertising materials mentioning features or use of this software
46 1.1 perry * must display the following acknowledgement:
47 1.1 perry * This product includes software developed or owned by Caldera
48 1.1 perry * International, Inc.
49 1.1 perry * 4. Neither the name of Caldera International, Inc. nor the names of other
50 1.1 perry * contributors may be used to endorse or promote products derived from
51 1.1 perry * this software without specific prior written permission.
52 1.1 perry *
53 1.1 perry * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
54 1.1 perry * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
55 1.1 perry * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
56 1.1 perry * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
57 1.1 perry * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
58 1.1 perry * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59 1.1 perry * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
60 1.1 perry * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 1.1 perry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62 1.1 perry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
63 1.1 perry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64 1.1 perry * POSSIBILITY OF SUCH DAMAGE.
65 1.1 perry */
66 1.1 perry
67 1.1 perry #ifndef lint
68 1.1 perry static const char copyright[] =
69 1.1 perry "@(#) Copyright (c) 1988, 1993\n\
70 1.1 perry The Regents of the University of California. All rights reserved.\n";
71 1.1 perry #endif /* not lint */
72 1.1 perry
73 1.1 perry #ifndef lint
74 1.1 perry #if 0
75 1.1 perry static const char sccsid[] = "@(#)deroff.c 8.1 (Berkeley) 6/6/93";
76 1.1 perry #else
77 1.4 perry static const char rcsid[] = "$NetBSD: deroff.c,v 1.4 2007/12/15 16:32:06 perry Exp $";
78 1.1 perry #endif
79 1.1 perry #endif /* not lint */
80 1.1 perry
81 1.4 perry #include <sys/cdefs.h>
82 1.1 perry #include <err.h>
83 1.1 perry #include <limits.h>
84 1.1 perry #include <stdio.h>
85 1.1 perry #include <stdlib.h>
86 1.1 perry #include <string.h>
87 1.1 perry #include <unistd.h>
88 1.1 perry
89 1.1 perry /*
90 1.1 perry * Deroff command -- strip troff, eqn, and Tbl sequences from
91 1.1 perry * a file. Has two flags argument, -w, to cause output one word per line
92 1.1 perry * rather than in the original format.
93 1.1 perry * -mm (or -ms) causes the corresponding macro's to be interpreted
94 1.1 perry * so that just sentences are output
95 1.1 perry * -ml also gets rid of lists.
96 1.1 perry * Deroff follows .so and .nx commands, removes contents of macro
97 1.1 perry * definitions, equations (both .EQ ... .EN and $...$),
98 1.1 perry * Tbl command sequences, and Troff backslash constructions.
99 1.1 perry *
100 1.1 perry * All input is through the Cget macro;
101 1.1 perry * the most recently read character is in c.
102 1.1 perry *
103 1.1 perry * Modified by Robert Henry to process -me and -man macros.
104 1.1 perry */
105 1.1 perry
106 1.1 perry #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
107 1.1 perry #define C1get ( (c=getc(infile)) == EOF ? eof() : c)
108 1.1 perry
109 1.1 perry #ifdef DEBUG
110 1.1 perry # define C _C()
111 1.1 perry # define C1 _C1()
112 1.1 perry #else /* not DEBUG */
113 1.1 perry # define C Cget
114 1.1 perry # define C1 C1get
115 1.1 perry #endif /* not DEBUG */
116 1.1 perry
117 1.1 perry #define SKIP while (C != '\n')
118 1.1 perry #define SKIP_TO_COM SKIP; SKIP; pc=c; while (C != '.' || pc != '\n' || C > 'Z')pc=c
119 1.1 perry
120 1.1 perry #define YES 1
121 1.1 perry #define NO 0
122 1.1 perry #define MS 0 /* -ms */
123 1.1 perry #define MM 1 /* -mm */
124 1.1 perry #define ME 2 /* -me */
125 1.1 perry #define MA 3 /* -man */
126 1.1 perry
127 1.1 perry #ifdef DEBUG
128 1.1 perry char *mactab[] = { "-ms", "-mm", "-me", "-ma" };
129 1.1 perry #endif /* DEBUG */
130 1.1 perry
131 1.1 perry #define ONE 1
132 1.1 perry #define TWO 2
133 1.1 perry
134 1.1 perry #define NOCHAR -2
135 1.1 perry #define SPECIAL 0
136 1.1 perry #define APOS 1
137 1.1 perry #define PUNCT 2
138 1.1 perry #define DIGIT 3
139 1.1 perry #define LETTER 4
140 1.1 perry
141 1.1 perry #define MAXFILES 20
142 1.1 perry
143 1.2 christos static int iflag;
144 1.2 christos static int wordflag;
145 1.2 christos static int msflag; /* processing a source written using a mac package */
146 1.2 christos static int mac; /* which package */
147 1.2 christos static int disp;
148 1.2 christos static int parag;
149 1.2 christos static int inmacro;
150 1.2 christos static int intable;
151 1.2 christos static int keepblock; /* keep blocks of text; normally false when msflag */
152 1.2 christos
153 1.2 christos static char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
154 1.2 christos
155 1.2 christos static char line[LINE_MAX];
156 1.2 christos static char *lp;
157 1.2 christos
158 1.2 christos static int c;
159 1.2 christos static int pc;
160 1.2 christos static int ldelim;
161 1.2 christos static int rdelim;
162 1.2 christos
163 1.2 christos static char fname[PATH_MAX];
164 1.2 christos static FILE *files[MAXFILES];
165 1.2 christos static FILE **filesp;
166 1.2 christos static FILE *infile;
167 1.1 perry
168 1.2 christos static int argc;
169 1.2 christos static char **argv;
170 1.1 perry
171 1.1 perry /*
172 1.1 perry * Macro processing
173 1.1 perry *
174 1.1 perry * Macro table definitions
175 1.1 perry */
176 1.1 perry typedef int pacmac; /* compressed macro name */
177 1.2 christos static int argconcat = 0; /* concat arguments together (-me only) */
178 1.1 perry
179 1.1 perry #define tomac(c1, c2) ((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
180 1.1 perry #define frommac(src, c1, c2) (((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
181 1.1 perry
182 1.2 christos struct mactab {
183 1.1 perry int condition;
184 1.1 perry pacmac macname;
185 1.2 christos int (*func)(pacmac);
186 1.1 perry };
187 1.1 perry
188 1.2 christos static const struct mactab troffmactab[];
189 1.2 christos static const struct mactab ppmactab[];
190 1.2 christos static const struct mactab msmactab[];
191 1.2 christos static const struct mactab mmmactab[];
192 1.2 christos static const struct mactab memactab[];
193 1.2 christos static const struct mactab manmactab[];
194 1.1 perry
195 1.1 perry /*
196 1.1 perry * Macro table initialization
197 1.1 perry */
198 1.1 perry #define M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
199 1.1 perry
200 1.1 perry /*
201 1.1 perry * Flags for matching conditions other than
202 1.1 perry * the macro name
203 1.1 perry */
204 1.1 perry #define NONE 0
205 1.1 perry #define FNEST 1 /* no nested files */
206 1.1 perry #define NOMAC 2 /* no macro */
207 1.1 perry #define MAC 3 /* macro */
208 1.1 perry #define PARAG 4 /* in a paragraph */
209 1.1 perry #define MSF 5 /* msflag is on */
210 1.1 perry #define NBLK 6 /* set if no blocks to be kept */
211 1.1 perry
212 1.1 perry /*
213 1.1 perry * Return codes from macro minions, determine where to jump,
214 1.1 perry * how to repeat/reprocess text
215 1.1 perry */
216 1.1 perry #define COMX 1 /* goto comx */
217 1.1 perry #define COM 2 /* goto com */
218 1.1 perry
219 1.2 christos static int skeqn(void);
220 1.2 christos static int eof(void);
221 1.2 christos #ifdef DEBUG
222 1.2 christos static int _C1(void);
223 1.2 christos static int _C(void);
224 1.2 christos #endif
225 1.2 christos static int EQ(pacmac);
226 1.2 christos static int domacro(pacmac);
227 1.2 christos static int PS(pacmac);
228 1.2 christos static int skip(pacmac);
229 1.2 christos static int intbl(pacmac);
230 1.2 christos static int outtbl(pacmac);
231 1.2 christos static int so(pacmac);
232 1.2 christos static int nx(pacmac);
233 1.2 christos static int skiptocom(pacmac);
234 1.2 christos static int PP(pacmac);
235 1.2 christos static int AU(pacmac);
236 1.2 christos static int SH(pacmac);
237 1.2 christos static int UX(pacmac);
238 1.2 christos static int MMHU(pacmac);
239 1.2 christos static int mesnblock(pacmac);
240 1.2 christos static int mssnblock(pacmac);
241 1.2 christos static int nf(pacmac);
242 1.2 christos static int ce(pacmac);
243 1.2 christos static int meip(pacmac);
244 1.2 christos static int mepp(pacmac);
245 1.2 christos static int mesh(pacmac);
246 1.2 christos static int mefont(pacmac);
247 1.2 christos static int manfont(pacmac);
248 1.2 christos static int manpp(pacmac);
249 1.2 christos static int macsort(const void *, const void *);
250 1.2 christos static int sizetab(const struct mactab *);
251 1.2 christos static void getfname(void);
252 1.2 christos static void textline(char *, int);
253 1.2 christos static void work(void);
254 1.2 christos static void regline(void (*)(char *, int), int);
255 1.2 christos static void macro(void);
256 1.2 christos static void tbl(void);
257 1.2 christos static void stbl(void);
258 1.2 christos static void eqn(void);
259 1.2 christos static void backsl(void);
260 1.2 christos static void sce(void);
261 1.2 christos static void refer(int);
262 1.2 christos static void inpic(void);
263 1.2 christos static void msputmac(char *, int);
264 1.2 christos static void msputwords(int);
265 1.2 christos static void meputmac(char *, int);
266 1.2 christos static void meputwords(int);
267 1.2 christos static void noblock(char, char);
268 1.2 christos static void defcomline(pacmac);
269 1.2 christos static void comline(void);
270 1.2 christos static void buildtab(const struct mactab **, int *);
271 1.2 christos static FILE *opn(char *);
272 1.2 christos static struct mactab *macfill(struct mactab *, const struct mactab *);
273 1.2 christos static void usage(void) __attribute__((__noreturn__));
274 1.1 perry
275 1.1 perry int
276 1.1 perry main(int ac, char **av)
277 1.1 perry {
278 1.1 perry int i, ch;
279 1.1 perry int errflg = 0;
280 1.1 perry int kflag = NO;
281 1.1 perry
282 1.1 perry iflag = NO;
283 1.1 perry wordflag = NO;
284 1.1 perry msflag = NO;
285 1.1 perry mac = ME;
286 1.1 perry disp = NO;
287 1.1 perry parag = NO;
288 1.1 perry inmacro = NO;
289 1.1 perry intable = NO;
290 1.1 perry ldelim = NOCHAR;
291 1.1 perry rdelim = NOCHAR;
292 1.1 perry keepblock = YES;
293 1.1 perry
294 1.1 perry while ((ch = getopt(ac, av, "ikpwm:")) != -1) {
295 1.1 perry switch (ch) {
296 1.1 perry case 'i':
297 1.1 perry iflag = YES;
298 1.1 perry break;
299 1.1 perry case 'k':
300 1.1 perry kflag = YES;
301 1.1 perry break;
302 1.1 perry case 'm':
303 1.1 perry msflag = YES;
304 1.1 perry keepblock = NO;
305 1.1 perry switch (optarg[0]) {
306 1.1 perry case 'm':
307 1.1 perry mac = MM;
308 1.1 perry break;
309 1.1 perry case 's':
310 1.1 perry mac = MS;
311 1.1 perry break;
312 1.1 perry case 'e':
313 1.1 perry mac = ME;
314 1.1 perry break;
315 1.1 perry case 'a':
316 1.1 perry mac = MA;
317 1.1 perry break;
318 1.1 perry case 'l':
319 1.1 perry disp = YES;
320 1.1 perry break;
321 1.1 perry default:
322 1.1 perry errflg++;
323 1.1 perry break;
324 1.1 perry }
325 1.1 perry if (errflg == 0 && optarg[1] != '\0')
326 1.1 perry errflg++;
327 1.1 perry break;
328 1.1 perry case 'p':
329 1.1 perry parag = YES;
330 1.1 perry break;
331 1.1 perry case 'w':
332 1.1 perry wordflag = YES;
333 1.1 perry kflag = YES;
334 1.1 perry break;
335 1.1 perry default:
336 1.1 perry errflg++;
337 1.1 perry }
338 1.1 perry }
339 1.1 perry argc = ac - optind;
340 1.1 perry argv = av + optind;
341 1.1 perry
342 1.1 perry if (kflag)
343 1.1 perry keepblock = YES;
344 1.1 perry if (errflg)
345 1.1 perry usage();
346 1.1 perry
347 1.1 perry #ifdef DEBUG
348 1.1 perry printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
349 1.1 perry msflag, mactab[mac], keepblock, disp);
350 1.1 perry #endif /* DEBUG */
351 1.1 perry if (argc == 0) {
352 1.1 perry infile = stdin;
353 1.1 perry } else {
354 1.1 perry infile = opn(argv[0]);
355 1.1 perry --argc;
356 1.1 perry ++argv;
357 1.1 perry }
358 1.1 perry files[0] = infile;
359 1.1 perry filesp = &files[0];
360 1.1 perry
361 1.1 perry for (i = 'a'; i <= 'z' ; ++i)
362 1.1 perry chars[i] = LETTER;
363 1.1 perry for (i = 'A'; i <= 'Z'; ++i)
364 1.1 perry chars[i] = LETTER;
365 1.1 perry for (i = '0'; i <= '9'; ++i)
366 1.1 perry chars[i] = DIGIT;
367 1.1 perry chars['\''] = APOS;
368 1.1 perry chars['&'] = APOS;
369 1.1 perry chars['.'] = PUNCT;
370 1.1 perry chars[','] = PUNCT;
371 1.1 perry chars[';'] = PUNCT;
372 1.1 perry chars['?'] = PUNCT;
373 1.1 perry chars[':'] = PUNCT;
374 1.1 perry work();
375 1.2 christos return 0;
376 1.1 perry }
377 1.1 perry
378 1.2 christos static int
379 1.1 perry skeqn(void)
380 1.1 perry {
381 1.1 perry
382 1.1 perry while ((c = getc(infile)) != rdelim) {
383 1.1 perry if (c == EOF)
384 1.1 perry c = eof();
385 1.1 perry else if (c == '"') {
386 1.1 perry while ((c = getc(infile)) != '"') {
387 1.1 perry if (c == EOF ||
388 1.1 perry (c == '\\' && (c = getc(infile)) == EOF))
389 1.1 perry c = eof();
390 1.1 perry }
391 1.1 perry }
392 1.1 perry }
393 1.1 perry if (msflag)
394 1.2 christos return c == 'x';
395 1.2 christos return c == ' ';
396 1.1 perry }
397 1.1 perry
398 1.2 christos static FILE *
399 1.1 perry opn(char *p)
400 1.1 perry {
401 1.1 perry FILE *fd;
402 1.1 perry
403 1.1 perry if ((fd = fopen(p, "r")) == NULL)
404 1.1 perry err(1, "fopen %s", p);
405 1.1 perry
406 1.2 christos return fd;
407 1.1 perry }
408 1.1 perry
409 1.2 christos static int
410 1.1 perry eof(void)
411 1.1 perry {
412 1.1 perry
413 1.1 perry if (infile != stdin)
414 1.1 perry fclose(infile);
415 1.1 perry if (filesp > files)
416 1.1 perry infile = *--filesp;
417 1.1 perry else if (argc > 0) {
418 1.1 perry infile = opn(argv[0]);
419 1.1 perry --argc;
420 1.1 perry ++argv;
421 1.1 perry } else
422 1.1 perry exit(0);
423 1.2 christos return C;
424 1.1 perry }
425 1.1 perry
426 1.2 christos static void
427 1.1 perry getfname(void)
428 1.1 perry {
429 1.1 perry char *p;
430 1.1 perry struct chain {
431 1.1 perry struct chain *nextp;
432 1.1 perry char *datap;
433 1.1 perry } *q;
434 1.1 perry static struct chain *namechain= NULL;
435 1.1 perry
436 1.1 perry while (C == ' ')
437 1.1 perry ; /* nothing */
438 1.1 perry
439 1.1 perry for (p = fname ; p - fname < sizeof(fname) && (*p = c) != '\n' &&
440 1.1 perry c != ' ' && c != '\t' && c != '\\'; ++p)
441 1.1 perry C;
442 1.1 perry *p = '\0';
443 1.1 perry while (c != '\n')
444 1.1 perry C;
445 1.1 perry
446 1.1 perry /* see if this name has already been used */
447 1.1 perry for (q = namechain ; q; q = q->nextp)
448 1.1 perry if (strcmp(fname, q->datap) == 0) {
449 1.1 perry fname[0] = '\0';
450 1.1 perry return;
451 1.1 perry }
452 1.1 perry
453 1.1 perry q = (struct chain *) malloc(sizeof(struct chain));
454 1.1 perry if (q == NULL)
455 1.1 perry err(1, NULL);
456 1.1 perry q->nextp = namechain;
457 1.1 perry q->datap = strdup(fname);
458 1.1 perry if (q->datap == NULL)
459 1.1 perry err(1, NULL);
460 1.1 perry namechain = q;
461 1.1 perry }
462 1.1 perry
463 1.1 perry /*ARGSUSED*/
464 1.2 christos static void
465 1.1 perry textline(char *str, int constant)
466 1.1 perry {
467 1.1 perry
468 1.1 perry if (wordflag) {
469 1.1 perry msputwords(0);
470 1.1 perry return;
471 1.1 perry }
472 1.1 perry puts(str);
473 1.1 perry }
474 1.1 perry
475 1.1 perry void
476 1.1 perry work(void)
477 1.1 perry {
478 1.1 perry
479 1.1 perry for (;;) {
480 1.1 perry C;
481 1.1 perry #ifdef FULLDEBUG
482 1.1 perry printf("Starting work with `%c'\n", c);
483 1.1 perry #endif /* FULLDEBUG */
484 1.1 perry if (c == '.' || c == '\'')
485 1.1 perry comline();
486 1.1 perry else
487 1.1 perry regline(textline, TWO);
488 1.1 perry }
489 1.1 perry }
490 1.1 perry
491 1.2 christos static void
492 1.1 perry regline(void (*pfunc)(char *, int), int constant)
493 1.1 perry {
494 1.1 perry
495 1.1 perry line[0] = c;
496 1.1 perry lp = line;
497 1.1 perry while (lp - line < sizeof(line)) {
498 1.1 perry if (c == '\\') {
499 1.1 perry *lp = ' ';
500 1.1 perry backsl();
501 1.1 perry }
502 1.1 perry if (c == '\n')
503 1.1 perry break;
504 1.1 perry if (intable && c == 'T') {
505 1.1 perry *++lp = C;
506 1.1 perry if (c == '{' || c == '}') {
507 1.1 perry lp[-1] = ' ';
508 1.1 perry *lp = C;
509 1.1 perry }
510 1.1 perry } else {
511 1.1 perry *++lp = C;
512 1.1 perry }
513 1.1 perry }
514 1.1 perry *lp = '\0';
515 1.1 perry
516 1.1 perry if (line[0] != '\0')
517 1.1 perry (*pfunc)(line, constant);
518 1.1 perry }
519 1.1 perry
520 1.2 christos static void
521 1.1 perry macro(void)
522 1.1 perry {
523 1.1 perry
524 1.1 perry if (msflag) {
525 1.1 perry do {
526 1.1 perry SKIP;
527 1.1 perry } while (C!='.' || C!='.' || C=='.'); /* look for .. */
528 1.1 perry if (c != '\n')
529 1.1 perry SKIP;
530 1.1 perry return;
531 1.1 perry }
532 1.1 perry SKIP;
533 1.1 perry inmacro = YES;
534 1.1 perry }
535 1.1 perry
536 1.2 christos static void
537 1.1 perry tbl(void)
538 1.1 perry {
539 1.1 perry
540 1.1 perry while (C != '.')
541 1.1 perry ; /* nothing */
542 1.1 perry SKIP;
543 1.1 perry intable = YES;
544 1.1 perry }
545 1.1 perry
546 1.2 christos static void
547 1.1 perry stbl(void)
548 1.1 perry {
549 1.1 perry
550 1.1 perry while (C != '.')
551 1.1 perry ; /* nothing */
552 1.1 perry SKIP_TO_COM;
553 1.1 perry if (c != 'T' || C != 'E') {
554 1.1 perry SKIP;
555 1.1 perry pc = c;
556 1.1 perry while (C != '.' || pc != '\n' || C != 'T' || C != 'E')
557 1.1 perry pc = c;
558 1.1 perry }
559 1.1 perry }
560 1.1 perry
561 1.2 christos static void
562 1.1 perry eqn(void)
563 1.1 perry {
564 1.1 perry int c1, c2;
565 1.1 perry int dflg;
566 1.1 perry char last;
567 1.1 perry
568 1.1 perry last=0;
569 1.1 perry dflg = 1;
570 1.1 perry SKIP;
571 1.1 perry
572 1.1 perry for (;;) {
573 1.1 perry if (C1 == '.' || c == '\'') {
574 1.1 perry while (C1 == ' ' || c == '\t')
575 1.1 perry ;
576 1.1 perry if (c == 'E' && C1 == 'N') {
577 1.1 perry SKIP;
578 1.1 perry if (msflag && dflg) {
579 1.1 perry putchar('x');
580 1.1 perry putchar(' ');
581 1.1 perry if (last) {
582 1.1 perry putchar(last);
583 1.1 perry putchar('\n');
584 1.1 perry }
585 1.1 perry }
586 1.1 perry return;
587 1.1 perry }
588 1.1 perry } else if (c == 'd') {
589 1.1 perry /* look for delim */
590 1.1 perry if (C1 == 'e' && C1 == 'l')
591 1.1 perry if (C1 == 'i' && C1 == 'm') {
592 1.1 perry while (C1 == ' ')
593 1.1 perry ; /* nothing */
594 1.1 perry
595 1.1 perry if ((c1 = c) == '\n' ||
596 1.1 perry (c2 = C1) == '\n' ||
597 1.1 perry (c1 == 'o' && c2 == 'f' && C1=='f')) {
598 1.1 perry ldelim = NOCHAR;
599 1.1 perry rdelim = NOCHAR;
600 1.1 perry } else {
601 1.1 perry ldelim = c1;
602 1.1 perry rdelim = c2;
603 1.1 perry }
604 1.1 perry }
605 1.1 perry dflg = 0;
606 1.1 perry }
607 1.1 perry
608 1.1 perry if (c != '\n')
609 1.1 perry while (C1 != '\n') {
610 1.1 perry if (chars[c] == PUNCT)
611 1.1 perry last = c;
612 1.1 perry else if (c != ' ')
613 1.1 perry last = 0;
614 1.1 perry }
615 1.1 perry }
616 1.1 perry }
617 1.1 perry
618 1.1 perry /* skip over a complete backslash construction */
619 1.2 christos static void
620 1.1 perry backsl(void)
621 1.1 perry {
622 1.1 perry int bdelim;
623 1.1 perry
624 1.1 perry sw:
625 1.1 perry switch (C) {
626 1.1 perry case '"':
627 1.1 perry SKIP;
628 1.1 perry return;
629 1.1 perry
630 1.1 perry case 's':
631 1.1 perry if (C == '\\')
632 1.1 perry backsl();
633 1.1 perry else {
634 1.1 perry while (C >= '0' && c <= '9')
635 1.1 perry ; /* nothing */
636 1.1 perry ungetc(c, infile);
637 1.1 perry c = '0';
638 1.1 perry }
639 1.1 perry --lp;
640 1.1 perry return;
641 1.1 perry
642 1.1 perry case 'f':
643 1.1 perry case 'n':
644 1.1 perry case '*':
645 1.1 perry if (C != '(')
646 1.1 perry return;
647 1.1 perry
648 1.1 perry case '(':
649 1.1 perry if (msflag) {
650 1.1 perry if (C == 'e') {
651 1.1 perry if (C == 'm') {
652 1.1 perry *lp = '-';
653 1.1 perry return;
654 1.1 perry }
655 1.1 perry }
656 1.1 perry else if (c != '\n')
657 1.1 perry C;
658 1.1 perry return;
659 1.1 perry }
660 1.1 perry if (C != '\n')
661 1.1 perry C;
662 1.1 perry return;
663 1.1 perry
664 1.1 perry case '$':
665 1.1 perry C; /* discard argument number */
666 1.1 perry return;
667 1.1 perry
668 1.1 perry case 'b':
669 1.1 perry case 'x':
670 1.1 perry case 'v':
671 1.1 perry case 'h':
672 1.1 perry case 'w':
673 1.1 perry case 'o':
674 1.1 perry case 'l':
675 1.1 perry case 'L':
676 1.1 perry if ((bdelim = C) == '\n')
677 1.1 perry return;
678 1.1 perry while (C != '\n' && c != bdelim)
679 1.1 perry if (c == '\\')
680 1.1 perry backsl();
681 1.1 perry return;
682 1.1 perry
683 1.1 perry case '\\':
684 1.1 perry if (inmacro)
685 1.1 perry goto sw;
686 1.1 perry
687 1.1 perry default:
688 1.1 perry return;
689 1.1 perry }
690 1.1 perry }
691 1.1 perry
692 1.2 christos static void
693 1.1 perry sce(void)
694 1.1 perry {
695 1.1 perry char *ap;
696 1.1 perry int n, i;
697 1.1 perry char a[10];
698 1.1 perry
699 1.1 perry for (ap = a; C != '\n'; ap++) {
700 1.1 perry *ap = c;
701 1.1 perry if (ap == &a[9]) {
702 1.1 perry SKIP;
703 1.1 perry ap = a;
704 1.1 perry break;
705 1.1 perry }
706 1.1 perry }
707 1.1 perry if (ap != a)
708 1.1 perry n = atoi(a);
709 1.1 perry else
710 1.1 perry n = 1;
711 1.1 perry for (i = 0; i < n;) {
712 1.1 perry if (C == '.') {
713 1.1 perry if (C == 'c') {
714 1.1 perry if (C == 'e') {
715 1.1 perry while (C == ' ')
716 1.1 perry ; /* nothing */
717 1.1 perry if (c == '0') {
718 1.1 perry SKIP;
719 1.1 perry break;
720 1.1 perry } else
721 1.1 perry SKIP;
722 1.1 perry }
723 1.1 perry else
724 1.1 perry SKIP;
725 1.1 perry } else if (c == 'P' || C == 'P') {
726 1.1 perry if (c != '\n')
727 1.1 perry SKIP;
728 1.1 perry break;
729 1.1 perry } else if (c != '\n')
730 1.1 perry SKIP;
731 1.1 perry } else {
732 1.1 perry SKIP;
733 1.1 perry i++;
734 1.1 perry }
735 1.1 perry }
736 1.1 perry }
737 1.1 perry
738 1.2 christos static void
739 1.1 perry refer(int c1)
740 1.1 perry {
741 1.1 perry int c2;
742 1.1 perry
743 1.1 perry if (c1 != '\n')
744 1.1 perry SKIP;
745 1.1 perry
746 1.1 perry for (c2 = -1;;) {
747 1.1 perry if (C != '.')
748 1.1 perry SKIP;
749 1.1 perry else {
750 1.1 perry if (C != ']')
751 1.1 perry SKIP;
752 1.1 perry else {
753 1.1 perry while (C != '\n')
754 1.1 perry c2 = c;
755 1.1 perry if (c2 != -1 && chars[c2] == PUNCT)
756 1.1 perry putchar(c2);
757 1.1 perry return;
758 1.1 perry }
759 1.1 perry }
760 1.1 perry }
761 1.1 perry }
762 1.1 perry
763 1.2 christos static void
764 1.1 perry inpic(void)
765 1.1 perry {
766 1.1 perry int c1;
767 1.1 perry char *p1;
768 1.1 perry
769 1.1 perry SKIP;
770 1.1 perry p1 = line;
771 1.1 perry c = '\n';
772 1.1 perry for (;;) {
773 1.1 perry c1 = c;
774 1.1 perry if (C == '.' && c1 == '\n') {
775 1.1 perry if (C != 'P') {
776 1.1 perry if (c == '\n')
777 1.1 perry continue;
778 1.1 perry else {
779 1.1 perry SKIP;
780 1.1 perry c = '\n';
781 1.1 perry continue;
782 1.1 perry }
783 1.1 perry }
784 1.1 perry if (C != 'E') {
785 1.1 perry if (c == '\n')
786 1.1 perry continue;
787 1.1 perry else {
788 1.1 perry SKIP;
789 1.1 perry c = '\n';
790 1.1 perry continue;
791 1.1 perry }
792 1.1 perry }
793 1.1 perry SKIP;
794 1.1 perry return;
795 1.1 perry }
796 1.1 perry else if (c == '\"') {
797 1.1 perry while (C != '\"') {
798 1.1 perry if (c == '\\') {
799 1.1 perry if (C == '\"')
800 1.1 perry continue;
801 1.1 perry ungetc(c, infile);
802 1.1 perry backsl();
803 1.1 perry } else
804 1.1 perry *p1++ = c;
805 1.1 perry }
806 1.1 perry *p1++ = ' ';
807 1.1 perry }
808 1.1 perry else if (c == '\n' && p1 != line) {
809 1.1 perry *p1 = '\0';
810 1.1 perry if (wordflag)
811 1.1 perry msputwords(NO);
812 1.1 perry else {
813 1.1 perry puts(line);
814 1.1 perry putchar('\n');
815 1.1 perry }
816 1.1 perry p1 = line;
817 1.1 perry }
818 1.1 perry }
819 1.1 perry }
820 1.1 perry
821 1.1 perry #ifdef DEBUG
822 1.2 christos static int
823 1.1 perry _C1(void)
824 1.1 perry {
825 1.1 perry
826 1.2 christos return C1get);
827 1.1 perry }
828 1.1 perry
829 1.2 christos static int
830 1.1 perry _C(void)
831 1.1 perry {
832 1.1 perry
833 1.2 christos return Cget);
834 1.1 perry }
835 1.1 perry #endif /* DEBUG */
836 1.1 perry
837 1.1 perry /*
838 1.1 perry * Put out a macro line, using ms and mm conventions.
839 1.1 perry */
840 1.2 christos static void
841 1.1 perry msputmac(char *s, int constant)
842 1.1 perry {
843 1.1 perry char *t;
844 1.1 perry int found;
845 1.1 perry int last;
846 1.1 perry
847 1.1 perry last = 0;
848 1.1 perry found = 0;
849 1.1 perry if (wordflag) {
850 1.1 perry msputwords(YES);
851 1.1 perry return;
852 1.1 perry }
853 1.1 perry while (*s) {
854 1.1 perry while (*s == ' ' || *s == '\t')
855 1.1 perry putchar(*s++);
856 1.1 perry for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t)
857 1.1 perry ; /* nothing */
858 1.1 perry if (*s == '\"')
859 1.1 perry s++;
860 1.1 perry if (t > s + constant && chars[(unsigned char)s[0]] == LETTER &&
861 1.1 perry chars[(unsigned char)s[1]] == LETTER) {
862 1.1 perry while (s < t)
863 1.1 perry if (*s == '\"')
864 1.1 perry s++;
865 1.1 perry else
866 1.1 perry putchar(*s++);
867 1.1 perry last = *(t-1);
868 1.1 perry found++;
869 1.1 perry } else if (found && chars[(unsigned char)s[0]] == PUNCT &&
870 1.1 perry s[1] == '\0') {
871 1.1 perry putchar(*s++);
872 1.1 perry } else {
873 1.1 perry last = *(t - 1);
874 1.1 perry s = t;
875 1.1 perry }
876 1.1 perry }
877 1.1 perry putchar('\n');
878 1.1 perry if (msflag && chars[last] == PUNCT) {
879 1.1 perry putchar(last);
880 1.1 perry putchar('\n');
881 1.1 perry }
882 1.1 perry }
883 1.1 perry
884 1.1 perry /*
885 1.1 perry * put out words (for the -w option) with ms and mm conventions
886 1.1 perry */
887 1.2 christos static void
888 1.1 perry msputwords(int macline)
889 1.1 perry {
890 1.1 perry char *p, *p1;
891 1.1 perry int i, nlet;
892 1.1 perry
893 1.1 perry for (p1 = line;;) {
894 1.1 perry /*
895 1.1 perry * skip initial specials ampersands and apostrophes
896 1.1 perry */
897 1.1 perry while (chars[(unsigned char)*p1] < DIGIT)
898 1.1 perry if (*p1++ == '\0')
899 1.1 perry return;
900 1.1 perry nlet = 0;
901 1.1 perry for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p)
902 1.1 perry if (i == LETTER)
903 1.1 perry ++nlet;
904 1.1 perry
905 1.1 perry if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) {
906 1.1 perry /*
907 1.1 perry * delete trailing ampersands and apostrophes
908 1.1 perry */
909 1.1 perry while ((i = chars[(unsigned char)p[-1]]) == PUNCT ||
910 1.1 perry i == APOS )
911 1.1 perry --p;
912 1.1 perry while (p1 < p)
913 1.1 perry putchar(*p1++);
914 1.1 perry putchar('\n');
915 1.1 perry } else {
916 1.1 perry p1 = p;
917 1.1 perry }
918 1.1 perry }
919 1.1 perry }
920 1.1 perry
921 1.1 perry /*
922 1.1 perry * put out a macro using the me conventions
923 1.1 perry */
924 1.1 perry #define SKIPBLANK(cp) while (*cp == ' ' || *cp == '\t') { cp++; }
925 1.1 perry #define SKIPNONBLANK(cp) while (*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
926 1.1 perry
927 1.2 christos static void
928 1.1 perry meputmac(char *cp, int constant)
929 1.1 perry {
930 1.1 perry char *np;
931 1.1 perry int found;
932 1.1 perry int argno;
933 1.1 perry int last;
934 1.1 perry int inquote;
935 1.1 perry
936 1.1 perry last = 0;
937 1.1 perry found = 0;
938 1.1 perry if (wordflag) {
939 1.1 perry meputwords(YES);
940 1.1 perry return;
941 1.1 perry }
942 1.1 perry for (argno = 0; *cp; argno++) {
943 1.1 perry SKIPBLANK(cp);
944 1.1 perry inquote = (*cp == '"');
945 1.1 perry if (inquote)
946 1.1 perry cp++;
947 1.1 perry for (np = cp; *np; np++) {
948 1.1 perry switch (*np) {
949 1.1 perry case '\n':
950 1.1 perry case '\0':
951 1.1 perry break;
952 1.1 perry
953 1.1 perry case '\t':
954 1.1 perry case ' ':
955 1.1 perry if (inquote)
956 1.1 perry continue;
957 1.1 perry else
958 1.1 perry goto endarg;
959 1.1 perry
960 1.1 perry case '"':
961 1.1 perry if (inquote && np[1] == '"') {
962 1.1 perry memmove(np, np + 1, strlen(np));
963 1.1 perry np++;
964 1.1 perry continue;
965 1.1 perry } else {
966 1.1 perry *np = ' '; /* bye bye " */
967 1.1 perry goto endarg;
968 1.1 perry }
969 1.1 perry
970 1.1 perry default:
971 1.1 perry continue;
972 1.1 perry }
973 1.1 perry }
974 1.1 perry endarg: ;
975 1.1 perry /*
976 1.1 perry * cp points at the first char in the arg
977 1.1 perry * np points one beyond the last char in the arg
978 1.1 perry */
979 1.1 perry if ((argconcat == 0) || (argconcat != argno))
980 1.1 perry putchar(' ');
981 1.1 perry #ifdef FULLDEBUG
982 1.1 perry {
983 1.1 perry char *p;
984 1.1 perry printf("[%d,%d: ", argno, np - cp);
985 1.1 perry for (p = cp; p < np; p++) {
986 1.1 perry putchar(*p);
987 1.1 perry }
988 1.1 perry printf("]");
989 1.1 perry }
990 1.1 perry #endif /* FULLDEBUG */
991 1.1 perry /*
992 1.1 perry * Determine if the argument merits being printed
993 1.1 perry *
994 1.1 perry * constant is the cut off point below which something
995 1.1 perry * is not a word.
996 1.1 perry */
997 1.1 perry if (((np - cp) > constant) &&
998 1.1 perry (inquote || (chars[(unsigned char)cp[0]] == LETTER))) {
999 1.1 perry for (cp = cp; cp < np; cp++)
1000 1.1 perry putchar(*cp);
1001 1.1 perry last = np[-1];
1002 1.1 perry found++;
1003 1.1 perry } else if (found && (np - cp == 1) &&
1004 1.1 perry chars[(unsigned char)*cp] == PUNCT) {
1005 1.1 perry putchar(*cp);
1006 1.1 perry } else {
1007 1.1 perry last = np[-1];
1008 1.1 perry }
1009 1.1 perry cp = np;
1010 1.1 perry }
1011 1.1 perry if (msflag && chars[last] == PUNCT)
1012 1.1 perry putchar(last);
1013 1.1 perry putchar('\n');
1014 1.1 perry }
1015 1.1 perry
1016 1.1 perry /*
1017 1.1 perry * put out words (for the -w option) with ms and mm conventions
1018 1.1 perry */
1019 1.2 christos static void
1020 1.1 perry meputwords(int macline)
1021 1.1 perry {
1022 1.1 perry
1023 1.1 perry msputwords(macline);
1024 1.1 perry }
1025 1.1 perry
1026 1.1 perry /*
1027 1.1 perry *
1028 1.1 perry * Skip over a nested set of macros
1029 1.1 perry *
1030 1.1 perry * Possible arguments to noblock are:
1031 1.1 perry *
1032 1.1 perry * fi end of unfilled text
1033 1.1 perry * PE pic ending
1034 1.1 perry * DE display ending
1035 1.1 perry *
1036 1.1 perry * for ms and mm only:
1037 1.1 perry * KE keep ending
1038 1.1 perry *
1039 1.1 perry * NE undocumented match to NS (for mm?)
1040 1.1 perry * LE mm only: matches RL or *L (for lists)
1041 1.1 perry *
1042 1.1 perry * for me:
1043 1.1 perry * ([lqbzcdf]
1044 1.1 perry */
1045 1.2 christos static void
1046 1.1 perry noblock(char a1, char a2)
1047 1.1 perry {
1048 1.1 perry int c1,c2;
1049 1.1 perry int eqnf;
1050 1.1 perry int lct;
1051 1.1 perry
1052 1.1 perry lct = 0;
1053 1.1 perry eqnf = 1;
1054 1.1 perry SKIP;
1055 1.1 perry for (;;) {
1056 1.1 perry while (C != '.')
1057 1.1 perry if (c == '\n')
1058 1.1 perry continue;
1059 1.1 perry else
1060 1.1 perry SKIP;
1061 1.1 perry if ((c1 = C) == '\n')
1062 1.1 perry continue;
1063 1.1 perry if ((c2 = C) == '\n')
1064 1.1 perry continue;
1065 1.1 perry if (c1 == a1 && c2 == a2) {
1066 1.1 perry SKIP;
1067 1.1 perry if (lct != 0) {
1068 1.1 perry lct--;
1069 1.1 perry continue;
1070 1.1 perry }
1071 1.1 perry if (eqnf)
1072 1.1 perry putchar('.');
1073 1.1 perry putchar('\n');
1074 1.1 perry return;
1075 1.1 perry } else if (a1 == 'L' && c2 == 'L') {
1076 1.1 perry lct++;
1077 1.1 perry SKIP;
1078 1.1 perry }
1079 1.1 perry /*
1080 1.1 perry * equations (EQ) nested within a display
1081 1.1 perry */
1082 1.1 perry else if (c1 == 'E' && c2 == 'Q') {
1083 1.1 perry if ((mac == ME && a1 == ')')
1084 1.1 perry || (mac != ME && a1 == 'D')) {
1085 1.1 perry eqn();
1086 1.1 perry eqnf=0;
1087 1.1 perry }
1088 1.1 perry }
1089 1.1 perry /*
1090 1.1 perry * turning on filling is done by the paragraphing
1091 1.1 perry * macros
1092 1.1 perry */
1093 1.1 perry else if (a1 == 'f') { /* .fi */
1094 1.1 perry if ((mac == ME && (c2 == 'h' || c2 == 'p'))
1095 1.1 perry || (mac != ME && (c1 == 'P' || c2 == 'P'))) {
1096 1.1 perry SKIP;
1097 1.1 perry return;
1098 1.1 perry }
1099 1.1 perry } else {
1100 1.1 perry SKIP;
1101 1.1 perry }
1102 1.1 perry }
1103 1.1 perry }
1104 1.1 perry
1105 1.2 christos static int
1106 1.2 christos /*ARGSUSED*/
1107 1.2 christos EQ(pacmac unused)
1108 1.1 perry {
1109 1.1 perry
1110 1.1 perry eqn();
1111 1.2 christos return 0;
1112 1.1 perry }
1113 1.1 perry
1114 1.2 christos static int
1115 1.2 christos /*ARGSUSED*/
1116 1.2 christos domacro(pacmac unused)
1117 1.1 perry {
1118 1.1 perry
1119 1.1 perry macro();
1120 1.2 christos return 0;
1121 1.1 perry }
1122 1.1 perry
1123 1.2 christos static int
1124 1.2 christos /*ARGSUSED*/
1125 1.2 christos PS(pacmac unused)
1126 1.1 perry {
1127 1.1 perry
1128 1.1 perry for (C; c == ' ' || c == '\t'; C)
1129 1.1 perry ; /* nothing */
1130 1.1 perry
1131 1.1 perry if (c == '<') { /* ".PS < file" -- don't expect a .PE */
1132 1.1 perry SKIP;
1133 1.2 christos return 0;
1134 1.1 perry }
1135 1.1 perry if (!msflag)
1136 1.1 perry inpic();
1137 1.1 perry else
1138 1.1 perry noblock('P', 'E');
1139 1.2 christos return 0;
1140 1.1 perry }
1141 1.1 perry
1142 1.2 christos static int
1143 1.2 christos /*ARGSUSED*/
1144 1.2 christos skip(pacmac unused)
1145 1.1 perry {
1146 1.1 perry
1147 1.1 perry SKIP;
1148 1.2 christos return 0;
1149 1.1 perry }
1150 1.1 perry
1151 1.2 christos static int
1152 1.2 christos /*ARGSUSED*/
1153 1.2 christos intbl(pacmac unused)
1154 1.1 perry {
1155 1.1 perry
1156 1.1 perry if (msflag)
1157 1.1 perry stbl();
1158 1.1 perry else
1159 1.1 perry tbl();
1160 1.2 christos return 0;
1161 1.1 perry }
1162 1.1 perry
1163 1.2 christos static int
1164 1.2 christos /*ARGSUSED*/
1165 1.2 christos outtbl(pacmac unused)
1166 1.1 perry {
1167 1.1 perry
1168 1.1 perry intable = NO;
1169 1.2 christos return 0;
1170 1.1 perry }
1171 1.1 perry
1172 1.1 perry int
1173 1.2 christos /*ARGSUSED*/
1174 1.2 christos so(pacmac unused)
1175 1.1 perry {
1176 1.1 perry
1177 1.1 perry if (!iflag) {
1178 1.1 perry getfname();
1179 1.1 perry if (fname[0]) {
1180 1.1 perry if (++filesp - &files[0] > MAXFILES)
1181 1.1 perry err(1, "too many nested files (max %d)",
1182 1.1 perry MAXFILES);
1183 1.1 perry infile = *filesp = opn(fname);
1184 1.1 perry }
1185 1.1 perry }
1186 1.2 christos return 0;
1187 1.1 perry }
1188 1.1 perry
1189 1.2 christos static int
1190 1.2 christos /*ARGSUSED*/
1191 1.2 christos nx(pacmac unused)
1192 1.1 perry {
1193 1.1 perry
1194 1.1 perry if (!iflag) {
1195 1.1 perry getfname();
1196 1.1 perry if (fname[0] == '\0')
1197 1.1 perry exit(0);
1198 1.1 perry if (infile != stdin)
1199 1.1 perry fclose(infile);
1200 1.1 perry infile = *filesp = opn(fname);
1201 1.1 perry }
1202 1.2 christos return 0;
1203 1.1 perry }
1204 1.1 perry
1205 1.2 christos static int
1206 1.2 christos /*ARGSUSED*/
1207 1.2 christos skiptocom(pacmac unused)
1208 1.1 perry {
1209 1.1 perry
1210 1.1 perry SKIP_TO_COM;
1211 1.2 christos return COMX;
1212 1.1 perry }
1213 1.1 perry
1214 1.2 christos static int
1215 1.1 perry PP(pacmac c12)
1216 1.1 perry {
1217 1.1 perry int c1, c2;
1218 1.1 perry
1219 1.1 perry frommac(c12, c1, c2);
1220 1.1 perry printf(".%c%c", c1, c2);
1221 1.1 perry while (C != '\n')
1222 1.1 perry putchar(c);
1223 1.1 perry putchar('\n');
1224 1.2 christos return 0;
1225 1.1 perry }
1226 1.1 perry
1227 1.2 christos static int
1228 1.2 christos /*ARGSUSED*/
1229 1.2 christos AU(pacmac unused)
1230 1.1 perry {
1231 1.1 perry
1232 1.1 perry if (mac == MM)
1233 1.2 christos return 0;
1234 1.1 perry SKIP_TO_COM;
1235 1.2 christos return COMX;
1236 1.1 perry }
1237 1.1 perry
1238 1.2 christos static int
1239 1.1 perry SH(pacmac c12)
1240 1.1 perry {
1241 1.1 perry int c1, c2;
1242 1.1 perry
1243 1.1 perry frommac(c12, c1, c2);
1244 1.1 perry
1245 1.1 perry if (parag) {
1246 1.1 perry printf(".%c%c", c1, c2);
1247 1.1 perry while (C != '\n')
1248 1.1 perry putchar(c);
1249 1.1 perry putchar(c);
1250 1.1 perry putchar('!');
1251 1.1 perry for (;;) {
1252 1.1 perry while (C != '\n')
1253 1.1 perry putchar(c);
1254 1.1 perry putchar('\n');
1255 1.1 perry if (C == '.')
1256 1.2 christos return COM;
1257 1.1 perry putchar('!');
1258 1.1 perry putchar(c);
1259 1.1 perry }
1260 1.1 perry /*NOTREACHED*/
1261 1.1 perry } else {
1262 1.1 perry SKIP_TO_COM;
1263 1.2 christos return COMX;
1264 1.1 perry }
1265 1.1 perry }
1266 1.1 perry
1267 1.2 christos static int
1268 1.2 christos /*ARGSUSED*/
1269 1.2 christos UX(pacmac unused)
1270 1.1 perry {
1271 1.1 perry
1272 1.1 perry if (wordflag)
1273 1.1 perry printf("UNIX\n");
1274 1.1 perry else
1275 1.1 perry printf("UNIX ");
1276 1.2 christos return 0;
1277 1.1 perry }
1278 1.1 perry
1279 1.2 christos static int
1280 1.1 perry MMHU(pacmac c12)
1281 1.1 perry {
1282 1.1 perry int c1, c2;
1283 1.1 perry
1284 1.1 perry frommac(c12, c1, c2);
1285 1.1 perry if (parag) {
1286 1.1 perry printf(".%c%c", c1, c2);
1287 1.1 perry while (C != '\n')
1288 1.1 perry putchar(c);
1289 1.1 perry putchar('\n');
1290 1.1 perry } else {
1291 1.1 perry SKIP;
1292 1.1 perry }
1293 1.2 christos return 0;
1294 1.1 perry }
1295 1.1 perry
1296 1.2 christos static int
1297 1.1 perry mesnblock(pacmac c12)
1298 1.1 perry {
1299 1.1 perry int c1, c2;
1300 1.1 perry
1301 1.1 perry frommac(c12, c1, c2);
1302 1.1 perry noblock(')', c2);
1303 1.2 christos return 0;
1304 1.1 perry }
1305 1.1 perry
1306 1.2 christos static int
1307 1.1 perry mssnblock(pacmac c12)
1308 1.1 perry {
1309 1.1 perry int c1, c2;
1310 1.1 perry
1311 1.1 perry frommac(c12, c1, c2);
1312 1.1 perry noblock(c1, 'E');
1313 1.2 christos return 0;
1314 1.1 perry }
1315 1.1 perry
1316 1.2 christos static int
1317 1.2 christos /*ARGUSED*/
1318 1.2 christos nf(pacmac unused)
1319 1.1 perry {
1320 1.1 perry
1321 1.1 perry noblock('f', 'i');
1322 1.2 christos return 0;
1323 1.1 perry }
1324 1.1 perry
1325 1.2 christos static int
1326 1.2 christos /*ARGUSED*/
1327 1.2 christos ce(pacmac unused)
1328 1.1 perry {
1329 1.1 perry
1330 1.1 perry sce();
1331 1.2 christos return 0;
1332 1.1 perry }
1333 1.1 perry
1334 1.2 christos static int
1335 1.1 perry meip(pacmac c12)
1336 1.1 perry {
1337 1.1 perry
1338 1.1 perry if (parag)
1339 1.1 perry mepp(c12);
1340 1.1 perry else if (wordflag) /* save the tag */
1341 1.1 perry regline(meputmac, ONE);
1342 1.1 perry else
1343 1.1 perry SKIP;
1344 1.2 christos return 0;
1345 1.1 perry }
1346 1.1 perry
1347 1.1 perry /*
1348 1.1 perry * only called for -me .pp or .sh, when parag is on
1349 1.1 perry */
1350 1.2 christos static int
1351 1.1 perry mepp(pacmac c12)
1352 1.1 perry {
1353 1.1 perry
1354 1.1 perry PP(c12); /* eats the line */
1355 1.2 christos return 0;
1356 1.1 perry }
1357 1.1 perry
1358 1.1 perry /*
1359 1.1 perry * Start of a section heading; output the section name if doing words
1360 1.1 perry */
1361 1.2 christos static int
1362 1.1 perry mesh(pacmac c12)
1363 1.1 perry {
1364 1.1 perry
1365 1.1 perry if (parag)
1366 1.1 perry mepp(c12);
1367 1.1 perry else if (wordflag)
1368 1.1 perry defcomline(c12);
1369 1.1 perry else
1370 1.1 perry SKIP;
1371 1.2 christos return 0;
1372 1.1 perry }
1373 1.1 perry
1374 1.1 perry /*
1375 1.1 perry * process a font setting
1376 1.1 perry */
1377 1.2 christos static int
1378 1.1 perry mefont(pacmac c12)
1379 1.1 perry {
1380 1.1 perry
1381 1.1 perry argconcat = 1;
1382 1.1 perry defcomline(c12);
1383 1.1 perry argconcat = 0;
1384 1.2 christos return 0;
1385 1.1 perry }
1386 1.1 perry
1387 1.2 christos static int
1388 1.1 perry manfont(pacmac c12)
1389 1.1 perry {
1390 1.1 perry
1391 1.2 christos return mefont(c12);
1392 1.1 perry }
1393 1.1 perry
1394 1.2 christos static int
1395 1.1 perry manpp(pacmac c12)
1396 1.1 perry {
1397 1.1 perry
1398 1.2 christos return mepp(c12);
1399 1.1 perry }
1400 1.1 perry
1401 1.2 christos static void
1402 1.1 perry defcomline(pacmac c12)
1403 1.1 perry {
1404 1.1 perry int c1, c2;
1405 1.1 perry
1406 1.1 perry frommac(c12, c1, c2);
1407 1.1 perry if (msflag && mac == MM && c2 == 'L') {
1408 1.1 perry if (disp || c1 == 'R') {
1409 1.1 perry noblock('L', 'E');
1410 1.1 perry } else {
1411 1.1 perry SKIP;
1412 1.1 perry putchar('.');
1413 1.1 perry }
1414 1.1 perry }
1415 1.1 perry else if (c1 == '.' && c2 == '.') {
1416 1.1 perry if (msflag) {
1417 1.1 perry SKIP;
1418 1.1 perry return;
1419 1.1 perry }
1420 1.1 perry while (C == '.')
1421 1.1 perry /*VOID*/;
1422 1.1 perry }
1423 1.1 perry ++inmacro;
1424 1.1 perry /*
1425 1.1 perry * Process the arguments to the macro
1426 1.1 perry */
1427 1.1 perry switch (mac) {
1428 1.1 perry default:
1429 1.1 perry case MM:
1430 1.1 perry case MS:
1431 1.1 perry if (c1 <= 'Z' && msflag)
1432 1.1 perry regline(msputmac, ONE);
1433 1.1 perry else
1434 1.1 perry regline(msputmac, TWO);
1435 1.1 perry break;
1436 1.1 perry case ME:
1437 1.1 perry regline(meputmac, ONE);
1438 1.1 perry break;
1439 1.1 perry }
1440 1.1 perry --inmacro;
1441 1.1 perry }
1442 1.1 perry
1443 1.2 christos static void
1444 1.1 perry comline(void)
1445 1.1 perry {
1446 1.1 perry int c1;
1447 1.1 perry int c2;
1448 1.1 perry pacmac c12;
1449 1.1 perry int mid;
1450 1.1 perry int lb, ub;
1451 1.1 perry int hit;
1452 1.1 perry static int tabsize = 0;
1453 1.2 christos static const struct mactab *mactab = NULL;
1454 1.2 christos const struct mactab *mp;
1455 1.1 perry
1456 1.1 perry if (mactab == 0)
1457 1.1 perry buildtab(&mactab, &tabsize);
1458 1.1 perry com:
1459 1.1 perry while (C == ' ' || c == '\t')
1460 1.1 perry ;
1461 1.1 perry comx:
1462 1.1 perry if ((c1 = c) == '\n')
1463 1.1 perry return;
1464 1.1 perry c2 = C;
1465 1.1 perry if (c1 == '.' && c2 != '.')
1466 1.1 perry inmacro = NO;
1467 1.1 perry if (msflag && c1 == '[') {
1468 1.1 perry refer(c2);
1469 1.1 perry return;
1470 1.1 perry }
1471 1.1 perry if (parag && mac==MM && c1 == 'P' && c2 == '\n') {
1472 1.1 perry printf(".P\n");
1473 1.1 perry return;
1474 1.1 perry }
1475 1.1 perry if (c2 == '\n')
1476 1.1 perry return;
1477 1.1 perry /*
1478 1.1 perry * Single letter macro
1479 1.1 perry */
1480 1.1 perry if (mac == ME && (c2 == ' ' || c2 == '\t') )
1481 1.1 perry c2 = ' ';
1482 1.1 perry c12 = tomac(c1, c2);
1483 1.1 perry /*
1484 1.1 perry * binary search through the table of macros
1485 1.1 perry */
1486 1.1 perry lb = 0;
1487 1.1 perry ub = tabsize - 1;
1488 1.1 perry while (lb <= ub) {
1489 1.1 perry mid = (ub + lb) / 2;
1490 1.1 perry mp = &mactab[mid];
1491 1.1 perry if (mp->macname < c12)
1492 1.1 perry lb = mid + 1;
1493 1.1 perry else if (mp->macname > c12)
1494 1.1 perry ub = mid - 1;
1495 1.1 perry else {
1496 1.1 perry hit = 1;
1497 1.1 perry #ifdef FULLDEBUG
1498 1.1 perry printf("preliminary hit macro %c%c ", c1, c2);
1499 1.1 perry #endif /* FULLDEBUG */
1500 1.1 perry switch (mp->condition) {
1501 1.1 perry case NONE:
1502 1.1 perry hit = YES;
1503 1.1 perry break;
1504 1.1 perry case FNEST:
1505 1.1 perry hit = (filesp == files);
1506 1.1 perry break;
1507 1.1 perry case NOMAC:
1508 1.1 perry hit = !inmacro;
1509 1.1 perry break;
1510 1.1 perry case MAC:
1511 1.1 perry hit = inmacro;
1512 1.1 perry break;
1513 1.1 perry case PARAG:
1514 1.1 perry hit = parag;
1515 1.1 perry break;
1516 1.1 perry case NBLK:
1517 1.1 perry hit = !keepblock;
1518 1.1 perry break;
1519 1.1 perry default:
1520 1.1 perry hit = 0;
1521 1.1 perry }
1522 1.1 perry
1523 1.1 perry if (hit) {
1524 1.1 perry #ifdef FULLDEBUG
1525 1.1 perry printf("MATCH\n");
1526 1.1 perry #endif /* FULLDEBUG */
1527 1.1 perry switch ((*(mp->func))(c12)) {
1528 1.1 perry default:
1529 1.1 perry return;
1530 1.1 perry case COMX:
1531 1.1 perry goto comx;
1532 1.1 perry case COM:
1533 1.1 perry goto com;
1534 1.1 perry }
1535 1.1 perry }
1536 1.1 perry #ifdef FULLDEBUG
1537 1.1 perry printf("FAIL\n");
1538 1.1 perry #endif /* FULLDEBUG */
1539 1.1 perry break;
1540 1.1 perry }
1541 1.1 perry }
1542 1.1 perry defcomline(c12);
1543 1.1 perry }
1544 1.1 perry
1545 1.2 christos static int
1546 1.1 perry macsort(const void *p1, const void *p2)
1547 1.1 perry {
1548 1.2 christos const struct mactab *t1 = p1;
1549 1.2 christos const struct mactab *t2 = p2;
1550 1.1 perry
1551 1.2 christos return t1->macname - t2->macname;
1552 1.1 perry }
1553 1.1 perry
1554 1.2 christos static int
1555 1.2 christos sizetab(const struct mactab *mp)
1556 1.1 perry {
1557 1.1 perry int i;
1558 1.1 perry
1559 1.1 perry i = 0;
1560 1.1 perry if (mp) {
1561 1.1 perry for (; mp->macname; mp++, i++)
1562 1.1 perry /*VOID*/ ;
1563 1.1 perry }
1564 1.2 christos return i;
1565 1.1 perry }
1566 1.1 perry
1567 1.2 christos static struct mactab *
1568 1.2 christos macfill(struct mactab *dst, const struct mactab *src)
1569 1.1 perry {
1570 1.1 perry
1571 1.1 perry if (src) {
1572 1.1 perry while (src->macname)
1573 1.1 perry *dst++ = *src++;
1574 1.1 perry }
1575 1.2 christos return dst;
1576 1.1 perry }
1577 1.1 perry
1578 1.2 christos static void
1579 1.1 perry usage(void)
1580 1.1 perry {
1581 1.1 perry extern char *__progname;
1582 1.1 perry
1583 1.3 wiz fprintf(stderr, "usage: %s [-ikpw ] [ -m a | e | l | m | s] [file ...]\n", __progname);
1584 1.1 perry exit(1);
1585 1.1 perry }
1586 1.1 perry
1587 1.2 christos static void
1588 1.2 christos buildtab(const struct mactab **r_back, int *r_size)
1589 1.1 perry {
1590 1.2 christos size_t size;
1591 1.2 christos const struct mactab *p1, *p2;
1592 1.2 christos struct mactab *back, *p;
1593 1.1 perry
1594 1.1 perry size = sizetab(troffmactab) + sizetab(ppmactab);
1595 1.1 perry p1 = p2 = NULL;
1596 1.1 perry if (msflag) {
1597 1.1 perry switch (mac) {
1598 1.1 perry case ME:
1599 1.1 perry p1 = memactab;
1600 1.1 perry break;
1601 1.1 perry case MM:
1602 1.1 perry p1 = msmactab;
1603 1.1 perry p2 = mmmactab;
1604 1.1 perry break;
1605 1.1 perry case MS:
1606 1.1 perry p1 = msmactab;
1607 1.1 perry break;
1608 1.1 perry case MA:
1609 1.1 perry p1 = manmactab;
1610 1.1 perry break;
1611 1.1 perry default:
1612 1.1 perry break;
1613 1.1 perry }
1614 1.1 perry }
1615 1.1 perry size += sizetab(p1);
1616 1.1 perry size += sizetab(p2);
1617 1.2 christos back = calloc(size + 2, sizeof(struct mactab));
1618 1.1 perry if (back == NULL)
1619 1.1 perry err(1, NULL);
1620 1.1 perry
1621 1.1 perry p = macfill(back, troffmactab);
1622 1.1 perry p = macfill(p, ppmactab);
1623 1.1 perry p = macfill(p, p1);
1624 1.1 perry p = macfill(p, p2);
1625 1.1 perry
1626 1.1 perry qsort(back, size, sizeof(struct mactab), macsort);
1627 1.1 perry *r_size = size;
1628 1.1 perry *r_back = back;
1629 1.1 perry }
1630 1.1 perry
1631 1.1 perry /*
1632 1.1 perry * troff commands
1633 1.1 perry */
1634 1.2 christos static const struct mactab troffmactab[] = {
1635 1.1 perry M(NONE, '\\','"', skip), /* comment */
1636 1.1 perry M(NOMAC, 'd','e', domacro), /* define */
1637 1.1 perry M(NOMAC, 'i','g', domacro), /* ignore till .. */
1638 1.1 perry M(NOMAC, 'a','m', domacro), /* append macro */
1639 1.1 perry M(NBLK, 'n','f', nf), /* filled */
1640 1.1 perry M(NBLK, 'c','e', ce), /* centered */
1641 1.1 perry
1642 1.1 perry M(NONE, 's','o', so), /* source a file */
1643 1.1 perry M(NONE, 'n','x', nx), /* go to next file */
1644 1.1 perry
1645 1.1 perry M(NONE, 't','m', skip), /* print string on tty */
1646 1.1 perry M(NONE, 'h','w', skip), /* exception hyphen words */
1647 1.1 perry M(NONE, 0,0, 0)
1648 1.1 perry };
1649 1.1 perry
1650 1.1 perry /*
1651 1.1 perry * Preprocessor output
1652 1.1 perry */
1653 1.2 christos static const struct mactab ppmactab[] = {
1654 1.1 perry M(FNEST, 'E','Q', EQ), /* equation starting */
1655 1.1 perry M(FNEST, 'T','S', intbl), /* table starting */
1656 1.1 perry M(FNEST, 'T','C', intbl), /* alternative table? */
1657 1.1 perry M(FNEST, 'T','&', intbl), /* table reformatting */
1658 1.1 perry M(NONE, 'T','E', outtbl),/* table ending */
1659 1.1 perry M(NONE, 'P','S', PS), /* picture starting */
1660 1.1 perry M(NONE, 0,0, 0)
1661 1.1 perry };
1662 1.1 perry
1663 1.1 perry /*
1664 1.1 perry * Particular to ms and mm
1665 1.1 perry */
1666 1.2 christos static const struct mactab msmactab[] = {
1667 1.1 perry M(NONE, 'T','L', skiptocom), /* title follows */
1668 1.1 perry M(NONE, 'F','S', skiptocom), /* start footnote */
1669 1.1 perry M(NONE, 'O','K', skiptocom), /* Other kws */
1670 1.1 perry
1671 1.1 perry M(NONE, 'N','R', skip), /* undocumented */
1672 1.1 perry M(NONE, 'N','D', skip), /* use supplied date */
1673 1.1 perry
1674 1.1 perry M(PARAG, 'P','P', PP), /* begin parag */
1675 1.1 perry M(PARAG, 'I','P', PP), /* begin indent parag, tag x */
1676 1.1 perry M(PARAG, 'L','P', PP), /* left blocked parag */
1677 1.1 perry
1678 1.1 perry M(NONE, 'A','U', AU), /* author */
1679 1.1 perry M(NONE, 'A','I', AU), /* authors institution */
1680 1.1 perry
1681 1.1 perry M(NONE, 'S','H', SH), /* section heading */
1682 1.1 perry M(NONE, 'S','N', SH), /* undocumented */
1683 1.1 perry M(NONE, 'U','X', UX), /* unix */
1684 1.1 perry
1685 1.1 perry M(NBLK, 'D','S', mssnblock), /* start display text */
1686 1.1 perry M(NBLK, 'K','S', mssnblock), /* start keep */
1687 1.1 perry M(NBLK, 'K','F', mssnblock), /* start float keep */
1688 1.1 perry M(NONE, 0,0, 0)
1689 1.1 perry };
1690 1.1 perry
1691 1.2 christos static const struct mactab mmmactab[] = {
1692 1.1 perry M(NONE, 'H',' ', MMHU), /* -mm ? */
1693 1.1 perry M(NONE, 'H','U', MMHU), /* -mm ? */
1694 1.1 perry M(PARAG, 'P',' ', PP), /* paragraph for -mm */
1695 1.1 perry M(NBLK, 'N','S', mssnblock), /* undocumented */
1696 1.1 perry M(NONE, 0,0, 0)
1697 1.1 perry };
1698 1.1 perry
1699 1.2 christos static const struct mactab memactab[] = {
1700 1.1 perry M(PARAG, 'p','p', mepp),
1701 1.1 perry M(PARAG, 'l','p', mepp),
1702 1.1 perry M(PARAG, 'n','p', mepp),
1703 1.1 perry M(NONE, 'i','p', meip),
1704 1.1 perry
1705 1.1 perry M(NONE, 's','h', mesh),
1706 1.1 perry M(NONE, 'u','h', mesh),
1707 1.1 perry
1708 1.1 perry M(NBLK, '(','l', mesnblock),
1709 1.1 perry M(NBLK, '(','q', mesnblock),
1710 1.1 perry M(NBLK, '(','b', mesnblock),
1711 1.1 perry M(NBLK, '(','z', mesnblock),
1712 1.1 perry M(NBLK, '(','c', mesnblock),
1713 1.1 perry
1714 1.1 perry M(NBLK, '(','d', mesnblock),
1715 1.1 perry M(NBLK, '(','f', mesnblock),
1716 1.1 perry M(NBLK, '(','x', mesnblock),
1717 1.1 perry
1718 1.1 perry M(NONE, 'r',' ', mefont),
1719 1.1 perry M(NONE, 'i',' ', mefont),
1720 1.1 perry M(NONE, 'b',' ', mefont),
1721 1.1 perry M(NONE, 'u',' ', mefont),
1722 1.1 perry M(NONE, 'q',' ', mefont),
1723 1.1 perry M(NONE, 'r','b', mefont),
1724 1.1 perry M(NONE, 'b','i', mefont),
1725 1.1 perry M(NONE, 'b','x', mefont),
1726 1.1 perry M(NONE, 0,0, 0)
1727 1.1 perry };
1728 1.1 perry
1729 1.2 christos static const struct mactab manmactab[] = {
1730 1.1 perry M(PARAG, 'B','I', manfont),
1731 1.1 perry M(PARAG, 'B','R', manfont),
1732 1.1 perry M(PARAG, 'I','B', manfont),
1733 1.1 perry M(PARAG, 'I','R', manfont),
1734 1.1 perry M(PARAG, 'R','B', manfont),
1735 1.1 perry M(PARAG, 'R','I', manfont),
1736 1.1 perry
1737 1.1 perry M(PARAG, 'P','P', manpp),
1738 1.1 perry M(PARAG, 'L','P', manpp),
1739 1.1 perry M(PARAG, 'H','P', manpp),
1740 1.1 perry M(NONE, 0,0, 0)
1741 1.1 perry };
1742