1 1.14 rillig /* $NetBSD: deroff.c,v 1.14 2025/02/20 19:32:16 rillig 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.14 rillig __RCSID("$NetBSD: deroff.c,v 1.14 2025/02/20 19:32:16 rillig 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.14 rillig static void msputwords(void); 254 1.2 christos static void meputmac(char *, int); 255 1.14 rillig static void meputwords(void); 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.1 perry } 365 1.1 perry 366 1.2 christos static int 367 1.1 perry skeqn(void) 368 1.1 perry { 369 1.1 perry 370 1.1 perry while ((c = getc(infile)) != rdelim) { 371 1.1 perry if (c == EOF) 372 1.1 perry c = eof(); 373 1.1 perry else if (c == '"') { 374 1.1 perry while ((c = getc(infile)) != '"') { 375 1.1 perry if (c == EOF || 376 1.1 perry (c == '\\' && (c = getc(infile)) == EOF)) 377 1.1 perry c = eof(); 378 1.1 perry } 379 1.1 perry } 380 1.1 perry } 381 1.1 perry if (msflag) 382 1.2 christos return c == 'x'; 383 1.2 christos return c == ' '; 384 1.1 perry } 385 1.1 perry 386 1.2 christos static FILE * 387 1.1 perry opn(char *p) 388 1.1 perry { 389 1.1 perry FILE *fd; 390 1.1 perry 391 1.1 perry if ((fd = fopen(p, "r")) == NULL) 392 1.1 perry err(1, "fopen %s", p); 393 1.1 perry 394 1.2 christos return fd; 395 1.1 perry } 396 1.1 perry 397 1.2 christos static int 398 1.1 perry eof(void) 399 1.1 perry { 400 1.1 perry 401 1.1 perry if (infile != stdin) 402 1.1 perry fclose(infile); 403 1.1 perry if (filesp > files) 404 1.1 perry infile = *--filesp; 405 1.1 perry else if (argc > 0) { 406 1.1 perry infile = opn(argv[0]); 407 1.1 perry --argc; 408 1.1 perry ++argv; 409 1.1 perry } else 410 1.1 perry exit(0); 411 1.2 christos return C; 412 1.1 perry } 413 1.1 perry 414 1.2 christos static void 415 1.1 perry getfname(void) 416 1.1 perry { 417 1.1 perry char *p; 418 1.1 perry struct chain { 419 1.1 perry struct chain *nextp; 420 1.1 perry char *datap; 421 1.1 perry } *q; 422 1.1 perry static struct chain *namechain= NULL; 423 1.1 perry 424 1.1 perry while (C == ' ') 425 1.1 perry ; /* nothing */ 426 1.1 perry 427 1.6 lukem for (p = fname ; p - fname < (ptrdiff_t)sizeof(fname) && 428 1.6 lukem (*p = c) != '\n' && 429 1.1 perry c != ' ' && c != '\t' && c != '\\'; ++p) 430 1.1 perry C; 431 1.1 perry *p = '\0'; 432 1.1 perry while (c != '\n') 433 1.1 perry C; 434 1.1 perry 435 1.1 perry /* see if this name has already been used */ 436 1.1 perry for (q = namechain ; q; q = q->nextp) 437 1.1 perry if (strcmp(fname, q->datap) == 0) { 438 1.1 perry fname[0] = '\0'; 439 1.1 perry return; 440 1.1 perry } 441 1.1 perry 442 1.1 perry q = (struct chain *) malloc(sizeof(struct chain)); 443 1.1 perry if (q == NULL) 444 1.1 perry err(1, NULL); 445 1.1 perry q->nextp = namechain; 446 1.1 perry q->datap = strdup(fname); 447 1.1 perry if (q->datap == NULL) 448 1.1 perry err(1, NULL); 449 1.1 perry namechain = q; 450 1.1 perry } 451 1.1 perry 452 1.1 perry /*ARGSUSED*/ 453 1.2 christos static void 454 1.1 perry textline(char *str, int constant) 455 1.1 perry { 456 1.1 perry 457 1.1 perry if (wordflag) { 458 1.14 rillig msputwords(); 459 1.1 perry return; 460 1.1 perry } 461 1.1 perry puts(str); 462 1.1 perry } 463 1.1 perry 464 1.9 joerg static void 465 1.1 perry work(void) 466 1.1 perry { 467 1.1 perry 468 1.1 perry for (;;) { 469 1.1 perry C; 470 1.1 perry #ifdef FULLDEBUG 471 1.1 perry printf("Starting work with `%c'\n", c); 472 1.1 perry #endif /* FULLDEBUG */ 473 1.1 perry if (c == '.' || c == '\'') 474 1.1 perry comline(); 475 1.1 perry else 476 1.1 perry regline(textline, TWO); 477 1.1 perry } 478 1.1 perry } 479 1.1 perry 480 1.2 christos static void 481 1.1 perry regline(void (*pfunc)(char *, int), int constant) 482 1.1 perry { 483 1.1 perry 484 1.1 perry line[0] = c; 485 1.1 perry lp = line; 486 1.6 lukem while (lp - line < (ptrdiff_t)sizeof(line)) { 487 1.1 perry if (c == '\\') { 488 1.1 perry *lp = ' '; 489 1.1 perry backsl(); 490 1.1 perry } 491 1.1 perry if (c == '\n') 492 1.1 perry break; 493 1.1 perry if (intable && c == 'T') { 494 1.1 perry *++lp = C; 495 1.1 perry if (c == '{' || c == '}') { 496 1.1 perry lp[-1] = ' '; 497 1.1 perry *lp = C; 498 1.1 perry } 499 1.1 perry } else { 500 1.1 perry *++lp = C; 501 1.1 perry } 502 1.1 perry } 503 1.1 perry *lp = '\0'; 504 1.1 perry 505 1.1 perry if (line[0] != '\0') 506 1.1 perry (*pfunc)(line, constant); 507 1.1 perry } 508 1.1 perry 509 1.2 christos static void 510 1.1 perry macro(void) 511 1.1 perry { 512 1.1 perry 513 1.1 perry if (msflag) { 514 1.1 perry do { 515 1.1 perry SKIP; 516 1.1 perry } while (C!='.' || C!='.' || C=='.'); /* look for .. */ 517 1.1 perry if (c != '\n') 518 1.1 perry SKIP; 519 1.1 perry return; 520 1.1 perry } 521 1.1 perry SKIP; 522 1.1 perry inmacro = YES; 523 1.1 perry } 524 1.1 perry 525 1.2 christos static void 526 1.1 perry tbl(void) 527 1.1 perry { 528 1.1 perry 529 1.1 perry while (C != '.') 530 1.1 perry ; /* nothing */ 531 1.1 perry SKIP; 532 1.1 perry intable = YES; 533 1.1 perry } 534 1.1 perry 535 1.2 christos static void 536 1.1 perry stbl(void) 537 1.1 perry { 538 1.1 perry 539 1.1 perry while (C != '.') 540 1.1 perry ; /* nothing */ 541 1.1 perry SKIP_TO_COM; 542 1.1 perry if (c != 'T' || C != 'E') { 543 1.1 perry SKIP; 544 1.1 perry pc = c; 545 1.1 perry while (C != '.' || pc != '\n' || C != 'T' || C != 'E') 546 1.1 perry pc = c; 547 1.1 perry } 548 1.1 perry } 549 1.1 perry 550 1.2 christos static void 551 1.1 perry eqn(void) 552 1.1 perry { 553 1.1 perry int c1, c2; 554 1.1 perry int dflg; 555 1.1 perry char last; 556 1.1 perry 557 1.1 perry last=0; 558 1.1 perry dflg = 1; 559 1.1 perry SKIP; 560 1.1 perry 561 1.1 perry for (;;) { 562 1.1 perry if (C1 == '.' || c == '\'') { 563 1.1 perry while (C1 == ' ' || c == '\t') 564 1.1 perry ; 565 1.1 perry if (c == 'E' && C1 == 'N') { 566 1.1 perry SKIP; 567 1.1 perry if (msflag && dflg) { 568 1.1 perry putchar('x'); 569 1.1 perry putchar(' '); 570 1.1 perry if (last) { 571 1.1 perry putchar(last); 572 1.1 perry putchar('\n'); 573 1.1 perry } 574 1.1 perry } 575 1.1 perry return; 576 1.1 perry } 577 1.1 perry } else if (c == 'd') { 578 1.1 perry /* look for delim */ 579 1.1 perry if (C1 == 'e' && C1 == 'l') 580 1.1 perry if (C1 == 'i' && C1 == 'm') { 581 1.1 perry while (C1 == ' ') 582 1.1 perry ; /* nothing */ 583 1.1 perry 584 1.1 perry if ((c1 = c) == '\n' || 585 1.1 perry (c2 = C1) == '\n' || 586 1.1 perry (c1 == 'o' && c2 == 'f' && C1=='f')) { 587 1.1 perry ldelim = NOCHAR; 588 1.1 perry rdelim = NOCHAR; 589 1.1 perry } else { 590 1.1 perry ldelim = c1; 591 1.1 perry rdelim = c2; 592 1.1 perry } 593 1.1 perry } 594 1.1 perry dflg = 0; 595 1.1 perry } 596 1.1 perry 597 1.1 perry if (c != '\n') 598 1.1 perry while (C1 != '\n') { 599 1.1 perry if (chars[c] == PUNCT) 600 1.1 perry last = c; 601 1.1 perry else if (c != ' ') 602 1.1 perry last = 0; 603 1.1 perry } 604 1.1 perry } 605 1.1 perry } 606 1.1 perry 607 1.1 perry /* skip over a complete backslash construction */ 608 1.2 christos static void 609 1.1 perry backsl(void) 610 1.1 perry { 611 1.1 perry int bdelim; 612 1.1 perry 613 1.1 perry sw: 614 1.1 perry switch (C) { 615 1.1 perry case '"': 616 1.1 perry SKIP; 617 1.1 perry return; 618 1.1 perry 619 1.1 perry case 's': 620 1.1 perry if (C == '\\') 621 1.1 perry backsl(); 622 1.1 perry else { 623 1.1 perry while (C >= '0' && c <= '9') 624 1.1 perry ; /* nothing */ 625 1.1 perry ungetc(c, infile); 626 1.1 perry c = '0'; 627 1.1 perry } 628 1.1 perry --lp; 629 1.1 perry return; 630 1.1 perry 631 1.1 perry case 'f': 632 1.1 perry case 'n': 633 1.1 perry case '*': 634 1.1 perry if (C != '(') 635 1.1 perry return; 636 1.1 perry 637 1.12 mrg /* FALLTHROUGH */ 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.14 rillig return; 677 1.1 perry 678 1.1 perry default: 679 1.1 perry return; 680 1.1 perry } 681 1.1 perry } 682 1.1 perry 683 1.2 christos static void 684 1.1 perry sce(void) 685 1.1 perry { 686 1.1 perry char *ap; 687 1.1 perry int n, i; 688 1.1 perry char a[10]; 689 1.1 perry 690 1.1 perry for (ap = a; C != '\n'; ap++) { 691 1.1 perry *ap = c; 692 1.1 perry if (ap == &a[9]) { 693 1.1 perry SKIP; 694 1.1 perry ap = a; 695 1.1 perry break; 696 1.1 perry } 697 1.1 perry } 698 1.1 perry if (ap != a) 699 1.1 perry n = atoi(a); 700 1.1 perry else 701 1.1 perry n = 1; 702 1.1 perry for (i = 0; i < n;) { 703 1.1 perry if (C == '.') { 704 1.1 perry if (C == 'c') { 705 1.1 perry if (C == 'e') { 706 1.1 perry while (C == ' ') 707 1.1 perry ; /* nothing */ 708 1.1 perry if (c == '0') { 709 1.1 perry SKIP; 710 1.1 perry break; 711 1.1 perry } else 712 1.1 perry SKIP; 713 1.1 perry } 714 1.1 perry else 715 1.1 perry SKIP; 716 1.1 perry } else if (c == 'P' || C == 'P') { 717 1.1 perry if (c != '\n') 718 1.1 perry SKIP; 719 1.1 perry break; 720 1.1 perry } else if (c != '\n') 721 1.1 perry SKIP; 722 1.1 perry } else { 723 1.1 perry SKIP; 724 1.1 perry i++; 725 1.1 perry } 726 1.1 perry } 727 1.1 perry } 728 1.1 perry 729 1.2 christos static void 730 1.1 perry refer(int c1) 731 1.1 perry { 732 1.1 perry int c2; 733 1.1 perry 734 1.1 perry if (c1 != '\n') 735 1.1 perry SKIP; 736 1.1 perry 737 1.1 perry for (c2 = -1;;) { 738 1.1 perry if (C != '.') 739 1.1 perry SKIP; 740 1.1 perry else { 741 1.1 perry if (C != ']') 742 1.1 perry SKIP; 743 1.1 perry else { 744 1.1 perry while (C != '\n') 745 1.1 perry c2 = c; 746 1.1 perry if (c2 != -1 && chars[c2] == PUNCT) 747 1.1 perry putchar(c2); 748 1.1 perry return; 749 1.1 perry } 750 1.1 perry } 751 1.1 perry } 752 1.1 perry } 753 1.1 perry 754 1.2 christos static void 755 1.1 perry inpic(void) 756 1.1 perry { 757 1.1 perry int c1; 758 1.1 perry char *p1; 759 1.1 perry 760 1.1 perry SKIP; 761 1.1 perry p1 = line; 762 1.1 perry c = '\n'; 763 1.1 perry for (;;) { 764 1.1 perry c1 = c; 765 1.1 perry if (C == '.' && c1 == '\n') { 766 1.1 perry if (C != 'P') { 767 1.1 perry if (c == '\n') 768 1.1 perry continue; 769 1.1 perry else { 770 1.1 perry SKIP; 771 1.1 perry c = '\n'; 772 1.1 perry continue; 773 1.1 perry } 774 1.1 perry } 775 1.1 perry if (C != 'E') { 776 1.1 perry if (c == '\n') 777 1.1 perry continue; 778 1.1 perry else { 779 1.1 perry SKIP; 780 1.1 perry c = '\n'; 781 1.1 perry continue; 782 1.1 perry } 783 1.1 perry } 784 1.1 perry SKIP; 785 1.1 perry return; 786 1.1 perry } 787 1.1 perry else if (c == '\"') { 788 1.1 perry while (C != '\"') { 789 1.1 perry if (c == '\\') { 790 1.1 perry if (C == '\"') 791 1.1 perry continue; 792 1.1 perry ungetc(c, infile); 793 1.1 perry backsl(); 794 1.1 perry } else 795 1.1 perry *p1++ = c; 796 1.1 perry } 797 1.1 perry *p1++ = ' '; 798 1.1 perry } 799 1.1 perry else if (c == '\n' && p1 != line) { 800 1.1 perry *p1 = '\0'; 801 1.1 perry if (wordflag) 802 1.14 rillig msputwords(); 803 1.1 perry else { 804 1.1 perry puts(line); 805 1.1 perry putchar('\n'); 806 1.1 perry } 807 1.1 perry p1 = line; 808 1.1 perry } 809 1.1 perry } 810 1.1 perry } 811 1.1 perry 812 1.1 perry #ifdef DEBUG 813 1.2 christos static int 814 1.1 perry _C1(void) 815 1.1 perry { 816 1.1 perry 817 1.7 wiz return C1get; 818 1.1 perry } 819 1.1 perry 820 1.2 christos static int 821 1.1 perry _C(void) 822 1.1 perry { 823 1.1 perry 824 1.7 wiz return Cget; 825 1.1 perry } 826 1.1 perry #endif /* DEBUG */ 827 1.1 perry 828 1.1 perry /* 829 1.1 perry * Put out a macro line, using ms and mm conventions. 830 1.1 perry */ 831 1.2 christos static void 832 1.1 perry msputmac(char *s, int constant) 833 1.1 perry { 834 1.1 perry char *t; 835 1.1 perry int found; 836 1.1 perry int last; 837 1.1 perry 838 1.1 perry last = 0; 839 1.1 perry found = 0; 840 1.1 perry if (wordflag) { 841 1.14 rillig msputwords(); 842 1.1 perry return; 843 1.1 perry } 844 1.1 perry while (*s) { 845 1.1 perry while (*s == ' ' || *s == '\t') 846 1.1 perry putchar(*s++); 847 1.1 perry for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t) 848 1.1 perry ; /* nothing */ 849 1.1 perry if (*s == '\"') 850 1.1 perry s++; 851 1.1 perry if (t > s + constant && chars[(unsigned char)s[0]] == LETTER && 852 1.1 perry chars[(unsigned char)s[1]] == LETTER) { 853 1.1 perry while (s < t) 854 1.1 perry if (*s == '\"') 855 1.1 perry s++; 856 1.1 perry else 857 1.1 perry putchar(*s++); 858 1.1 perry last = *(t-1); 859 1.1 perry found++; 860 1.1 perry } else if (found && chars[(unsigned char)s[0]] == PUNCT && 861 1.1 perry s[1] == '\0') { 862 1.1 perry putchar(*s++); 863 1.1 perry } else { 864 1.1 perry last = *(t - 1); 865 1.1 perry s = t; 866 1.1 perry } 867 1.1 perry } 868 1.1 perry putchar('\n'); 869 1.1 perry if (msflag && chars[last] == PUNCT) { 870 1.1 perry putchar(last); 871 1.1 perry putchar('\n'); 872 1.1 perry } 873 1.1 perry } 874 1.1 perry 875 1.1 perry /* 876 1.1 perry * put out words (for the -w option) with ms and mm conventions 877 1.1 perry */ 878 1.2 christos static void 879 1.14 rillig msputwords(void) 880 1.1 perry { 881 1.1 perry char *p, *p1; 882 1.1 perry int i, nlet; 883 1.1 perry 884 1.1 perry for (p1 = line;;) { 885 1.1 perry /* 886 1.1 perry * skip initial specials ampersands and apostrophes 887 1.1 perry */ 888 1.1 perry while (chars[(unsigned char)*p1] < DIGIT) 889 1.1 perry if (*p1++ == '\0') 890 1.1 perry return; 891 1.1 perry nlet = 0; 892 1.1 perry for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p) 893 1.1 perry if (i == LETTER) 894 1.1 perry ++nlet; 895 1.1 perry 896 1.1 perry if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) { 897 1.1 perry /* 898 1.1 perry * delete trailing ampersands and apostrophes 899 1.1 perry */ 900 1.1 perry while ((i = chars[(unsigned char)p[-1]]) == PUNCT || 901 1.1 perry i == APOS ) 902 1.1 perry --p; 903 1.1 perry while (p1 < p) 904 1.1 perry putchar(*p1++); 905 1.1 perry putchar('\n'); 906 1.1 perry } else { 907 1.1 perry p1 = p; 908 1.1 perry } 909 1.1 perry } 910 1.1 perry } 911 1.1 perry 912 1.1 perry /* 913 1.1 perry * put out a macro using the me conventions 914 1.1 perry */ 915 1.1 perry #define SKIPBLANK(cp) while (*cp == ' ' || *cp == '\t') { cp++; } 916 1.1 perry 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.14 rillig meputwords(); 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.14 rillig meputwords(void) 1011 1.1 perry { 1012 1.1 perry 1013 1.14 rillig msputwords(); 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.14 rillig /*ARGSUSED*/ 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.14 rillig /*ARGSUSED*/ 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