deroff.c revision 1.11 1 1.11 christos /* $NetBSD: deroff.c,v 1.11 2013/10/18 20:47:06 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.10 joerg #include <sys/cdefs.h>
68 1.11 christos __RCSID("$NetBSD: deroff.c,v 1.11 2013/10/18 20:47:06 christos 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.1 perry case '(':
639 1.1 perry if (msflag) {
640 1.1 perry if (C == 'e') {
641 1.1 perry if (C == 'm') {
642 1.1 perry *lp = '-';
643 1.1 perry return;
644 1.1 perry }
645 1.1 perry }
646 1.1 perry else if (c != '\n')
647 1.1 perry C;
648 1.1 perry return;
649 1.1 perry }
650 1.1 perry if (C != '\n')
651 1.1 perry C;
652 1.1 perry return;
653 1.1 perry
654 1.1 perry case '$':
655 1.1 perry C; /* discard argument number */
656 1.1 perry return;
657 1.1 perry
658 1.1 perry case 'b':
659 1.1 perry case 'x':
660 1.1 perry case 'v':
661 1.1 perry case 'h':
662 1.1 perry case 'w':
663 1.1 perry case 'o':
664 1.1 perry case 'l':
665 1.1 perry case 'L':
666 1.1 perry if ((bdelim = C) == '\n')
667 1.1 perry return;
668 1.1 perry while (C != '\n' && c != bdelim)
669 1.1 perry if (c == '\\')
670 1.1 perry backsl();
671 1.1 perry return;
672 1.1 perry
673 1.1 perry case '\\':
674 1.1 perry if (inmacro)
675 1.1 perry goto sw;
676 1.1 perry
677 1.1 perry default:
678 1.1 perry return;
679 1.1 perry }
680 1.1 perry }
681 1.1 perry
682 1.2 christos static void
683 1.1 perry sce(void)
684 1.1 perry {
685 1.1 perry char *ap;
686 1.1 perry int n, i;
687 1.1 perry char a[10];
688 1.1 perry
689 1.1 perry for (ap = a; C != '\n'; ap++) {
690 1.1 perry *ap = c;
691 1.1 perry if (ap == &a[9]) {
692 1.1 perry SKIP;
693 1.1 perry ap = a;
694 1.1 perry break;
695 1.1 perry }
696 1.1 perry }
697 1.1 perry if (ap != a)
698 1.1 perry n = atoi(a);
699 1.1 perry else
700 1.1 perry n = 1;
701 1.1 perry for (i = 0; i < n;) {
702 1.1 perry if (C == '.') {
703 1.1 perry if (C == 'c') {
704 1.1 perry if (C == 'e') {
705 1.1 perry while (C == ' ')
706 1.1 perry ; /* nothing */
707 1.1 perry if (c == '0') {
708 1.1 perry SKIP;
709 1.1 perry break;
710 1.1 perry } else
711 1.1 perry SKIP;
712 1.1 perry }
713 1.1 perry else
714 1.1 perry SKIP;
715 1.1 perry } else if (c == 'P' || C == 'P') {
716 1.1 perry if (c != '\n')
717 1.1 perry SKIP;
718 1.1 perry break;
719 1.1 perry } else if (c != '\n')
720 1.1 perry SKIP;
721 1.1 perry } else {
722 1.1 perry SKIP;
723 1.1 perry i++;
724 1.1 perry }
725 1.1 perry }
726 1.1 perry }
727 1.1 perry
728 1.2 christos static void
729 1.1 perry refer(int c1)
730 1.1 perry {
731 1.1 perry int c2;
732 1.1 perry
733 1.1 perry if (c1 != '\n')
734 1.1 perry SKIP;
735 1.1 perry
736 1.1 perry for (c2 = -1;;) {
737 1.1 perry if (C != '.')
738 1.1 perry SKIP;
739 1.1 perry else {
740 1.1 perry if (C != ']')
741 1.1 perry SKIP;
742 1.1 perry else {
743 1.1 perry while (C != '\n')
744 1.1 perry c2 = c;
745 1.1 perry if (c2 != -1 && chars[c2] == PUNCT)
746 1.1 perry putchar(c2);
747 1.1 perry return;
748 1.1 perry }
749 1.1 perry }
750 1.1 perry }
751 1.1 perry }
752 1.1 perry
753 1.2 christos static void
754 1.1 perry inpic(void)
755 1.1 perry {
756 1.1 perry int c1;
757 1.1 perry char *p1;
758 1.1 perry
759 1.1 perry SKIP;
760 1.1 perry p1 = line;
761 1.1 perry c = '\n';
762 1.1 perry for (;;) {
763 1.1 perry c1 = c;
764 1.1 perry if (C == '.' && c1 == '\n') {
765 1.1 perry if (C != 'P') {
766 1.1 perry if (c == '\n')
767 1.1 perry continue;
768 1.1 perry else {
769 1.1 perry SKIP;
770 1.1 perry c = '\n';
771 1.1 perry continue;
772 1.1 perry }
773 1.1 perry }
774 1.1 perry if (C != 'E') {
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 SKIP;
784 1.1 perry return;
785 1.1 perry }
786 1.1 perry else if (c == '\"') {
787 1.1 perry while (C != '\"') {
788 1.1 perry if (c == '\\') {
789 1.1 perry if (C == '\"')
790 1.1 perry continue;
791 1.1 perry ungetc(c, infile);
792 1.1 perry backsl();
793 1.1 perry } else
794 1.1 perry *p1++ = c;
795 1.1 perry }
796 1.1 perry *p1++ = ' ';
797 1.1 perry }
798 1.1 perry else if (c == '\n' && p1 != line) {
799 1.1 perry *p1 = '\0';
800 1.1 perry if (wordflag)
801 1.1 perry msputwords(NO);
802 1.1 perry else {
803 1.1 perry puts(line);
804 1.1 perry putchar('\n');
805 1.1 perry }
806 1.1 perry p1 = line;
807 1.1 perry }
808 1.1 perry }
809 1.1 perry }
810 1.1 perry
811 1.1 perry #ifdef DEBUG
812 1.2 christos static int
813 1.1 perry _C1(void)
814 1.1 perry {
815 1.1 perry
816 1.7 wiz return C1get;
817 1.1 perry }
818 1.1 perry
819 1.2 christos static int
820 1.1 perry _C(void)
821 1.1 perry {
822 1.1 perry
823 1.7 wiz return Cget;
824 1.1 perry }
825 1.1 perry #endif /* DEBUG */
826 1.1 perry
827 1.1 perry /*
828 1.1 perry * Put out a macro line, using ms and mm conventions.
829 1.1 perry */
830 1.2 christos static void
831 1.1 perry msputmac(char *s, int constant)
832 1.1 perry {
833 1.1 perry char *t;
834 1.1 perry int found;
835 1.1 perry int last;
836 1.1 perry
837 1.1 perry last = 0;
838 1.1 perry found = 0;
839 1.1 perry if (wordflag) {
840 1.1 perry msputwords(YES);
841 1.1 perry return;
842 1.1 perry }
843 1.1 perry while (*s) {
844 1.1 perry while (*s == ' ' || *s == '\t')
845 1.1 perry putchar(*s++);
846 1.1 perry for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t)
847 1.1 perry ; /* nothing */
848 1.1 perry if (*s == '\"')
849 1.1 perry s++;
850 1.1 perry if (t > s + constant && chars[(unsigned char)s[0]] == LETTER &&
851 1.1 perry chars[(unsigned char)s[1]] == LETTER) {
852 1.1 perry while (s < t)
853 1.1 perry if (*s == '\"')
854 1.1 perry s++;
855 1.1 perry else
856 1.1 perry putchar(*s++);
857 1.1 perry last = *(t-1);
858 1.1 perry found++;
859 1.1 perry } else if (found && chars[(unsigned char)s[0]] == PUNCT &&
860 1.1 perry s[1] == '\0') {
861 1.1 perry putchar(*s++);
862 1.1 perry } else {
863 1.1 perry last = *(t - 1);
864 1.1 perry s = t;
865 1.1 perry }
866 1.1 perry }
867 1.1 perry putchar('\n');
868 1.1 perry if (msflag && chars[last] == PUNCT) {
869 1.1 perry putchar(last);
870 1.1 perry putchar('\n');
871 1.1 perry }
872 1.1 perry }
873 1.1 perry
874 1.1 perry /*
875 1.1 perry * put out words (for the -w option) with ms and mm conventions
876 1.1 perry */
877 1.2 christos static void
878 1.1 perry msputwords(int macline)
879 1.1 perry {
880 1.1 perry char *p, *p1;
881 1.1 perry int i, nlet;
882 1.1 perry
883 1.1 perry for (p1 = line;;) {
884 1.1 perry /*
885 1.1 perry * skip initial specials ampersands and apostrophes
886 1.1 perry */
887 1.1 perry while (chars[(unsigned char)*p1] < DIGIT)
888 1.1 perry if (*p1++ == '\0')
889 1.1 perry return;
890 1.1 perry nlet = 0;
891 1.1 perry for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p)
892 1.1 perry if (i == LETTER)
893 1.1 perry ++nlet;
894 1.1 perry
895 1.1 perry if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) {
896 1.1 perry /*
897 1.1 perry * delete trailing ampersands and apostrophes
898 1.1 perry */
899 1.1 perry while ((i = chars[(unsigned char)p[-1]]) == PUNCT ||
900 1.1 perry i == APOS )
901 1.1 perry --p;
902 1.1 perry while (p1 < p)
903 1.1 perry putchar(*p1++);
904 1.1 perry putchar('\n');
905 1.1 perry } else {
906 1.1 perry p1 = p;
907 1.1 perry }
908 1.1 perry }
909 1.1 perry }
910 1.1 perry
911 1.1 perry /*
912 1.1 perry * put out a macro using the me conventions
913 1.1 perry */
914 1.1 perry #define SKIPBLANK(cp) while (*cp == ' ' || *cp == '\t') { cp++; }
915 1.1 perry #define SKIPNONBLANK(cp) while (*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
916 1.1 perry
917 1.2 christos static void
918 1.1 perry meputmac(char *cp, int constant)
919 1.1 perry {
920 1.1 perry char *np;
921 1.1 perry int found;
922 1.1 perry int argno;
923 1.1 perry int last;
924 1.1 perry int inquote;
925 1.1 perry
926 1.1 perry last = 0;
927 1.1 perry found = 0;
928 1.1 perry if (wordflag) {
929 1.1 perry meputwords(YES);
930 1.1 perry return;
931 1.1 perry }
932 1.1 perry for (argno = 0; *cp; argno++) {
933 1.1 perry SKIPBLANK(cp);
934 1.1 perry inquote = (*cp == '"');
935 1.1 perry if (inquote)
936 1.1 perry cp++;
937 1.1 perry for (np = cp; *np; np++) {
938 1.1 perry switch (*np) {
939 1.1 perry case '\n':
940 1.1 perry case '\0':
941 1.1 perry break;
942 1.1 perry
943 1.1 perry case '\t':
944 1.1 perry case ' ':
945 1.1 perry if (inquote)
946 1.1 perry continue;
947 1.1 perry else
948 1.1 perry goto endarg;
949 1.1 perry
950 1.1 perry case '"':
951 1.1 perry if (inquote && np[1] == '"') {
952 1.1 perry memmove(np, np + 1, strlen(np));
953 1.1 perry np++;
954 1.1 perry continue;
955 1.1 perry } else {
956 1.1 perry *np = ' '; /* bye bye " */
957 1.1 perry goto endarg;
958 1.1 perry }
959 1.1 perry
960 1.1 perry default:
961 1.1 perry continue;
962 1.1 perry }
963 1.1 perry }
964 1.1 perry endarg: ;
965 1.1 perry /*
966 1.1 perry * cp points at the first char in the arg
967 1.1 perry * np points one beyond the last char in the arg
968 1.1 perry */
969 1.1 perry if ((argconcat == 0) || (argconcat != argno))
970 1.1 perry putchar(' ');
971 1.1 perry #ifdef FULLDEBUG
972 1.1 perry {
973 1.1 perry char *p;
974 1.1 perry printf("[%d,%d: ", argno, np - cp);
975 1.1 perry for (p = cp; p < np; p++) {
976 1.1 perry putchar(*p);
977 1.1 perry }
978 1.1 perry printf("]");
979 1.1 perry }
980 1.1 perry #endif /* FULLDEBUG */
981 1.1 perry /*
982 1.1 perry * Determine if the argument merits being printed
983 1.1 perry *
984 1.1 perry * constant is the cut off point below which something
985 1.1 perry * is not a word.
986 1.1 perry */
987 1.1 perry if (((np - cp) > constant) &&
988 1.1 perry (inquote || (chars[(unsigned char)cp[0]] == LETTER))) {
989 1.8 joerg for (; cp < np; cp++)
990 1.1 perry putchar(*cp);
991 1.1 perry last = np[-1];
992 1.1 perry found++;
993 1.1 perry } else if (found && (np - cp == 1) &&
994 1.1 perry chars[(unsigned char)*cp] == PUNCT) {
995 1.1 perry putchar(*cp);
996 1.1 perry } else {
997 1.1 perry last = np[-1];
998 1.1 perry }
999 1.1 perry cp = np;
1000 1.1 perry }
1001 1.1 perry if (msflag && chars[last] == PUNCT)
1002 1.1 perry putchar(last);
1003 1.1 perry putchar('\n');
1004 1.1 perry }
1005 1.1 perry
1006 1.1 perry /*
1007 1.1 perry * put out words (for the -w option) with ms and mm conventions
1008 1.1 perry */
1009 1.2 christos static void
1010 1.1 perry meputwords(int macline)
1011 1.1 perry {
1012 1.1 perry
1013 1.1 perry msputwords(macline);
1014 1.1 perry }
1015 1.1 perry
1016 1.1 perry /*
1017 1.1 perry *
1018 1.1 perry * Skip over a nested set of macros
1019 1.1 perry *
1020 1.1 perry * Possible arguments to noblock are:
1021 1.1 perry *
1022 1.1 perry * fi end of unfilled text
1023 1.1 perry * PE pic ending
1024 1.1 perry * DE display ending
1025 1.1 perry *
1026 1.1 perry * for ms and mm only:
1027 1.1 perry * KE keep ending
1028 1.1 perry *
1029 1.1 perry * NE undocumented match to NS (for mm?)
1030 1.1 perry * LE mm only: matches RL or *L (for lists)
1031 1.1 perry *
1032 1.1 perry * for me:
1033 1.1 perry * ([lqbzcdf]
1034 1.1 perry */
1035 1.2 christos static void
1036 1.1 perry noblock(char a1, char a2)
1037 1.1 perry {
1038 1.1 perry int c1,c2;
1039 1.1 perry int eqnf;
1040 1.1 perry int lct;
1041 1.1 perry
1042 1.1 perry lct = 0;
1043 1.1 perry eqnf = 1;
1044 1.1 perry SKIP;
1045 1.1 perry for (;;) {
1046 1.1 perry while (C != '.')
1047 1.1 perry if (c == '\n')
1048 1.1 perry continue;
1049 1.1 perry else
1050 1.1 perry SKIP;
1051 1.1 perry if ((c1 = C) == '\n')
1052 1.1 perry continue;
1053 1.1 perry if ((c2 = C) == '\n')
1054 1.1 perry continue;
1055 1.1 perry if (c1 == a1 && c2 == a2) {
1056 1.1 perry SKIP;
1057 1.1 perry if (lct != 0) {
1058 1.1 perry lct--;
1059 1.1 perry continue;
1060 1.1 perry }
1061 1.1 perry if (eqnf)
1062 1.1 perry putchar('.');
1063 1.1 perry putchar('\n');
1064 1.1 perry return;
1065 1.1 perry } else if (a1 == 'L' && c2 == 'L') {
1066 1.1 perry lct++;
1067 1.1 perry SKIP;
1068 1.1 perry }
1069 1.1 perry /*
1070 1.1 perry * equations (EQ) nested within a display
1071 1.1 perry */
1072 1.1 perry else if (c1 == 'E' && c2 == 'Q') {
1073 1.1 perry if ((mac == ME && a1 == ')')
1074 1.1 perry || (mac != ME && a1 == 'D')) {
1075 1.1 perry eqn();
1076 1.1 perry eqnf=0;
1077 1.1 perry }
1078 1.1 perry }
1079 1.1 perry /*
1080 1.1 perry * turning on filling is done by the paragraphing
1081 1.1 perry * macros
1082 1.1 perry */
1083 1.1 perry else if (a1 == 'f') { /* .fi */
1084 1.1 perry if ((mac == ME && (c2 == 'h' || c2 == 'p'))
1085 1.1 perry || (mac != ME && (c1 == 'P' || c2 == 'P'))) {
1086 1.1 perry SKIP;
1087 1.1 perry return;
1088 1.1 perry }
1089 1.1 perry } else {
1090 1.1 perry SKIP;
1091 1.1 perry }
1092 1.1 perry }
1093 1.1 perry }
1094 1.1 perry
1095 1.2 christos static int
1096 1.2 christos /*ARGSUSED*/
1097 1.2 christos EQ(pacmac unused)
1098 1.1 perry {
1099 1.1 perry
1100 1.1 perry eqn();
1101 1.2 christos return 0;
1102 1.1 perry }
1103 1.1 perry
1104 1.2 christos static int
1105 1.2 christos /*ARGSUSED*/
1106 1.2 christos domacro(pacmac unused)
1107 1.1 perry {
1108 1.1 perry
1109 1.1 perry macro();
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 PS(pacmac unused)
1116 1.1 perry {
1117 1.1 perry
1118 1.1 perry for (C; c == ' ' || c == '\t'; C)
1119 1.1 perry ; /* nothing */
1120 1.1 perry
1121 1.1 perry if (c == '<') { /* ".PS < file" -- don't expect a .PE */
1122 1.1 perry SKIP;
1123 1.2 christos return 0;
1124 1.1 perry }
1125 1.1 perry if (!msflag)
1126 1.1 perry inpic();
1127 1.1 perry else
1128 1.1 perry noblock('P', 'E');
1129 1.2 christos return 0;
1130 1.1 perry }
1131 1.1 perry
1132 1.2 christos static int
1133 1.2 christos /*ARGSUSED*/
1134 1.2 christos skip(pacmac unused)
1135 1.1 perry {
1136 1.1 perry
1137 1.1 perry SKIP;
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 intbl(pacmac unused)
1144 1.1 perry {
1145 1.1 perry
1146 1.1 perry if (msflag)
1147 1.1 perry stbl();
1148 1.1 perry else
1149 1.1 perry tbl();
1150 1.2 christos return 0;
1151 1.1 perry }
1152 1.1 perry
1153 1.2 christos static int
1154 1.2 christos /*ARGSUSED*/
1155 1.2 christos outtbl(pacmac unused)
1156 1.1 perry {
1157 1.1 perry
1158 1.1 perry intable = NO;
1159 1.2 christos return 0;
1160 1.1 perry }
1161 1.1 perry
1162 1.9 joerg static int
1163 1.2 christos /*ARGSUSED*/
1164 1.2 christos so(pacmac unused)
1165 1.1 perry {
1166 1.1 perry
1167 1.1 perry if (!iflag) {
1168 1.1 perry getfname();
1169 1.1 perry if (fname[0]) {
1170 1.1 perry if (++filesp - &files[0] > MAXFILES)
1171 1.1 perry err(1, "too many nested files (max %d)",
1172 1.1 perry MAXFILES);
1173 1.1 perry infile = *filesp = opn(fname);
1174 1.1 perry }
1175 1.1 perry }
1176 1.2 christos return 0;
1177 1.1 perry }
1178 1.1 perry
1179 1.2 christos static int
1180 1.2 christos /*ARGSUSED*/
1181 1.2 christos nx(pacmac unused)
1182 1.1 perry {
1183 1.1 perry
1184 1.1 perry if (!iflag) {
1185 1.1 perry getfname();
1186 1.1 perry if (fname[0] == '\0')
1187 1.1 perry exit(0);
1188 1.1 perry if (infile != stdin)
1189 1.1 perry fclose(infile);
1190 1.1 perry infile = *filesp = opn(fname);
1191 1.1 perry }
1192 1.2 christos return 0;
1193 1.1 perry }
1194 1.1 perry
1195 1.2 christos static int
1196 1.2 christos /*ARGSUSED*/
1197 1.2 christos skiptocom(pacmac unused)
1198 1.1 perry {
1199 1.1 perry
1200 1.1 perry SKIP_TO_COM;
1201 1.2 christos return COMX;
1202 1.1 perry }
1203 1.1 perry
1204 1.2 christos static int
1205 1.1 perry PP(pacmac c12)
1206 1.1 perry {
1207 1.1 perry int c1, c2;
1208 1.1 perry
1209 1.1 perry frommac(c12, c1, c2);
1210 1.1 perry printf(".%c%c", c1, c2);
1211 1.1 perry while (C != '\n')
1212 1.1 perry putchar(c);
1213 1.1 perry putchar('\n');
1214 1.2 christos return 0;
1215 1.1 perry }
1216 1.1 perry
1217 1.2 christos static int
1218 1.2 christos /*ARGSUSED*/
1219 1.2 christos AU(pacmac unused)
1220 1.1 perry {
1221 1.1 perry
1222 1.1 perry if (mac == MM)
1223 1.2 christos return 0;
1224 1.1 perry SKIP_TO_COM;
1225 1.2 christos return COMX;
1226 1.1 perry }
1227 1.1 perry
1228 1.2 christos static int
1229 1.1 perry SH(pacmac c12)
1230 1.1 perry {
1231 1.1 perry int c1, c2;
1232 1.1 perry
1233 1.1 perry frommac(c12, c1, c2);
1234 1.1 perry
1235 1.1 perry if (parag) {
1236 1.1 perry printf(".%c%c", c1, c2);
1237 1.1 perry while (C != '\n')
1238 1.1 perry putchar(c);
1239 1.1 perry putchar(c);
1240 1.1 perry putchar('!');
1241 1.1 perry for (;;) {
1242 1.1 perry while (C != '\n')
1243 1.1 perry putchar(c);
1244 1.1 perry putchar('\n');
1245 1.1 perry if (C == '.')
1246 1.2 christos return COM;
1247 1.1 perry putchar('!');
1248 1.1 perry putchar(c);
1249 1.1 perry }
1250 1.1 perry /*NOTREACHED*/
1251 1.1 perry } else {
1252 1.1 perry SKIP_TO_COM;
1253 1.2 christos return COMX;
1254 1.1 perry }
1255 1.1 perry }
1256 1.1 perry
1257 1.2 christos static int
1258 1.2 christos /*ARGSUSED*/
1259 1.2 christos UX(pacmac unused)
1260 1.1 perry {
1261 1.1 perry
1262 1.1 perry if (wordflag)
1263 1.1 perry printf("UNIX\n");
1264 1.1 perry else
1265 1.1 perry printf("UNIX ");
1266 1.2 christos return 0;
1267 1.1 perry }
1268 1.1 perry
1269 1.2 christos static int
1270 1.1 perry MMHU(pacmac c12)
1271 1.1 perry {
1272 1.1 perry int c1, c2;
1273 1.1 perry
1274 1.1 perry frommac(c12, c1, c2);
1275 1.1 perry if (parag) {
1276 1.1 perry printf(".%c%c", c1, c2);
1277 1.1 perry while (C != '\n')
1278 1.1 perry putchar(c);
1279 1.1 perry putchar('\n');
1280 1.1 perry } else {
1281 1.1 perry SKIP;
1282 1.1 perry }
1283 1.2 christos return 0;
1284 1.1 perry }
1285 1.1 perry
1286 1.2 christos static int
1287 1.1 perry mesnblock(pacmac c12)
1288 1.1 perry {
1289 1.1 perry int c1, c2;
1290 1.1 perry
1291 1.1 perry frommac(c12, c1, c2);
1292 1.1 perry noblock(')', c2);
1293 1.2 christos return 0;
1294 1.1 perry }
1295 1.1 perry
1296 1.2 christos static int
1297 1.1 perry mssnblock(pacmac c12)
1298 1.1 perry {
1299 1.1 perry int c1, c2;
1300 1.1 perry
1301 1.1 perry frommac(c12, c1, c2);
1302 1.1 perry noblock(c1, 'E');
1303 1.2 christos return 0;
1304 1.1 perry }
1305 1.1 perry
1306 1.2 christos static int
1307 1.2 christos /*ARGUSED*/
1308 1.2 christos nf(pacmac unused)
1309 1.1 perry {
1310 1.1 perry
1311 1.1 perry noblock('f', 'i');
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 ce(pacmac unused)
1318 1.1 perry {
1319 1.1 perry
1320 1.1 perry sce();
1321 1.2 christos return 0;
1322 1.1 perry }
1323 1.1 perry
1324 1.2 christos static int
1325 1.1 perry meip(pacmac c12)
1326 1.1 perry {
1327 1.1 perry
1328 1.1 perry if (parag)
1329 1.1 perry mepp(c12);
1330 1.1 perry else if (wordflag) /* save the tag */
1331 1.1 perry regline(meputmac, ONE);
1332 1.1 perry else
1333 1.1 perry SKIP;
1334 1.2 christos return 0;
1335 1.1 perry }
1336 1.1 perry
1337 1.1 perry /*
1338 1.1 perry * only called for -me .pp or .sh, when parag is on
1339 1.1 perry */
1340 1.2 christos static int
1341 1.1 perry mepp(pacmac c12)
1342 1.1 perry {
1343 1.1 perry
1344 1.1 perry PP(c12); /* eats the line */
1345 1.2 christos return 0;
1346 1.1 perry }
1347 1.1 perry
1348 1.1 perry /*
1349 1.1 perry * Start of a section heading; output the section name if doing words
1350 1.1 perry */
1351 1.2 christos static int
1352 1.1 perry mesh(pacmac c12)
1353 1.1 perry {
1354 1.1 perry
1355 1.1 perry if (parag)
1356 1.1 perry mepp(c12);
1357 1.1 perry else if (wordflag)
1358 1.1 perry defcomline(c12);
1359 1.1 perry else
1360 1.1 perry SKIP;
1361 1.2 christos return 0;
1362 1.1 perry }
1363 1.1 perry
1364 1.1 perry /*
1365 1.1 perry * process a font setting
1366 1.1 perry */
1367 1.2 christos static int
1368 1.1 perry mefont(pacmac c12)
1369 1.1 perry {
1370 1.1 perry
1371 1.1 perry argconcat = 1;
1372 1.1 perry defcomline(c12);
1373 1.1 perry argconcat = 0;
1374 1.2 christos return 0;
1375 1.1 perry }
1376 1.1 perry
1377 1.2 christos static int
1378 1.1 perry manfont(pacmac c12)
1379 1.1 perry {
1380 1.1 perry
1381 1.2 christos return mefont(c12);
1382 1.1 perry }
1383 1.1 perry
1384 1.2 christos static int
1385 1.1 perry manpp(pacmac c12)
1386 1.1 perry {
1387 1.1 perry
1388 1.2 christos return mepp(c12);
1389 1.1 perry }
1390 1.1 perry
1391 1.2 christos static void
1392 1.1 perry defcomline(pacmac c12)
1393 1.1 perry {
1394 1.1 perry int c1, c2;
1395 1.1 perry
1396 1.1 perry frommac(c12, c1, c2);
1397 1.1 perry if (msflag && mac == MM && c2 == 'L') {
1398 1.1 perry if (disp || c1 == 'R') {
1399 1.1 perry noblock('L', 'E');
1400 1.1 perry } else {
1401 1.1 perry SKIP;
1402 1.1 perry putchar('.');
1403 1.1 perry }
1404 1.1 perry }
1405 1.1 perry else if (c1 == '.' && c2 == '.') {
1406 1.1 perry if (msflag) {
1407 1.1 perry SKIP;
1408 1.1 perry return;
1409 1.1 perry }
1410 1.1 perry while (C == '.')
1411 1.1 perry /*VOID*/;
1412 1.1 perry }
1413 1.1 perry ++inmacro;
1414 1.1 perry /*
1415 1.1 perry * Process the arguments to the macro
1416 1.1 perry */
1417 1.1 perry switch (mac) {
1418 1.1 perry default:
1419 1.1 perry case MM:
1420 1.1 perry case MS:
1421 1.1 perry if (c1 <= 'Z' && msflag)
1422 1.1 perry regline(msputmac, ONE);
1423 1.1 perry else
1424 1.1 perry regline(msputmac, TWO);
1425 1.1 perry break;
1426 1.1 perry case ME:
1427 1.1 perry regline(meputmac, ONE);
1428 1.1 perry break;
1429 1.1 perry }
1430 1.1 perry --inmacro;
1431 1.1 perry }
1432 1.1 perry
1433 1.2 christos static void
1434 1.1 perry comline(void)
1435 1.1 perry {
1436 1.1 perry int c1;
1437 1.1 perry int c2;
1438 1.1 perry pacmac c12;
1439 1.1 perry int mid;
1440 1.1 perry int lb, ub;
1441 1.1 perry int hit;
1442 1.1 perry static int tabsize = 0;
1443 1.2 christos static const struct mactab *mactab = NULL;
1444 1.2 christos const struct mactab *mp;
1445 1.1 perry
1446 1.1 perry if (mactab == 0)
1447 1.1 perry buildtab(&mactab, &tabsize);
1448 1.1 perry com:
1449 1.1 perry while (C == ' ' || c == '\t')
1450 1.1 perry ;
1451 1.1 perry comx:
1452 1.1 perry if ((c1 = c) == '\n')
1453 1.1 perry return;
1454 1.1 perry c2 = C;
1455 1.1 perry if (c1 == '.' && c2 != '.')
1456 1.1 perry inmacro = NO;
1457 1.1 perry if (msflag && c1 == '[') {
1458 1.1 perry refer(c2);
1459 1.1 perry return;
1460 1.1 perry }
1461 1.1 perry if (parag && mac==MM && c1 == 'P' && c2 == '\n') {
1462 1.1 perry printf(".P\n");
1463 1.1 perry return;
1464 1.1 perry }
1465 1.1 perry if (c2 == '\n')
1466 1.1 perry return;
1467 1.1 perry /*
1468 1.1 perry * Single letter macro
1469 1.1 perry */
1470 1.1 perry if (mac == ME && (c2 == ' ' || c2 == '\t') )
1471 1.1 perry c2 = ' ';
1472 1.1 perry c12 = tomac(c1, c2);
1473 1.1 perry /*
1474 1.1 perry * binary search through the table of macros
1475 1.1 perry */
1476 1.1 perry lb = 0;
1477 1.1 perry ub = tabsize - 1;
1478 1.1 perry while (lb <= ub) {
1479 1.1 perry mid = (ub + lb) / 2;
1480 1.1 perry mp = &mactab[mid];
1481 1.1 perry if (mp->macname < c12)
1482 1.1 perry lb = mid + 1;
1483 1.1 perry else if (mp->macname > c12)
1484 1.1 perry ub = mid - 1;
1485 1.1 perry else {
1486 1.1 perry hit = 1;
1487 1.1 perry #ifdef FULLDEBUG
1488 1.1 perry printf("preliminary hit macro %c%c ", c1, c2);
1489 1.1 perry #endif /* FULLDEBUG */
1490 1.1 perry switch (mp->condition) {
1491 1.1 perry case NONE:
1492 1.1 perry hit = YES;
1493 1.1 perry break;
1494 1.1 perry case FNEST:
1495 1.1 perry hit = (filesp == files);
1496 1.1 perry break;
1497 1.1 perry case NOMAC:
1498 1.1 perry hit = !inmacro;
1499 1.1 perry break;
1500 1.1 perry case MAC:
1501 1.1 perry hit = inmacro;
1502 1.1 perry break;
1503 1.1 perry case PARAG:
1504 1.1 perry hit = parag;
1505 1.1 perry break;
1506 1.1 perry case NBLK:
1507 1.1 perry hit = !keepblock;
1508 1.1 perry break;
1509 1.1 perry default:
1510 1.1 perry hit = 0;
1511 1.1 perry }
1512 1.1 perry
1513 1.1 perry if (hit) {
1514 1.1 perry #ifdef FULLDEBUG
1515 1.1 perry printf("MATCH\n");
1516 1.1 perry #endif /* FULLDEBUG */
1517 1.1 perry switch ((*(mp->func))(c12)) {
1518 1.1 perry default:
1519 1.1 perry return;
1520 1.1 perry case COMX:
1521 1.1 perry goto comx;
1522 1.1 perry case COM:
1523 1.1 perry goto com;
1524 1.1 perry }
1525 1.1 perry }
1526 1.1 perry #ifdef FULLDEBUG
1527 1.1 perry printf("FAIL\n");
1528 1.1 perry #endif /* FULLDEBUG */
1529 1.1 perry break;
1530 1.1 perry }
1531 1.1 perry }
1532 1.1 perry defcomline(c12);
1533 1.1 perry }
1534 1.1 perry
1535 1.2 christos static int
1536 1.1 perry macsort(const void *p1, const void *p2)
1537 1.1 perry {
1538 1.2 christos const struct mactab *t1 = p1;
1539 1.2 christos const struct mactab *t2 = p2;
1540 1.1 perry
1541 1.2 christos return t1->macname - t2->macname;
1542 1.1 perry }
1543 1.1 perry
1544 1.2 christos static int
1545 1.2 christos sizetab(const struct mactab *mp)
1546 1.1 perry {
1547 1.1 perry int i;
1548 1.1 perry
1549 1.1 perry i = 0;
1550 1.1 perry if (mp) {
1551 1.1 perry for (; mp->macname; mp++, i++)
1552 1.1 perry /*VOID*/ ;
1553 1.1 perry }
1554 1.2 christos return i;
1555 1.1 perry }
1556 1.1 perry
1557 1.2 christos static struct mactab *
1558 1.2 christos macfill(struct mactab *dst, const struct mactab *src)
1559 1.1 perry {
1560 1.1 perry
1561 1.1 perry if (src) {
1562 1.1 perry while (src->macname)
1563 1.1 perry *dst++ = *src++;
1564 1.1 perry }
1565 1.2 christos return dst;
1566 1.1 perry }
1567 1.1 perry
1568 1.2 christos static void
1569 1.1 perry usage(void)
1570 1.1 perry {
1571 1.1 perry extern char *__progname;
1572 1.1 perry
1573 1.3 wiz fprintf(stderr, "usage: %s [-ikpw ] [ -m a | e | l | m | s] [file ...]\n", __progname);
1574 1.1 perry exit(1);
1575 1.1 perry }
1576 1.1 perry
1577 1.2 christos static void
1578 1.2 christos buildtab(const struct mactab **r_back, int *r_size)
1579 1.1 perry {
1580 1.2 christos size_t size;
1581 1.2 christos const struct mactab *p1, *p2;
1582 1.2 christos struct mactab *back, *p;
1583 1.1 perry
1584 1.1 perry size = sizetab(troffmactab) + sizetab(ppmactab);
1585 1.1 perry p1 = p2 = NULL;
1586 1.1 perry if (msflag) {
1587 1.1 perry switch (mac) {
1588 1.1 perry case ME:
1589 1.1 perry p1 = memactab;
1590 1.1 perry break;
1591 1.1 perry case MM:
1592 1.1 perry p1 = msmactab;
1593 1.1 perry p2 = mmmactab;
1594 1.1 perry break;
1595 1.1 perry case MS:
1596 1.1 perry p1 = msmactab;
1597 1.1 perry break;
1598 1.1 perry case MA:
1599 1.1 perry p1 = manmactab;
1600 1.1 perry break;
1601 1.1 perry default:
1602 1.1 perry break;
1603 1.1 perry }
1604 1.1 perry }
1605 1.1 perry size += sizetab(p1);
1606 1.1 perry size += sizetab(p2);
1607 1.2 christos back = calloc(size + 2, sizeof(struct mactab));
1608 1.1 perry if (back == NULL)
1609 1.1 perry err(1, NULL);
1610 1.1 perry
1611 1.1 perry p = macfill(back, troffmactab);
1612 1.1 perry p = macfill(p, ppmactab);
1613 1.1 perry p = macfill(p, p1);
1614 1.1 perry p = macfill(p, p2);
1615 1.1 perry
1616 1.1 perry qsort(back, size, sizeof(struct mactab), macsort);
1617 1.1 perry *r_size = size;
1618 1.1 perry *r_back = back;
1619 1.1 perry }
1620 1.1 perry
1621 1.1 perry /*
1622 1.1 perry * troff commands
1623 1.1 perry */
1624 1.2 christos static const struct mactab troffmactab[] = {
1625 1.1 perry M(NONE, '\\','"', skip), /* comment */
1626 1.1 perry M(NOMAC, 'd','e', domacro), /* define */
1627 1.1 perry M(NOMAC, 'i','g', domacro), /* ignore till .. */
1628 1.1 perry M(NOMAC, 'a','m', domacro), /* append macro */
1629 1.1 perry M(NBLK, 'n','f', nf), /* filled */
1630 1.1 perry M(NBLK, 'c','e', ce), /* centered */
1631 1.1 perry
1632 1.1 perry M(NONE, 's','o', so), /* source a file */
1633 1.1 perry M(NONE, 'n','x', nx), /* go to next file */
1634 1.1 perry
1635 1.1 perry M(NONE, 't','m', skip), /* print string on tty */
1636 1.1 perry M(NONE, 'h','w', skip), /* exception hyphen words */
1637 1.1 perry M(NONE, 0,0, 0)
1638 1.1 perry };
1639 1.1 perry
1640 1.1 perry /*
1641 1.1 perry * Preprocessor output
1642 1.1 perry */
1643 1.2 christos static const struct mactab ppmactab[] = {
1644 1.1 perry M(FNEST, 'E','Q', EQ), /* equation starting */
1645 1.1 perry M(FNEST, 'T','S', intbl), /* table starting */
1646 1.1 perry M(FNEST, 'T','C', intbl), /* alternative table? */
1647 1.1 perry M(FNEST, 'T','&', intbl), /* table reformatting */
1648 1.1 perry M(NONE, 'T','E', outtbl),/* table ending */
1649 1.1 perry M(NONE, 'P','S', PS), /* picture starting */
1650 1.1 perry M(NONE, 0,0, 0)
1651 1.1 perry };
1652 1.1 perry
1653 1.1 perry /*
1654 1.1 perry * Particular to ms and mm
1655 1.1 perry */
1656 1.2 christos static const struct mactab msmactab[] = {
1657 1.1 perry M(NONE, 'T','L', skiptocom), /* title follows */
1658 1.1 perry M(NONE, 'F','S', skiptocom), /* start footnote */
1659 1.1 perry M(NONE, 'O','K', skiptocom), /* Other kws */
1660 1.1 perry
1661 1.1 perry M(NONE, 'N','R', skip), /* undocumented */
1662 1.1 perry M(NONE, 'N','D', skip), /* use supplied date */
1663 1.1 perry
1664 1.1 perry M(PARAG, 'P','P', PP), /* begin parag */
1665 1.1 perry M(PARAG, 'I','P', PP), /* begin indent parag, tag x */
1666 1.1 perry M(PARAG, 'L','P', PP), /* left blocked parag */
1667 1.1 perry
1668 1.1 perry M(NONE, 'A','U', AU), /* author */
1669 1.1 perry M(NONE, 'A','I', AU), /* authors institution */
1670 1.1 perry
1671 1.1 perry M(NONE, 'S','H', SH), /* section heading */
1672 1.1 perry M(NONE, 'S','N', SH), /* undocumented */
1673 1.1 perry M(NONE, 'U','X', UX), /* unix */
1674 1.1 perry
1675 1.1 perry M(NBLK, 'D','S', mssnblock), /* start display text */
1676 1.1 perry M(NBLK, 'K','S', mssnblock), /* start keep */
1677 1.1 perry M(NBLK, 'K','F', mssnblock), /* start float keep */
1678 1.1 perry M(NONE, 0,0, 0)
1679 1.1 perry };
1680 1.1 perry
1681 1.2 christos static const struct mactab mmmactab[] = {
1682 1.1 perry M(NONE, 'H',' ', MMHU), /* -mm ? */
1683 1.1 perry M(NONE, 'H','U', MMHU), /* -mm ? */
1684 1.1 perry M(PARAG, 'P',' ', PP), /* paragraph for -mm */
1685 1.1 perry M(NBLK, 'N','S', mssnblock), /* undocumented */
1686 1.1 perry M(NONE, 0,0, 0)
1687 1.1 perry };
1688 1.1 perry
1689 1.2 christos static const struct mactab memactab[] = {
1690 1.1 perry M(PARAG, 'p','p', mepp),
1691 1.1 perry M(PARAG, 'l','p', mepp),
1692 1.1 perry M(PARAG, 'n','p', mepp),
1693 1.1 perry M(NONE, 'i','p', meip),
1694 1.1 perry
1695 1.1 perry M(NONE, 's','h', mesh),
1696 1.1 perry M(NONE, 'u','h', mesh),
1697 1.1 perry
1698 1.1 perry M(NBLK, '(','l', mesnblock),
1699 1.1 perry M(NBLK, '(','q', mesnblock),
1700 1.1 perry M(NBLK, '(','b', mesnblock),
1701 1.1 perry M(NBLK, '(','z', mesnblock),
1702 1.1 perry M(NBLK, '(','c', mesnblock),
1703 1.1 perry
1704 1.1 perry M(NBLK, '(','d', mesnblock),
1705 1.1 perry M(NBLK, '(','f', mesnblock),
1706 1.1 perry M(NBLK, '(','x', mesnblock),
1707 1.1 perry
1708 1.1 perry M(NONE, 'r',' ', mefont),
1709 1.1 perry M(NONE, 'i',' ', mefont),
1710 1.1 perry M(NONE, 'b',' ', mefont),
1711 1.1 perry M(NONE, 'u',' ', mefont),
1712 1.1 perry M(NONE, 'q',' ', mefont),
1713 1.1 perry M(NONE, 'r','b', mefont),
1714 1.1 perry M(NONE, 'b','i', mefont),
1715 1.1 perry M(NONE, 'b','x', mefont),
1716 1.1 perry M(NONE, 0,0, 0)
1717 1.1 perry };
1718 1.1 perry
1719 1.2 christos static const struct mactab manmactab[] = {
1720 1.1 perry M(PARAG, 'B','I', manfont),
1721 1.1 perry M(PARAG, 'B','R', manfont),
1722 1.1 perry M(PARAG, 'I','B', manfont),
1723 1.1 perry M(PARAG, 'I','R', manfont),
1724 1.1 perry M(PARAG, 'R','B', manfont),
1725 1.1 perry M(PARAG, 'R','I', manfont),
1726 1.1 perry
1727 1.1 perry M(PARAG, 'P','P', manpp),
1728 1.1 perry M(PARAG, 'L','P', manpp),
1729 1.1 perry M(PARAG, 'H','P', manpp),
1730 1.1 perry M(NONE, 0,0, 0)
1731 1.1 perry };
1732