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