Annotation of mandoc/roff.c, Revision 1.64
1.64 ! kristaps 1: /* $Id: roff.c,v 1.63 2008/12/10 16:03:12 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
1.30 kristaps 19: #include <sys/param.h>
1.33 kristaps 20: #include <sys/types.h>
1.30 kristaps 21:
1.1 kristaps 22: #include <assert.h>
23: #include <ctype.h>
24: #include <err.h>
1.12 kristaps 25: #include <stdarg.h>
1.1 kristaps 26: #include <stdlib.h>
27: #include <stdio.h>
28: #include <string.h>
29: #include <time.h>
30:
31: #include "private.h"
1.43 kristaps 32: #include "roff.h"
1.1 kristaps 33:
1.33 kristaps 34: /* FIXME: First letters of quoted-text interpreted in rofffindtok. */
35: /* FIXME: `No' not implemented. */
1.27 kristaps 36: /* TODO: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */
37: /* TODO: warn about empty lists. */
38: /* TODO: (warn) some sections need specific elements. */
39: /* TODO: (warn) NAME section has particular order. */
40: /* TODO: macros with a set number of arguments? */
1.43 kristaps 41: /* FIXME: Bl -diag supposed to ignore callable children. */
1.1 kristaps 42:
43: struct roffnode {
1.55 kristaps 44: int tok; /* Token id. */
45: struct roffnode *parent; /* Parent (or NULL). */
46: };
47:
48: enum rofferr {
49: ERR_ARGEQ1, /* Macro requires arg == 1. */
50: ERR_ARGEQ0, /* Macro requires arg == 0. */
51: ERR_ARGGE1, /* Macro requires arg >= 1. */
52: ERR_ARGGE2, /* Macro requires arg >= 2. */
53: ERR_ARGLEN, /* Macro argument too long. */
54: ERR_BADARG, /* Macro has bad arg. */
55: ERR_ARGMNY, /* Too many macro arguments. */
56: ERR_NOTSUP, /* Macro not supported. */
57: ERR_DEPREC, /* Macro deprecated. */
58: ERR_PR_OOO, /* Prelude macro bad order. */
59: ERR_PR_REP, /* Prelude macro repeated. */
60: ERR_NOT_PR, /* Not allowed in prelude. */
1.60 kristaps 61: WRN_SECORD /* Sections out-of-order. */
1.1 kristaps 62: };
63:
64: struct rofftree {
1.5 kristaps 65: struct roffnode *last; /* Last parsed node. */
1.32 kristaps 66: char *cur; /* Line start. */
1.30 kristaps 67: struct tm tm; /* `Dd' results. */
1.42 kristaps 68: char name[64]; /* `Nm' results. */
1.5 kristaps 69: char os[64]; /* `Os' results. */
70: char title[64]; /* `Dt' results. */
1.51 kristaps 71: enum roffmsec section;
1.58 kristaps 72: enum roffvol volume;
1.32 kristaps 73: struct roffcb cb; /* Callbacks. */
74: void *arg; /* Callbacks' arg. */
1.52 kristaps 75: int csec; /* Current section. */
76: int asec; /* Thus-far sections. */
1.64 ! kristaps 77: int literal; /* Literal mode. */
1.1 kristaps 78: };
79:
1.4 kristaps 80: static struct roffnode *roffnode_new(int, struct rofftree *);
1.15 kristaps 81: static void roffnode_free(struct rofftree *);
1.55 kristaps 82: static int roff_warn(const struct rofftree *,
1.12 kristaps 83: const char *, char *, ...);
1.55 kristaps 84: static int roff_warnp(const struct rofftree *,
85: const char *, int, enum rofferr);
86: static int roff_err(const struct rofftree *,
1.12 kristaps 87: const char *, char *, ...);
1.55 kristaps 88: static int roff_errp(const struct rofftree *,
89: const char *, int, enum rofferr);
1.31 kristaps 90: static int roffpurgepunct(struct rofftree *, char **);
1.7 kristaps 91: static int roffscan(int, const int *);
1.1 kristaps 92: static int rofffindtok(const char *);
93: static int rofffindarg(const char *);
1.2 kristaps 94: static int rofffindcallable(const char *);
1.51 kristaps 95: static int roffispunct(const char *);
1.52 kristaps 96: static int roffchecksec(struct rofftree *,
1.61 kristaps 97: const char *, int, int);
1.10 kristaps 98: static int roffargs(const struct rofftree *,
99: int, char *, char **);
1.5 kristaps 100: static int roffargok(int, int);
1.12 kristaps 101: static int roffnextopt(const struct rofftree *,
1.18 kristaps 102: int, char ***, char **);
1.27 kristaps 103: static int roffparseopts(struct rofftree *, int,
104: char ***, int *, char **);
1.33 kristaps 105: static int roffcall(struct rofftree *, int, char **);
1.51 kristaps 106: static int roffexit(struct rofftree *, int);
1.17 kristaps 107: static int roffparse(struct rofftree *, char *);
1.37 kristaps 108: static int textparse(struct rofftree *, char *);
109: static int roffdata(struct rofftree *, int, char *);
1.44 kristaps 110: static int roffspecial(struct rofftree *, int,
1.47 kristaps 111: const char *, const int *,
112: const char **, size_t, char **);
1.42 kristaps 113: static int roffsetname(struct rofftree *, char **);
1.1 kristaps 114:
1.35 kristaps 115: #ifdef __linux__
116: extern size_t strlcat(char *, const char *, size_t);
117: extern size_t strlcpy(char *, const char *, size_t);
1.33 kristaps 118: extern int vsnprintf(char *, size_t,
119: const char *, va_list);
120: extern char *strptime(const char *, const char *,
121: struct tm *);
122: #endif
123:
1.1 kristaps 124: int
125: roff_free(struct rofftree *tree, int flush)
126: {
1.16 kristaps 127: int error, t;
1.15 kristaps 128: struct roffnode *n;
1.1 kristaps 129:
1.17 kristaps 130: error = 0;
131:
1.16 kristaps 132: if ( ! flush)
133: goto end;
1.1 kristaps 134:
1.16 kristaps 135: error = 1;
1.1 kristaps 136:
1.61 kristaps 137: if ( ! (ROFFSec_NAME & tree->asec)) {
1.54 kristaps 138: (void)roff_err(tree, NULL, "missing `NAME' section");
1.52 kristaps 139: goto end;
140: } else if ( ! (ROFFSec_NMASK & tree->asec))
1.55 kristaps 141: (void)roff_warn(tree, NULL, "missing suggested `NAME', "
1.52 kristaps 142: "`SYNOPSIS', `DESCRIPTION' sections");
1.16 kristaps 143:
1.28 kristaps 144: for (n = tree->last; n; n = n->parent) {
1.16 kristaps 145: if (0 != tokens[n->tok].ctx)
1.17 kristaps 146: continue;
1.54 kristaps 147: (void)roff_err(tree, NULL, "closing explicit scope "
148: "`%s'", toknames[n->tok]);
1.16 kristaps 149: goto end;
150: }
151:
152: while (tree->last) {
153: t = tree->last->tok;
1.51 kristaps 154: if ( ! roffexit(tree, t))
1.16 kristaps 155: goto end;
1.1 kristaps 156: }
157:
1.59 kristaps 158: if ( ! (*tree->cb.rofftail)(tree->arg, &tree->tm,
159: tree->os, tree->title,
160: tree->section, tree->volume))
1.30 kristaps 161: goto end;
162:
1.16 kristaps 163: error = 0;
164:
165: end:
166:
1.15 kristaps 167: while (tree->last)
168: roffnode_free(tree);
169:
1.1 kristaps 170: free(tree);
1.17 kristaps 171:
1.1 kristaps 172: return(error ? 0 : 1);
173: }
174:
175:
176: struct rofftree *
1.15 kristaps 177: roff_alloc(const struct roffcb *cb, void *args)
1.1 kristaps 178: {
179: struct rofftree *tree;
180:
1.17 kristaps 181: assert(args);
182: assert(cb);
183:
1.12 kristaps 184: if (NULL == (tree = calloc(1, sizeof(struct rofftree))))
185: err(1, "calloc");
1.1 kristaps 186:
1.15 kristaps 187: tree->arg = args;
1.51 kristaps 188: tree->section = ROFF_MSEC_MAX;
1.15 kristaps 189:
190: (void)memcpy(&tree->cb, cb, sizeof(struct roffcb));
1.1 kristaps 191:
192: return(tree);
193: }
194:
195:
196: int
1.17 kristaps 197: roff_engine(struct rofftree *tree, char *buf)
1.1 kristaps 198: {
199:
1.17 kristaps 200: tree->cur = buf;
201: assert(buf);
1.12 kristaps 202:
1.54 kristaps 203: if (0 == *buf)
204: return(roff_err(tree, buf, "blank line"));
205: else if ('.' != *buf)
1.17 kristaps 206: return(textparse(tree, buf));
1.1 kristaps 207:
1.17 kristaps 208: return(roffparse(tree, buf));
1.1 kristaps 209: }
210:
211:
212: static int
1.37 kristaps 213: textparse(struct rofftree *tree, char *buf)
1.1 kristaps 214: {
1.37 kristaps 215: char *bufp;
216:
217: /* TODO: literal parsing. */
1.17 kristaps 218:
1.61 kristaps 219: if ( ! (ROFFSec_NAME & tree->asec))
220: return(roff_err(tree, buf, "data before `NAME' section"));
1.37 kristaps 221:
1.64 ! kristaps 222: if (tree->literal)
! 223: return(roffdata(tree, 0, buf));
! 224:
1.37 kristaps 225: /* LINTED */
226: while (*buf) {
227: while (*buf && isspace(*buf))
228: buf++;
229:
230: if (0 == *buf)
231: break;
232:
233: bufp = buf++;
234:
235: while (*buf && ! isspace(*buf))
236: buf++;
237:
238: if (0 != *buf) {
239: *buf++ = 0;
240: if ( ! roffdata(tree, 1, bufp))
241: return(0);
242: continue;
243: }
244:
245: if ( ! roffdata(tree, 1, bufp))
246: return(0);
247: break;
248: }
249:
250: return(1);
1.1 kristaps 251: }
252:
253:
254: static int
1.10 kristaps 255: roffargs(const struct rofftree *tree,
256: int tok, char *buf, char **argv)
1.1 kristaps 257: {
258: int i;
1.12 kristaps 259: char *p;
1.1 kristaps 260:
261: assert(tok >= 0 && tok < ROFF_MAX);
262: assert('.' == *buf);
263:
1.12 kristaps 264: p = buf;
265:
1.40 kristaps 266: /*
267: * This is an ugly little loop. It parses a line into
268: * space-delimited tokens. If a quote mark is encountered, a
269: * token is alloted the entire quoted text. If whitespace is
270: * escaped, it's included in the prior alloted token.
271: */
272:
1.1 kristaps 273: /* LINTED */
1.37 kristaps 274: for (i = 0; *buf && i < ROFF_MAXLINEARG; i++) {
1.10 kristaps 275: if ('\"' == *buf) {
276: argv[i] = ++buf;
277: while (*buf && '\"' != *buf)
278: buf++;
1.54 kristaps 279: if (0 == *buf)
280: return(roff_err(tree, argv[i],
281: "unclosed quote in arg list"));
1.10 kristaps 282: } else {
283: argv[i] = buf++;
1.40 kristaps 284: while (*buf) {
285: if ( ! isspace(*buf)) {
286: buf++;
287: continue;
288: }
289: if (*(buf - 1) == '\\') {
290: buf++;
291: continue;
292: }
293: break;
294: }
1.10 kristaps 295: if (0 == *buf)
296: continue;
1.1 kristaps 297: }
298: *buf++ = 0;
299: while (*buf && isspace(*buf))
300: buf++;
301: }
1.40 kristaps 302:
1.1 kristaps 303: assert(i > 0);
1.54 kristaps 304: if (ROFF_MAXLINEARG == i && *buf)
305: return(roff_err(tree, p, "too many args"));
1.10 kristaps 306:
307: argv[i] = NULL;
308: return(1);
1.1 kristaps 309: }
310:
311:
1.6 kristaps 312: static int
313: roffscan(int tok, const int *tokv)
314: {
1.7 kristaps 315:
1.6 kristaps 316: if (NULL == tokv)
317: return(1);
318:
1.7 kristaps 319: for ( ; ROFF_MAX != *tokv; tokv++)
1.6 kristaps 320: if (tok == *tokv)
321: return(1);
322:
323: return(0);
324: }
325:
326:
1.1 kristaps 327: static int
1.17 kristaps 328: roffparse(struct rofftree *tree, char *buf)
1.1 kristaps 329: {
330: int tok, t;
1.6 kristaps 331: struct roffnode *n;
1.37 kristaps 332: char *argv[ROFF_MAXLINEARG];
1.18 kristaps 333: char **argvp;
1.1 kristaps 334:
1.25 kristaps 335: if (0 != *buf && 0 != *(buf + 1) && 0 != *(buf + 2))
336: if (0 == strncmp(buf, ".\\\"", 3))
337: return(1);
338:
1.54 kristaps 339: if (ROFF_MAX == (tok = rofffindtok(buf + 1)))
340: return(roff_err(tree, buf, "bogus line macro"));
341: else if ( ! roffargs(tree, tok, buf, argv))
1.1 kristaps 342: return(0);
1.12 kristaps 343:
1.18 kristaps 344: argvp = (char **)argv;
1.6 kristaps 345:
346: /*
1.12 kristaps 347: * Prelude macros break some assumptions, so branch now.
1.6 kristaps 348: */
1.1 kristaps 349:
1.61 kristaps 350: if ( ! (ROFFSec_PR_Dd & tree->asec)) {
1.6 kristaps 351: assert(NULL == tree->last);
1.51 kristaps 352: return(roffcall(tree, tok, argvp));
1.28 kristaps 353: }
1.6 kristaps 354:
355: /*
356: * First check that our possible parents and parent's possible
357: * children are satisfied.
358: */
359:
1.28 kristaps 360: if (tree->last && ! roffscan
1.54 kristaps 361: (tree->last->tok, tokens[tok].parents))
362: return(roff_err(tree, *argvp, "`%s' has invalid "
363: "parent `%s'", toknames[tok],
364: toknames[tree->last->tok]));
1.6 kristaps 365:
1.28 kristaps 366: if (tree->last && ! roffscan
1.54 kristaps 367: (tok, tokens[tree->last->tok].children))
368: return(roff_err(tree, *argvp, "`%s' has invalid "
369: "child `%s'", toknames[tok],
370: toknames[tree->last->tok]));
1.1 kristaps 371:
372: /*
1.6 kristaps 373: * Branch if we're not a layout token.
1.1 kristaps 374: */
375:
1.6 kristaps 376: if (ROFF_LAYOUT != tokens[tok].type)
1.51 kristaps 377: return(roffcall(tree, tok, argvp));
1.6 kristaps 378: if (0 == tokens[tok].ctx)
1.51 kristaps 379: return(roffcall(tree, tok, argvp));
1.1 kristaps 380:
1.12 kristaps 381: /*
382: * First consider implicit-end tags, like as follows:
383: * .Sh SECTION 1
384: * .Sh SECTION 2
385: * In this, we want to close the scope of the NAME section. If
386: * there's an intermediary implicit-end tag, such as
387: * .Sh SECTION 1
388: * .Ss Subsection 1
389: * .Sh SECTION 2
390: * then it must be closed as well.
391: */
392:
1.6 kristaps 393: if (tok == tokens[tok].ctx) {
1.12 kristaps 394: /*
395: * First search up to the point where we must close.
396: * If one doesn't exist, then we can open a new scope.
397: */
398:
1.6 kristaps 399: for (n = tree->last; n; n = n->parent) {
400: assert(0 == tokens[n->tok].ctx ||
401: n->tok == tokens[n->tok].ctx);
402: if (n->tok == tok)
403: break;
1.10 kristaps 404: if (ROFF_SHALLOW & tokens[tok].flags) {
405: n = NULL;
406: break;
407: }
1.28 kristaps 408: if (tokens[n->tok].ctx == n->tok)
409: continue;
1.54 kristaps 410: return(roff_err(tree, *argv, "`%s' breaks "
411: "scope of prior`%s'",
412: toknames[tok],
413: toknames[n->tok]));
1.6 kristaps 414: }
1.10 kristaps 415:
416: /*
417: * Create a new scope, as no previous one exists to
418: * close out.
419: */
1.12 kristaps 420:
421: if (NULL == n)
1.51 kristaps 422: return(roffcall(tree, tok, argvp));
1.10 kristaps 423:
424: /*
1.12 kristaps 425: * Close out all intermediary scoped blocks, then hang
426: * the current scope from our predecessor's parent.
1.10 kristaps 427: */
428:
1.1 kristaps 429: do {
430: t = tree->last->tok;
1.51 kristaps 431: if ( ! roffexit(tree, t))
1.1 kristaps 432: return(0);
433: } while (t != tok);
1.6 kristaps 434:
1.51 kristaps 435: return(roffcall(tree, tok, argvp));
1.1 kristaps 436: }
437:
1.12 kristaps 438: /*
439: * Now consider explicit-end tags, where we want to close back
440: * to a specific tag. Example:
441: * .Bl
442: * .It Item.
443: * .El
444: * In this, the `El' tag closes out the scope of `Bl'.
445: */
446:
1.6 kristaps 447: assert(tok != tokens[tok].ctx && 0 != tokens[tok].ctx);
448:
1.32 kristaps 449: /* LINTED */
1.28 kristaps 450: for (n = tree->last; n; n = n->parent)
451: if (n->tok != tokens[tok].ctx) {
452: if (n->tok == tokens[n->tok].ctx)
453: continue;
1.54 kristaps 454: return(roff_err(tree, *argv, "`%s' breaks "
455: "scope of prior `%s'",
456: toknames[tok],
457: toknames[n->tok]));
1.28 kristaps 458: } else
459: break;
460:
1.54 kristaps 461: if (NULL == n)
462: return(roff_err(tree, *argv, "`%s' has no starting "
463: "tag `%s'", toknames[tok],
464: toknames[tokens[tok].ctx]));
1.28 kristaps 465:
1.14 kristaps 466: /* LINTED */
1.6 kristaps 467: do {
468: t = tree->last->tok;
1.51 kristaps 469: if ( ! roffexit(tree, t))
1.6 kristaps 470: return(0);
471: } while (t != tokens[tok].ctx);
1.1 kristaps 472:
1.9 kristaps 473: return(1);
1.1 kristaps 474: }
475:
476:
477: static int
478: rofffindarg(const char *name)
479: {
480: size_t i;
481:
482: /* FIXME: use a table, this is slow but ok for now. */
483:
484: /* LINTED */
485: for (i = 0; i < ROFF_ARGMAX; i++)
486: /* LINTED */
1.4 kristaps 487: if (0 == strcmp(name, tokargnames[i]))
1.1 kristaps 488: return((int)i);
489:
490: return(ROFF_ARGMAX);
491: }
492:
493:
494: static int
1.6 kristaps 495: rofffindtok(const char *buf)
1.1 kristaps 496: {
1.6 kristaps 497: char token[4];
1.23 kristaps 498: int i;
1.1 kristaps 499:
1.6 kristaps 500: for (i = 0; *buf && ! isspace(*buf) && i < 3; i++, buf++)
501: token[i] = *buf;
502:
1.9 kristaps 503: if (i == 3)
1.6 kristaps 504: return(ROFF_MAX);
505:
506: token[i] = 0;
507:
1.1 kristaps 508: /* FIXME: use a table, this is slow but ok for now. */
509:
510: /* LINTED */
511: for (i = 0; i < ROFF_MAX; i++)
512: /* LINTED */
1.12 kristaps 513: if (0 == strcmp(toknames[i], token))
1.1 kristaps 514: return((int)i);
1.7 kristaps 515:
1.1 kristaps 516: return(ROFF_MAX);
517: }
518:
519:
1.20 kristaps 520: static int
1.61 kristaps 521: roffchecksec(struct rofftree *tree,
522: const char *start, int sec, int fail)
1.52 kristaps 523: {
524:
525: switch (sec) {
1.61 kristaps 526: case(ROFFSec_PR_Dd):
527: return(1);
528: case(ROFFSec_PR_Dt):
529: if (ROFFSec_PR_Dd & tree->asec)
530: return(1);
531: break;
532: case(ROFFSec_PR_Os):
533: if (ROFFSec_PR_Dt & tree->asec)
534: return(1);
535: break;
536: case(ROFFSec_NAME):
537: if (ROFFSec_PR_Os & tree->asec)
538: return(1);
539: break;
1.52 kristaps 540: case(ROFFSec_SYNOP):
1.60 kristaps 541: if (ROFFSec_NAME & tree->asec)
1.52 kristaps 542: return(1);
543: break;
544: case(ROFFSec_DESC):
1.60 kristaps 545: if (ROFFSec_SYNOP & tree->asec)
1.52 kristaps 546: return(1);
547: break;
548: case(ROFFSec_RETVAL):
1.60 kristaps 549: if (ROFFSec_DESC & tree->asec)
1.52 kristaps 550: return(1);
551: break;
552: case(ROFFSec_ENV):
1.60 kristaps 553: if (ROFFSec_RETVAL & tree->asec)
1.52 kristaps 554: return(1);
555: break;
556: case(ROFFSec_FILES):
1.60 kristaps 557: if (ROFFSec_ENV & tree->asec)
1.52 kristaps 558: return(1);
559: break;
560: case(ROFFSec_EX):
1.60 kristaps 561: if (ROFFSec_FILES & tree->asec)
1.52 kristaps 562: return(1);
563: break;
564: case(ROFFSec_DIAG):
1.60 kristaps 565: if (ROFFSec_EX & tree->asec)
1.52 kristaps 566: return(1);
567: break;
568: case(ROFFSec_ERRS):
1.60 kristaps 569: if (ROFFSec_DIAG & tree->asec)
1.52 kristaps 570: return(1);
571: break;
572: case(ROFFSec_SEEALSO):
1.60 kristaps 573: if (ROFFSec_ERRS & tree->asec)
1.52 kristaps 574: return(1);
575: break;
576: case(ROFFSec_STAND):
1.60 kristaps 577: if (ROFFSec_SEEALSO & tree->asec)
1.52 kristaps 578: return(1);
579: break;
580: case(ROFFSec_HIST):
1.60 kristaps 581: if (ROFFSec_STAND & tree->asec)
1.52 kristaps 582: return(1);
583: break;
584: case(ROFFSec_AUTH):
1.60 kristaps 585: if (ROFFSec_HIST & tree->asec)
1.52 kristaps 586: return(1);
587: break;
588: case(ROFFSec_CAVEATS):
1.60 kristaps 589: if (ROFFSec_AUTH & tree->asec)
1.52 kristaps 590: return(1);
591: break;
592: case(ROFFSec_BUGS):
1.60 kristaps 593: if (ROFFSec_CAVEATS & tree->asec)
1.52 kristaps 594: return(1);
595: break;
596: default:
597: return(1);
598: }
599:
1.61 kristaps 600: if (fail)
601: return(0);
1.55 kristaps 602: return(roff_warnp(tree, start, ROFF_Sh, WRN_SECORD));
1.53 kristaps 603: }
604:
605:
606: static int
1.20 kristaps 607: roffispunct(const char *p)
608: {
609:
610: if (0 == *p)
611: return(0);
612: if (0 != *(p + 1))
613: return(0);
614:
615: switch (*p) {
616: case('{'):
617: /* FALLTHROUGH */
618: case('.'):
619: /* FALLTHROUGH */
620: case(','):
621: /* FALLTHROUGH */
622: case(';'):
623: /* FALLTHROUGH */
624: case(':'):
625: /* FALLTHROUGH */
626: case('?'):
627: /* FALLTHROUGH */
628: case('!'):
629: /* FALLTHROUGH */
630: case('('):
631: /* FALLTHROUGH */
632: case(')'):
633: /* FALLTHROUGH */
634: case('['):
635: /* FALLTHROUGH */
636: case(']'):
637: /* FALLTHROUGH */
638: case('}'):
639: return(1);
640: default:
641: break;
642: }
643:
644: return(0);
645: }
646:
647:
1.2 kristaps 648: static int
649: rofffindcallable(const char *name)
650: {
651: int c;
652:
653: if (ROFF_MAX == (c = rofffindtok(name)))
654: return(ROFF_MAX);
1.8 kristaps 655: assert(c >= 0 && c < ROFF_MAX);
1.2 kristaps 656: return(ROFF_CALLABLE & tokens[c].flags ? c : ROFF_MAX);
657: }
658:
659:
1.1 kristaps 660: static struct roffnode *
1.4 kristaps 661: roffnode_new(int tokid, struct rofftree *tree)
1.1 kristaps 662: {
663: struct roffnode *p;
664:
1.12 kristaps 665: if (NULL == (p = malloc(sizeof(struct roffnode))))
666: err(1, "malloc");
1.1 kristaps 667:
668: p->tok = tokid;
669: p->parent = tree->last;
670: tree->last = p;
1.9 kristaps 671:
1.1 kristaps 672: return(p);
673: }
674:
675:
1.5 kristaps 676: static int
677: roffargok(int tokid, int argid)
678: {
679: const int *c;
680:
681: if (NULL == (c = tokens[tokid].args))
682: return(0);
683:
684: for ( ; ROFF_ARGMAX != *c; c++)
685: if (argid == *c)
686: return(1);
687:
688: return(0);
689: }
690:
691:
1.1 kristaps 692: static void
1.15 kristaps 693: roffnode_free(struct rofftree *tree)
1.1 kristaps 694: {
695: struct roffnode *p;
696:
697: assert(tree->last);
698:
699: p = tree->last;
700: tree->last = tree->last->parent;
701: free(p);
702: }
703:
704:
1.6 kristaps 705: static int
1.47 kristaps 706: roffspecial(struct rofftree *tree, int tok, const char *start,
707: const int *argc, const char **argv,
708: size_t sz, char **ordp)
1.40 kristaps 709: {
710:
1.44 kristaps 711: switch (tok) {
1.46 kristaps 712: case (ROFF_At):
713: if (0 == sz)
714: break;
1.56 kristaps 715: if (ROFF_ATT_MAX != roff_att(*ordp))
1.46 kristaps 716: break;
1.55 kristaps 717: return(roff_errp(tree, *ordp, tok, ERR_BADARG));
1.49 kristaps 718:
1.50 kristaps 719: case (ROFF_Xr):
1.51 kristaps 720: if (2 == sz) {
721: assert(ordp[1]);
1.55 kristaps 722: if (ROFF_MSEC_MAX != roff_msec(ordp[1]))
1.51 kristaps 723: break;
1.55 kristaps 724: if ( ! roff_warn(tree, start, "invalid `%s' manual "
725: "section", toknames[tok]))
726: return(0);
1.51 kristaps 727: }
1.50 kristaps 728: /* FALLTHROUGH */
1.51 kristaps 729:
1.52 kristaps 730: case (ROFF_Sx):
731: /* FALLTHROUGH*/
1.49 kristaps 732: case (ROFF_Fn):
733: if (0 != sz)
734: break;
1.55 kristaps 735: return(roff_errp(tree, start, tok, ERR_ARGGE1));
1.46 kristaps 736:
1.44 kristaps 737: case (ROFF_Nm):
738: if (0 == sz) {
1.55 kristaps 739: if (0 != tree->name[0]) {
740: ordp[0] = tree->name;
741: ordp[1] = NULL;
742: break;
1.44 kristaps 743: }
1.55 kristaps 744: return(roff_err(tree, start, "`Nm' not set"));
1.44 kristaps 745: } else if ( ! roffsetname(tree, ordp))
746: return(0);
747: break;
748:
1.48 kristaps 749: case (ROFF_Rv):
750: /* FALLTHROUGH*/
1.44 kristaps 751: case (ROFF_Ex):
1.48 kristaps 752: if (1 == sz)
753: break;
1.55 kristaps 754: return(roff_errp(tree, start, tok, ERR_ARGEQ1));
1.44 kristaps 755:
756: case (ROFF_Sm):
1.55 kristaps 757: if (1 != sz)
758: return(roff_errp(tree, start, tok, ERR_ARGEQ1));
759: else if (0 == strcmp(ordp[0], "on") ||
760: 0 == strcmp(ordp[0], "off"))
761: break;
762: return(roff_errp(tree, *ordp, tok, ERR_BADARG));
1.45 kristaps 763:
764: case (ROFF_Ud):
765: /* FALLTHROUGH */
1.46 kristaps 766: case (ROFF_Ux):
767: /* FALLTHROUGH */
1.45 kristaps 768: case (ROFF_Bt):
1.55 kristaps 769: if (0 == sz)
770: break;
771: return(roff_errp(tree, start, tok, ERR_ARGEQ0));
1.44 kristaps 772: default:
773: break;
774: }
775:
1.50 kristaps 776: return((*tree->cb.roffspecial)(tree->arg, tok, tree->cur,
777: argc, argv, (const char **)ordp));
1.40 kristaps 778: }
779:
780:
781: static int
1.51 kristaps 782: roffexit(struct rofftree *tree, int tok)
783: {
784:
785: assert(tokens[tok].cb);
786: return((*tokens[tok].cb)(tok, tree, NULL, ROFF_EXIT));
787: }
788:
789:
790: static int
1.33 kristaps 791: roffcall(struct rofftree *tree, int tok, char **argv)
792: {
1.51 kristaps 793: int i;
794: enum roffmsec c;
1.33 kristaps 795:
1.55 kristaps 796: if (NULL == tokens[tok].cb)
797: return(roff_errp(tree, *argv, tok, ERR_NOTSUP));
798:
1.51 kristaps 799: if (tokens[tok].sections && ROFF_MSEC_MAX != tree->section) {
800: i = 0;
801: while (ROFF_MSEC_MAX !=
802: (c = tokens[tok].sections[i++]))
803: if (c == tree->section)
804: break;
805: if (ROFF_MSEC_MAX == c) {
1.55 kristaps 806: if ( ! roff_warn(tree, *argv, "`%s' is not a valid "
1.51 kristaps 807: "macro in this manual section",
1.55 kristaps 808: toknames[tok]))
809: return(0);
1.51 kristaps 810: }
811: }
812:
813: return((*tokens[tok].cb)(tok, tree, argv, ROFF_ENTER));
1.33 kristaps 814: }
815:
816:
817: static int
1.12 kristaps 818: roffnextopt(const struct rofftree *tree, int tok,
1.18 kristaps 819: char ***in, char **val)
1.6 kristaps 820: {
1.18 kristaps 821: char *arg, **argv;
1.6 kristaps 822: int v;
823:
824: *val = NULL;
825: argv = *in;
826: assert(argv);
827:
828: if (NULL == (arg = *argv))
829: return(-1);
830: if ('-' != *arg)
831: return(-1);
832:
1.12 kristaps 833: if (ROFF_ARGMAX == (v = rofffindarg(arg + 1))) {
1.55 kristaps 834: if ( ! roff_warn(tree, arg, "argument-like parameter `%s' to "
835: "`%s'", arg, toknames[tok]))
836: return(ROFF_ARGMAX);
1.6 kristaps 837: return(-1);
1.12 kristaps 838: }
839:
840: if ( ! roffargok(tok, v)) {
1.55 kristaps 841: if ( ! roff_warn(tree, arg, "invalid argument parameter `%s' to "
842: "`%s'", tokargnames[v], toknames[tok]))
843: return(ROFF_ARGMAX);
1.6 kristaps 844: return(-1);
1.12 kristaps 845: }
846:
847: if ( ! (ROFF_VALUE & tokenargs[v]))
1.6 kristaps 848: return(v);
849:
850: *in = ++argv;
851:
1.12 kristaps 852: if (NULL == *argv) {
1.55 kristaps 853: (void)roff_err(tree, arg, "empty value of `%s' for `%s'",
1.12 kristaps 854: tokargnames[v], toknames[tok]);
855: return(ROFF_ARGMAX);
856: }
1.6 kristaps 857:
1.12 kristaps 858: return(v);
1.6 kristaps 859: }
860:
861:
1.27 kristaps 862: static int
1.31 kristaps 863: roffpurgepunct(struct rofftree *tree, char **argv)
864: {
865: int i;
866:
867: i = 0;
868: while (argv[i])
869: i++;
870: assert(i > 0);
871: if ( ! roffispunct(argv[--i]))
872: return(1);
873: while (i >= 0 && roffispunct(argv[i]))
874: i--;
875: i++;
876:
877: /* LINTED */
878: while (argv[i])
1.37 kristaps 879: if ( ! roffdata(tree, 0, argv[i++]))
1.31 kristaps 880: return(0);
881: return(1);
882: }
883:
884:
885: static int
1.27 kristaps 886: roffparseopts(struct rofftree *tree, int tok,
887: char ***args, int *argc, char **argv)
888: {
889: int i, c;
890: char *v;
891:
892: i = 0;
893:
894: while (-1 != (c = roffnextopt(tree, tok, args, &v))) {
895: if (ROFF_ARGMAX == c)
896: return(0);
897:
898: argc[i] = c;
899: argv[i] = v;
900: i++;
901: *args = *args + 1;
902: }
903:
904: argc[i] = ROFF_ARGMAX;
905: argv[i] = NULL;
906: return(1);
907: }
908:
909:
1.37 kristaps 910: static int
911: roffdata(struct rofftree *tree, int space, char *buf)
912: {
913:
1.38 kristaps 914: if (0 == *buf)
915: return(1);
1.37 kristaps 916: return((*tree->cb.roffdata)(tree->arg,
917: space != 0, tree->cur, buf));
918: }
919:
920:
1.1 kristaps 921: /* ARGSUSED */
922: static int
923: roff_Dd(ROFFCALL_ARGS)
924: {
1.30 kristaps 925: time_t t;
926: char *p, buf[32];
1.55 kristaps 927: size_t sz;
1.1 kristaps 928:
1.61 kristaps 929: if (ROFFSec_PR_Os & tree->asec)
1.4 kristaps 930: return(roff_text(tok, tree, argv, type));
1.61 kristaps 931: if (ROFFSec_PR_Dd & tree->asec)
1.55 kristaps 932: return(roff_errp(tree, *argv, tok, ERR_PR_REP));
1.61 kristaps 933: if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Dd, 1))
1.55 kristaps 934: return(roff_errp(tree, *argv, tok, ERR_PR_OOO));
1.1 kristaps 935:
1.30 kristaps 936: assert(NULL == tree->last);
937: argv++;
1.61 kristaps 938: tree->asec |= (tree->csec = ROFFSec_PR_Dd);
1.30 kristaps 939:
1.55 kristaps 940: /*
941: * This is a bit complex because there are many forms the date
942: * can be in: it can be simply $Mdocdate$, $Mdocdate <date>$,
943: * or a raw date. Process accordingly.
944: */
945:
1.30 kristaps 946: if (0 == strcmp(*argv, "$Mdocdate$")) {
947: t = time(NULL);
948: if (NULL == localtime_r(&t, &tree->tm))
949: err(1, "localtime_r");
950: return(1);
951: }
952:
953: buf[0] = 0;
954: p = *argv;
1.55 kristaps 955: sz = sizeof(buf);
1.30 kristaps 956:
957: if (0 != strcmp(*argv, "$Mdocdate:")) {
958: while (*argv) {
1.55 kristaps 959: if (strlcat(buf, *argv++, sz) < sz)
1.30 kristaps 960: continue;
1.55 kristaps 961: return(roff_errp(tree, p, tok, ERR_BADARG));
1.30 kristaps 962: }
1.61 kristaps 963: if (strptime(buf, "%b%d,%Y", &tree->tm))
1.30 kristaps 964: return(1);
1.55 kristaps 965: return(roff_errp(tree, p, tok, ERR_BADARG));
1.30 kristaps 966: }
967:
968: argv++;
1.55 kristaps 969:
1.30 kristaps 970: while (*argv && **argv != '$') {
1.55 kristaps 971: if (strlcat(buf, *argv++, sz) >= sz)
972: return(roff_errp(tree, p, tok, ERR_BADARG));
973: if (strlcat(buf, " ", sz) >= sz)
974: return(roff_errp(tree, p, tok, ERR_BADARG));
1.30 kristaps 975: }
976:
1.55 kristaps 977: if (NULL == *argv)
978: return(roff_errp(tree, p, tok, ERR_BADARG));
979: if (NULL == strptime(buf, "%b %d %Y", &tree->tm))
980: return(roff_errp(tree, p, tok, ERR_BADARG));
1.4 kristaps 981:
1.1 kristaps 982: return(1);
983: }
984:
985:
986: /* ARGSUSED */
987: static int
988: roff_Dt(ROFFCALL_ARGS)
989: {
1.55 kristaps 990: size_t sz;
1.1 kristaps 991:
1.61 kristaps 992: if (ROFFSec_PR_Os & tree->asec)
1.4 kristaps 993: return(roff_text(tok, tree, argv, type));
1.61 kristaps 994: if (ROFFSec_PR_Dt & tree->asec)
995: return(roff_errp(tree, *argv, tok, ERR_PR_REP));
996: if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Dt, 1))
1.55 kristaps 997: return(roff_errp(tree, *argv, tok, ERR_PR_OOO));
1.1 kristaps 998:
1.30 kristaps 999: argv++;
1.61 kristaps 1000: tree->asec |= (tree->csec = ROFFSec_PR_Dt);
1.55 kristaps 1001: sz = sizeof(tree->title);
1002:
1003: if (NULL == *argv)
1004: return(roff_errp(tree, *argv, tok, ERR_ARGGE2));
1005: if (strlcpy(tree->title, *argv, sz) >= sz)
1006: return(roff_errp(tree, *argv, tok, ERR_ARGLEN));
1.30 kristaps 1007:
1008: argv++;
1.55 kristaps 1009: if (NULL == *argv)
1010: return(roff_errp(tree, *argv, tok, ERR_ARGGE2));
1.51 kristaps 1011:
1.55 kristaps 1012: if (ROFF_MSEC_MAX == (tree->section = roff_msec(*argv)))
1013: return(roff_errp(tree, *argv, tok, ERR_BADARG));
1.30 kristaps 1014:
1015: argv++;
1.55 kristaps 1016:
1.30 kristaps 1017: if (NULL == *argv) {
1.58 kristaps 1018: switch (tree->section) {
1019: case(ROFF_MSEC_1):
1020: /* FALLTHROUGH */
1021: case(ROFF_MSEC_6):
1022: /* FALLTHROUGH */
1023: case(ROFF_MSEC_7):
1024: tree->volume = ROFF_VOL_URM;
1025: break;
1026: case(ROFF_MSEC_2):
1027: /* FALLTHROUGH */
1028: case(ROFF_MSEC_3):
1029: /* FALLTHROUGH */
1030: case(ROFF_MSEC_3p):
1031: /* FALLTHROUGH */
1032: case(ROFF_MSEC_4):
1033: /* FALLTHROUGH */
1034: case(ROFF_MSEC_5):
1035: tree->volume = ROFF_VOL_PRM;
1036: break;
1037: case(ROFF_MSEC_8):
1038: tree->volume = ROFF_VOL_PRM;
1039: break;
1040: case(ROFF_MSEC_9):
1041: tree->volume = ROFF_VOL_KM;
1042: break;
1043: case(ROFF_MSEC_UNASS):
1044: /* FALLTHROUGH */
1045: case(ROFF_MSEC_DRAFT):
1046: /* FALLTHROUGH */
1047: case(ROFF_MSEC_PAPER):
1048: tree->volume = ROFF_VOL_NONE;
1049: break;
1050: default:
1051: abort();
1052: /* NOTREACHED */
1053: }
1054: } else if (ROFF_VOL_MAX == (tree->volume = roff_vol(*argv)))
1055: return(roff_errp(tree, *argv, tok, ERR_BADARG));
1.4 kristaps 1056:
1.1 kristaps 1057: assert(NULL == tree->last);
1058:
1059: return(1);
1060: }
1061:
1062:
1.42 kristaps 1063: static int
1064: roffsetname(struct rofftree *tree, char **ordp)
1065: {
1.55 kristaps 1066: size_t sz;
1.42 kristaps 1067:
1068: assert(*ordp);
1069:
1070: /* FIXME: not all sections can set this. */
1071:
1.55 kristaps 1072: if (NULL != *(ordp + 1))
1073: return(roff_errp(tree, *ordp, ROFF_Nm, ERR_ARGMNY));
1.42 kristaps 1074:
1.55 kristaps 1075: sz = sizeof(tree->name);
1076: if (strlcpy(tree->name, *ordp, sz) >= sz)
1077: return(roff_errp(tree, *ordp, ROFF_Nm, ERR_ARGLEN));
1.42 kristaps 1078:
1079: return(1);
1080: }
1081:
1082:
1.1 kristaps 1083: /* ARGSUSED */
1.33 kristaps 1084: static int
1085: roff_Ns(ROFFCALL_ARGS)
1086: {
1087: int j, c, first;
1.40 kristaps 1088: char *morep[1];
1.33 kristaps 1089:
1090: first = (*argv++ == tree->cur);
1.40 kristaps 1091: morep[0] = NULL;
1.33 kristaps 1092:
1.47 kristaps 1093: if ( ! roffspecial(tree, tok, *argv, NULL, NULL, 0, morep))
1.33 kristaps 1094: return(0);
1.31 kristaps 1095:
1.33 kristaps 1096: while (*argv) {
1097: if (ROFF_MAX != (c = rofffindcallable(*argv))) {
1098: if ( ! roffcall(tree, c, argv))
1099: return(0);
1.31 kristaps 1100: break;
1101: }
1.33 kristaps 1102:
1103: if ( ! roffispunct(*argv)) {
1.37 kristaps 1104: if ( ! roffdata(tree, 1, *argv++))
1105: return(0);
1106: continue;
1.31 kristaps 1107: }
1.37 kristaps 1108:
1.33 kristaps 1109: for (j = 0; argv[j]; j++)
1110: if ( ! roffispunct(argv[j]))
1111: break;
1112:
1113: if (argv[j]) {
1.37 kristaps 1114: if ( ! roffdata(tree, 0, *argv++))
1115: return(0);
1116: continue;
1.33 kristaps 1117: }
1118:
1.31 kristaps 1119: break;
1120: }
1121:
1122: if ( ! first)
1123: return(1);
1.33 kristaps 1124:
1.31 kristaps 1125: return(roffpurgepunct(tree, argv));
1126: }
1127:
1128:
1129: /* ARGSUSED */
1130: static int
1.1 kristaps 1131: roff_Os(ROFFCALL_ARGS)
1132: {
1.30 kristaps 1133: char *p;
1.55 kristaps 1134: size_t sz;
1.1 kristaps 1135:
1.61 kristaps 1136: if (ROFFSec_PR_Os & tree->asec)
1.4 kristaps 1137: return(roff_text(tok, tree, argv, type));
1.61 kristaps 1138: if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Os, 1))
1.55 kristaps 1139: return(roff_errp(tree, *argv, tok, ERR_PR_OOO));
1.1 kristaps 1140:
1.30 kristaps 1141: p = *++argv;
1.55 kristaps 1142: sz = sizeof(tree->os);
1.61 kristaps 1143: tree->asec |= (tree->csec = ROFFSec_PR_Os);
1144:
1145: tree->os[0] = 0;
1.30 kristaps 1146:
1.55 kristaps 1147: while (*argv)
1148: if (strlcat(tree->os, *argv++, sz) >= sz)
1149: return(roff_errp(tree, p, tok, ERR_ARGLEN));
1.30 kristaps 1150:
1151: if (0 == tree->os[0])
1.55 kristaps 1152: if (strlcpy(tree->os, "LOCAL", sz) >= sz)
1153: return(roff_errp(tree, p, tok, ERR_ARGLEN));
1.1 kristaps 1154:
1.51 kristaps 1155: assert(ROFF_MSEC_MAX != tree->section);
1156: assert(0 != tree->title[0]);
1157: assert(0 != tree->os[0]);
1158:
1.4 kristaps 1159: assert(NULL == tree->last);
1160:
1.36 kristaps 1161: return((*tree->cb.roffhead)(tree->arg, &tree->tm,
1.55 kristaps 1162: tree->os, tree->title,
1163: tree->section, tree->volume));
1.1 kristaps 1164: }
1165:
1166:
1167: /* ARGSUSED */
1168: static int
1.2 kristaps 1169: roff_layout(ROFFCALL_ARGS)
1.1 kristaps 1170: {
1.37 kristaps 1171: int i, c, argcp[ROFF_MAXLINEARG];
1.62 kristaps 1172: char *argvp[ROFF_MAXLINEARG], *p;
1.1 kristaps 1173:
1.52 kristaps 1174: /*
1175: * The roff_layout function is for multi-line macros. A layout
1176: * has a start and end point, which is either declared
1177: * explicitly or implicitly. An explicit start and end is
1178: * embodied by `.Bl' and `.El', with the former being the start
1179: * and the latter being an end. The `.Sh' and `.Ss' tags, on
1180: * the other hand, are implicit. The scope of a layout is the
1181: * space between start and end. Explicit layouts may not close
1182: * out implicit ones and vice versa; implicit layouts may close
1183: * out other implicit layouts.
1184: */
1185:
1186: assert( ! (ROFF_CALLABLE & tokens[tok].flags));
1187:
1.63 kristaps 1188: if ( ! (ROFFSec_PR_Os & tree->asec))
1.55 kristaps 1189: return(roff_errp(tree, *argv, tok, ERR_NOT_PR));
1190:
1191: if (ROFF_EXIT == type) {
1.15 kristaps 1192: roffnode_free(tree);
1.35 kristaps 1193: if ( ! (*tree->cb.roffblkbodyout)(tree->arg, tok))
1194: return(0);
1.15 kristaps 1195: return((*tree->cb.roffblkout)(tree->arg, tok));
1.2 kristaps 1196: }
1.1 kristaps 1197:
1.62 kristaps 1198: p = *argv++;
1.27 kristaps 1199: assert( ! (ROFF_CALLABLE & tokens[tok].flags));
1.5 kristaps 1200:
1.27 kristaps 1201: if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
1202: return(0);
1.4 kristaps 1203: if (NULL == roffnode_new(tok, tree))
1.2 kristaps 1204: return(0);
1205:
1.27 kristaps 1206: /*
1207: * Layouts have two parts: the layout body and header. The
1208: * layout header is the trailing text of the line macro, while
1209: * the layout body is everything following until termination.
1.52 kristaps 1210: * Example:
1211: *
1212: * .It Fl f ) ;
1213: * Bar.
1214: *
1215: * ...Produces...
1216: *
1217: * <block>
1218: * <head>
1219: * <!Fl f!> ;
1220: * </head>
1221: *
1222: * <body>
1223: * Bar.
1224: * </body>
1225: * </block>
1.27 kristaps 1226: */
1227:
1.50 kristaps 1228: if ( ! (*tree->cb.roffblkin)(tree->arg, tok, argcp,
1229: (const char **)argvp))
1.18 kristaps 1230: return(0);
1.52 kristaps 1231:
1232: /* +++ Begin run macro-specific hooks over argv. */
1233:
1234: switch (tok) {
1.64 ! kristaps 1235: case (ROFF_Bd):
! 1236: tree->literal++;
! 1237: break;
! 1238:
1.52 kristaps 1239: case (ROFF_Sh):
1240: if (NULL == *argv) {
1.55 kristaps 1241: argv--;
1242: return(roff_errp(tree, *argv, tok, ERR_ARGGE1));
1.52 kristaps 1243: }
1.55 kristaps 1244:
1245: tree->csec = roff_sec((const char **)argv);
1246:
1.52 kristaps 1247: if ( ! (ROFFSec_OTHER & tree->csec) &&
1248: tree->asec & tree->csec)
1.55 kristaps 1249: if ( ! roff_warn(tree, *argv, "section repeated"))
1250: return(0);
1251:
1252: if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec))
1253: return(roff_err(tree, *argv, "`NAME' section "
1254: "must be first"));
1.61 kristaps 1255: if ( ! roffchecksec(tree, *argv, tree->csec, 0))
1.52 kristaps 1256: return(0);
1257:
1258: tree->asec |= tree->csec;
1.62 kristaps 1259:
1260: if ( ! roffspecial(tree, tok, p, argcp,
1261: (const char **)argvp, 0, argv))
1262: return(0);
1.52 kristaps 1263: break;
1264: default:
1265: break;
1266: }
1267:
1268: /* --- End run macro-specific hooks over argv. */
1269:
1.18 kristaps 1270: if (NULL == *argv)
1.35 kristaps 1271: return((*tree->cb.roffblkbodyin)
1.50 kristaps 1272: (tree->arg, tok, argcp,
1273: (const char **)argvp));
1.35 kristaps 1274:
1.50 kristaps 1275: if ( ! (*tree->cb.roffblkheadin)(tree->arg, tok, argcp,
1276: (const char **)argvp))
1.2 kristaps 1277: return(0);
1278:
1.27 kristaps 1279: /*
1280: * If there are no parsable parts, then write remaining tokens
1281: * into the layout header and exit.
1282: */
1283:
1.2 kristaps 1284: if ( ! (ROFF_PARSED & tokens[tok].flags)) {
1.21 kristaps 1285: i = 0;
1.37 kristaps 1286: while (*argv)
1287: if ( ! roffdata(tree, i++, *argv++))
1.14 kristaps 1288: return(0);
1.37 kristaps 1289:
1.35 kristaps 1290: if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
1291: return(0);
1.52 kristaps 1292: return((*tree->cb.roffblkbodyin)(tree->arg, tok, argcp,
1.50 kristaps 1293: (const char **)argvp));
1.2 kristaps 1294: }
1295:
1.27 kristaps 1296: /*
1297: * Parsable elements may be in the header (or be the header, for
1298: * that matter). Follow the regular parsing rules for these.
1299: */
1300:
1.21 kristaps 1301: i = 0;
1.1 kristaps 1302: while (*argv) {
1.26 kristaps 1303: if (ROFF_MAX == (c = rofffindcallable(*argv))) {
1304: assert(tree->arg);
1.37 kristaps 1305: if ( ! roffdata(tree, i++, *argv++))
1.8 kristaps 1306: return(0);
1.26 kristaps 1307: continue;
1308: }
1.33 kristaps 1309: if ( ! roffcall(tree, c, argv))
1.14 kristaps 1310: return(0);
1.26 kristaps 1311: break;
1.21 kristaps 1312: }
1313:
1314: /*
1.27 kristaps 1315: * If there's trailing punctuation in the header, then write it
1316: * out now. Here we mimic the behaviour of a line-dominant text
1317: * macro.
1.21 kristaps 1318: */
1319:
1.35 kristaps 1320: if (NULL == *argv) {
1321: if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
1322: return(0);
1323: return((*tree->cb.roffblkbodyin)
1.50 kristaps 1324: (tree->arg, tok, argcp,
1325: (const char **)argvp));
1.35 kristaps 1326: }
1.21 kristaps 1327:
1.27 kristaps 1328: /*
1329: * Expensive. Scan to the end of line then work backwards until
1330: * a token isn't punctuation.
1331: */
1332:
1.31 kristaps 1333: if ( ! roffpurgepunct(tree, argv))
1334: return(0);
1.35 kristaps 1335: if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
1336: return(0);
1.52 kristaps 1337: return((*tree->cb.roffblkbodyin)(tree->arg,
1338: tok, argcp, (const char **)argvp));
1.2 kristaps 1339: }
1340:
1341:
1342: /* ARGSUSED */
1343: static int
1.40 kristaps 1344: roff_ordered(ROFFCALL_ARGS)
1345: {
1.44 kristaps 1346: int i, first, c, argcp[ROFF_MAXLINEARG];
1347: char *ordp[ROFF_MAXLINEARG], *p,
1348: *argvp[ROFF_MAXLINEARG];
1.40 kristaps 1349:
1.52 kristaps 1350: /*
1351: * Ordered macros pass their arguments directly to handlers,
1352: * instead of considering it free-form text. Thus, the
1353: * following macro looks as follows:
1354: *
1355: * .Xr foo 1 ) ,
1356: *
1357: * .Xr arg1 arg2 punctuation
1358: */
1359:
1.63 kristaps 1360: if ( ! (ROFFSec_PR_Os & tree->asec))
1.55 kristaps 1361: return(roff_errp(tree, *argv, tok, ERR_NOT_PR));
1.40 kristaps 1362:
1363: first = (*argv == tree->cur);
1.44 kristaps 1364: p = *argv++;
1.52 kristaps 1365: ordp[0] = NULL;
1.40 kristaps 1366:
1.44 kristaps 1367: if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
1368: return(0);
1.40 kristaps 1369:
1.52 kristaps 1370: if (NULL == *argv)
1.47 kristaps 1371: return(roffspecial(tree, tok, p, argcp,
1372: (const char **)argvp, 0, ordp));
1.40 kristaps 1373:
1374: i = 0;
1375: while (*argv && i < ROFF_MAXLINEARG) {
1.46 kristaps 1376: c = ROFF_PARSED & tokens[tok].flags ?
1377: rofffindcallable(*argv) : ROFF_MAX;
1.42 kristaps 1378:
1379: if (ROFF_MAX == c && ! roffispunct(*argv)) {
1380: ordp[i++] = *argv++;
1381: continue;
1382: }
1383: ordp[i] = NULL;
1384:
1385: if (ROFF_MAX == c)
1386: break;
1387:
1.47 kristaps 1388: if ( ! roffspecial(tree, tok, p, argcp,
1389: (const char **)argvp,
1390: (size_t)i, ordp))
1.42 kristaps 1391: return(0);
1.40 kristaps 1392:
1.46 kristaps 1393: return(roffcall(tree, c, argv));
1.40 kristaps 1394: }
1395:
1.42 kristaps 1396: assert(i != ROFF_MAXLINEARG);
1.40 kristaps 1397: ordp[i] = NULL;
1398:
1.47 kristaps 1399: if ( ! roffspecial(tree, tok, p, argcp,
1400: (const char**)argvp,
1401: (size_t)i, ordp))
1.40 kristaps 1402: return(0);
1403:
1404: /* FIXME: error if there's stuff after the punctuation. */
1405:
1406: if ( ! first || NULL == *argv)
1407: return(1);
1408:
1409: return(roffpurgepunct(tree, argv));
1410: }
1411:
1412:
1.64 ! kristaps 1413: static int
! 1414: macro_default(struct rofftree *tree, int tok, char *args[])
! 1415: {
! 1416: char **p;
! 1417: char *argv[ROFF_MAXLINEARG];
! 1418: int i, argc[ROFF_MAXLINEARG];
! 1419:
! 1420: if ( ! roffparseopts(tree, tok, &args, argc, argv))
! 1421: return(0);
! 1422:
! 1423: if ( ! (ROFF_PARSED & tokens[tok].flags))
! 1424: return((*tree->cb.macro)(tree->arg, tok, argc, argv, 0, args));
! 1425:
! 1426: p = args;
! 1427:
! 1428: while (*args) {
! 1429: c = rofffindcallable(*args);
! 1430: if (ROFF_MAX == c) {
! 1431: if (roffispunct(*args)) {
! 1432:
! 1433:
! 1434: }
! 1435: }
! 1436:
! 1437: if (ROFF_MAX != (c = rofffindcallable(*argv))) {
! 1438: if ( ! (ROFF_LSCOPE & tokens[tok].flags))
! 1439: if ( ! (*tree->cb.roffout)(tree->arg, tok))
! 1440: return(0);
! 1441:
! 1442: if ( ! roffcall(tree, c, argv))
! 1443: return(0);
! 1444: if (ROFF_LSCOPE & tokens[tok].flags)
! 1445: if ( ! (*tree->cb.roffout)(tree->arg, tok))
! 1446: return(0);
! 1447: break;
! 1448: }
! 1449:
! 1450: if ( ! roffispunct(*argv)) {
! 1451: if ( ! roffdata(tree, i++, *argv++))
! 1452: return(0);
! 1453: continue;
! 1454: }
! 1455:
! 1456: i = 1;
! 1457: for (j = 0; argv[j]; j++)
! 1458: if ( ! roffispunct(argv[j]))
! 1459: break;
! 1460:
! 1461: if (argv[j]) {
! 1462: if (ROFF_LSCOPE & tokens[tok].flags) {
! 1463: if ( ! roffdata(tree, 0, *argv++))
! 1464: return(0);
! 1465: continue;
! 1466: }
! 1467: if ( ! (*tree->cb.roffout)(tree->arg, tok))
! 1468: return(0);
! 1469: if ( ! roffdata(tree, 0, *argv++))
! 1470: return(0);
! 1471: if ( ! (*tree->cb.roffin)(tree->arg, tok,
! 1472: argcp,
! 1473: (const char **)argvp))
! 1474: return(0);
! 1475:
! 1476: i = 0;
! 1477: continue;
! 1478: }
! 1479:
! 1480: if ( ! (*tree->cb.roffout)(tree->arg, tok))
! 1481: return(0);
! 1482: break;
! 1483: }
! 1484: }
! 1485:
! 1486:
1.40 kristaps 1487: /* ARGSUSED */
1488: static int
1.2 kristaps 1489: roff_text(ROFFCALL_ARGS)
1490: {
1.37 kristaps 1491: int i, j, first, c, argcp[ROFF_MAXLINEARG];
1492: char *argvp[ROFF_MAXLINEARG];
1.2 kristaps 1493:
1.52 kristaps 1494: /*
1495: * Text macros are similar to special tokens, except that
1496: * arguments are instead flushed as pure data: we're only
1497: * concerned with the macro and its arguments. Example:
1498: *
1499: * .Fl v W f ;
1500: *
1501: * ...Produces...
1502: *
1503: * <fl> v W f </fl> ;
1504: */
1505:
1.63 kristaps 1506: if ( ! (ROFFSec_PR_Os & tree->asec))
1.55 kristaps 1507: return(roff_errp(tree, *argv, tok, ERR_NOT_PR));
1.4 kristaps 1508:
1.27 kristaps 1509: first = (*argv == tree->cur);
1.12 kristaps 1510: argv++;
1.5 kristaps 1511:
1.27 kristaps 1512: if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
1513: return(0);
1.50 kristaps 1514: if ( ! (*tree->cb.roffin)(tree->arg, tok, argcp,
1515: (const char **)argvp))
1.2 kristaps 1516: return(0);
1.27 kristaps 1517: if (NULL == *argv)
1518: return((*tree->cb.roffout)(tree->arg, tok));
1.1 kristaps 1519:
1.2 kristaps 1520: if ( ! (ROFF_PARSED & tokens[tok].flags)) {
1.21 kristaps 1521: i = 0;
1.37 kristaps 1522: while (*argv)
1523: if ( ! roffdata(tree, i++, *argv++))
1.14 kristaps 1524: return(0);
1.15 kristaps 1525: return((*tree->cb.roffout)(tree->arg, tok));
1.2 kristaps 1526: }
1.1 kristaps 1527:
1.27 kristaps 1528: /*
1529: * Deal with punctuation. Ugly. Work ahead until we encounter
1530: * terminating punctuation. If we encounter it and all
1531: * subsequent tokens are punctuation, then stop processing (the
1532: * line-dominant macro will print these tokens after closure).
1.49 kristaps 1533: * If the punctuation is followed by non-punctuation, then close
1534: * and re-open our scope, then continue.
1.27 kristaps 1535: */
1536:
1.21 kristaps 1537: i = 0;
1.2 kristaps 1538: while (*argv) {
1.33 kristaps 1539: if (ROFF_MAX != (c = rofffindcallable(*argv))) {
1540: if ( ! (ROFF_LSCOPE & tokens[tok].flags))
1541: if ( ! (*tree->cb.roffout)(tree->arg, tok))
1542: return(0);
1543:
1544: if ( ! roffcall(tree, c, argv))
1545: return(0);
1546: if (ROFF_LSCOPE & tokens[tok].flags)
1547: if ( ! (*tree->cb.roffout)(tree->arg, tok))
1.27 kristaps 1548: return(0);
1.33 kristaps 1549: break;
1550: }
1.21 kristaps 1551:
1.33 kristaps 1552: if ( ! roffispunct(*argv)) {
1.37 kristaps 1553: if ( ! roffdata(tree, i++, *argv++))
1.33 kristaps 1554: return(0);
1555: continue;
1556: }
1.27 kristaps 1557:
1.33 kristaps 1558: i = 1;
1559: for (j = 0; argv[j]; j++)
1560: if ( ! roffispunct(argv[j]))
1561: break;
1.27 kristaps 1562:
1.33 kristaps 1563: if (argv[j]) {
1.49 kristaps 1564: if (ROFF_LSCOPE & tokens[tok].flags) {
1565: if ( ! roffdata(tree, 0, *argv++))
1566: return(0);
1567: continue;
1568: }
1569: if ( ! (*tree->cb.roffout)(tree->arg, tok))
1570: return(0);
1.37 kristaps 1571: if ( ! roffdata(tree, 0, *argv++))
1.27 kristaps 1572: return(0);
1.50 kristaps 1573: if ( ! (*tree->cb.roffin)(tree->arg, tok,
1574: argcp,
1575: (const char **)argvp))
1.49 kristaps 1576: return(0);
1577:
1578: i = 0;
1.33 kristaps 1579: continue;
1.8 kristaps 1580: }
1.20 kristaps 1581:
1.33 kristaps 1582: if ( ! (*tree->cb.roffout)(tree->arg, tok))
1.14 kristaps 1583: return(0);
1.20 kristaps 1584: break;
1.14 kristaps 1585: }
1.12 kristaps 1586:
1.27 kristaps 1587: if (NULL == *argv)
1588: return((*tree->cb.roffout)(tree->arg, tok));
1589: if ( ! first)
1590: return(1);
1.21 kristaps 1591:
1.31 kristaps 1592: return(roffpurgepunct(tree, argv));
1.6 kristaps 1593: }
1594:
1595:
1.9 kristaps 1596: /* ARGSUSED */
1.6 kristaps 1597: static int
1.27 kristaps 1598: roff_noop(ROFFCALL_ARGS)
1.6 kristaps 1599: {
1600:
1.64 ! kristaps 1601: switch (tok) {
! 1602: case (ROFF_Ed):
! 1603: tree->literal--;
! 1604: break;
! 1605: default:
! 1606: break;
! 1607: }
! 1608:
1.6 kristaps 1609: return(1);
1.1 kristaps 1610: }
1.9 kristaps 1611:
1612:
1613: /* ARGSUSED */
1614: static int
1.27 kristaps 1615: roff_depr(ROFFCALL_ARGS)
1.9 kristaps 1616: {
1617:
1.55 kristaps 1618: return(roff_errp(tree, *argv, tok, ERR_DEPREC));
1619: }
1620:
1621:
1.64 ! kristaps 1622: /* FIXME: push this into the filter. */
1.55 kristaps 1623: static int
1624: roff_warnp(const struct rofftree *tree, const char *pos,
1625: int tok, enum rofferr type)
1626: {
1627: char *p;
1628:
1629: switch (type) {
1630: case (WRN_SECORD):
1631: p = "section at `%s' out of order";
1632: break;
1633: default:
1634: abort();
1635: /* NOTREACHED */
1636: }
1637:
1638: return(roff_warn(tree, pos, p, toknames[tok]));
1.11 kristaps 1639: }
1.12 kristaps 1640:
1641:
1.55 kristaps 1642: static int
1.12 kristaps 1643: roff_warn(const struct rofftree *tree, const char *pos, char *fmt, ...)
1644: {
1645: va_list ap;
1646: char buf[128];
1647:
1648: va_start(ap, fmt);
1649: (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1650: va_end(ap);
1651:
1.55 kristaps 1652: return((*tree->cb.roffmsg)(tree->arg,
1653: ROFF_WARN, tree->cur, pos, buf));
1654: }
1655:
1656:
1.64 ! kristaps 1657: /* FIXME: push this into the filter. */
1.55 kristaps 1658: static int
1659: roff_errp(const struct rofftree *tree, const char *pos,
1660: int tok, enum rofferr type)
1661: {
1662: char *p;
1663:
1664: switch (type) {
1665: case (ERR_ARGEQ1):
1666: p = "`%s' expects exactly one argument";
1667: break;
1668: case (ERR_ARGEQ0):
1669: p = "`%s' expects exactly zero arguments";
1670: break;
1671: case (ERR_ARGGE1):
1672: p = "`%s' expects one or more arguments";
1673: break;
1674: case (ERR_ARGGE2):
1675: p = "`%s' expects two or more arguments";
1676: break;
1677: case (ERR_BADARG):
1678: p = "invalid argument for `%s'";
1679: break;
1680: case (ERR_NOTSUP):
1681: p = "macro `%s' is not supported";
1682: break;
1683: case(ERR_PR_OOO):
1684: p = "prelude macro `%s' is out of order";
1685: break;
1686: case(ERR_PR_REP):
1687: p = "prelude macro `%s' repeated";
1688: break;
1689: case(ERR_ARGLEN):
1690: p = "macro argument for `%s' is too long";
1691: break;
1692: case(ERR_DEPREC):
1693: p = "macro `%s' is deprecated";
1694: break;
1695: case(ERR_NOT_PR):
1696: p = "macro `%s' disallowed in prelude";
1697: break;
1698: case(ERR_ARGMNY):
1699: p = "too many arguments for macro `%s'";
1700: break;
1701: default:
1702: abort();
1703: /* NOTREACHED */
1704: }
1705:
1706: return(roff_err(tree, pos, p, toknames[tok]));
1.12 kristaps 1707: }
1708:
1709:
1.55 kristaps 1710: static int
1.12 kristaps 1711: roff_err(const struct rofftree *tree, const char *pos, char *fmt, ...)
1712: {
1713: va_list ap;
1714: char buf[128];
1715:
1716: va_start(ap, fmt);
1.55 kristaps 1717: if (-1 == vsnprintf(buf, sizeof(buf), fmt, ap))
1718: err(1, "vsnprintf");
1.12 kristaps 1719: va_end(ap);
1720:
1.55 kristaps 1721: return((*tree->cb.roffmsg)
1722: (tree->arg, ROFF_ERROR, tree->cur, pos, buf));
1.12 kristaps 1723: }
1.33 kristaps 1724:
CVSweb