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