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