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