Annotation of mandoc/action.c, Revision 1.23
1.23 ! kristaps 1: /* $Id: action.c,v 1.22 2009/02/27 10:55:16 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: */
19: #include <assert.h>
1.20 kristaps 20: #include <stdio.h>
1.1 kristaps 21: #include <stdlib.h>
1.20 kristaps 22: #include <string.h>
1.5 kristaps 23: #include <time.h>
1.1 kristaps 24:
25: #include "private.h"
26:
1.14 kristaps 27: /*
28: * Actions are executed on macros after they've been post-validated: in
29: * other words, a macro will not be "acted upon" until all of its
30: * children have been filled in (post-fix order).
31: */
1.1 kristaps 32:
33: struct actions {
1.10 kristaps 34: int (*post)(struct mdoc *);
1.1 kristaps 35: };
36:
1.11 kristaps 37: /* Per-macro action routines. */
1.1 kristaps 38:
1.20 kristaps 39: static int post_bl(struct mdoc *);
1.23 ! kristaps 40: static int post_bl_width(struct mdoc *);
! 41: static int post_bl_tagwidth(struct mdoc *);
1.13 kristaps 42: static int post_sh(struct mdoc *);
43: static int post_os(struct mdoc *);
44: static int post_dt(struct mdoc *);
45: static int post_dd(struct mdoc *);
46: static int post_nm(struct mdoc *);
47:
48: static int post_prologue(struct mdoc *);
1.3 kristaps 49:
1.11 kristaps 50: /* Array of macro action routines. */
51:
1.1 kristaps 52: const struct actions mdoc_actions[MDOC_MAX] = {
1.10 kristaps 53: { NULL }, /* \" */
54: { post_dd }, /* Dd */
55: { post_dt }, /* Dt */
56: { post_os }, /* Os */
57: { post_sh }, /* Sh */
58: { NULL }, /* Ss */
59: { NULL }, /* Pp */
60: { NULL }, /* D1 */
61: { NULL }, /* Dl */
62: { NULL }, /* Bd */
63: { NULL }, /* Ed */
1.20 kristaps 64: { post_bl }, /* Bl */
1.10 kristaps 65: { NULL }, /* El */
66: { NULL }, /* It */
67: { NULL }, /* Ad */
68: { NULL }, /* An */
69: { NULL }, /* Ar */
70: { NULL }, /* Cd */
71: { NULL }, /* Cm */
72: { NULL }, /* Dv */
73: { NULL }, /* Er */
74: { NULL }, /* Ev */
75: { NULL }, /* Ex */
76: { NULL }, /* Fa */
77: { NULL }, /* Fd */
78: { NULL }, /* Fl */
79: { NULL }, /* Fn */
80: { NULL }, /* Ft */
81: { NULL }, /* Ic */
82: { NULL }, /* In */
83: { NULL }, /* Li */
84: { NULL }, /* Nd */
85: { post_nm }, /* Nm */
86: { NULL }, /* Op */
87: { NULL }, /* Ot */
88: { NULL }, /* Pa */
89: { NULL }, /* Rv */
90: { NULL }, /* St */
91: { NULL }, /* Va */
92: { NULL }, /* Vt */
93: { NULL }, /* Xr */
94: { NULL }, /* %A */
95: { NULL }, /* %B */
96: { NULL }, /* %D */
97: { NULL }, /* %I */
98: { NULL }, /* %J */
99: { NULL }, /* %N */
100: { NULL }, /* %O */
101: { NULL }, /* %P */
102: { NULL }, /* %R */
103: { NULL }, /* %T */
104: { NULL }, /* %V */
105: { NULL }, /* Ac */
106: { NULL }, /* Ao */
107: { NULL }, /* Aq */
108: { NULL }, /* At */
109: { NULL }, /* Bc */
110: { NULL }, /* Bf */
111: { NULL }, /* Bo */
112: { NULL }, /* Bq */
113: { NULL }, /* Bsx */
114: { NULL }, /* Bx */
115: { NULL }, /* Db */
116: { NULL }, /* Dc */
117: { NULL }, /* Do */
118: { NULL }, /* Dq */
119: { NULL }, /* Ec */
120: { NULL }, /* Ef */
121: { NULL }, /* Em */
122: { NULL }, /* Eo */
123: { NULL }, /* Fx */
124: { NULL }, /* Ms */
125: { NULL }, /* No */
126: { NULL }, /* Ns */
127: { NULL }, /* Nx */
128: { NULL }, /* Ox */
129: { NULL }, /* Pc */
130: { NULL }, /* Pf */
131: { NULL }, /* Po */
132: { NULL }, /* Pq */
133: { NULL }, /* Qc */
134: { NULL }, /* Ql */
135: { NULL }, /* Qo */
136: { NULL }, /* Qq */
137: { NULL }, /* Re */
138: { NULL }, /* Rs */
139: { NULL }, /* Sc */
140: { NULL }, /* So */
141: { NULL }, /* Sq */
142: { NULL }, /* Sm */
143: { NULL }, /* Sx */
144: { NULL }, /* Sy */
145: { NULL }, /* Tn */
146: { NULL }, /* Ux */
147: { NULL }, /* Xc */
148: { NULL }, /* Xo */
149: { NULL }, /* Fo */
150: { NULL }, /* Fc */
151: { NULL }, /* Oo */
152: { NULL }, /* Oc */
153: { NULL }, /* Bk */
154: { NULL }, /* Ek */
155: { NULL }, /* Bt */
156: { NULL }, /* Hf */
157: { NULL }, /* Fr */
158: { NULL }, /* Ud */
1.1 kristaps 159: };
160:
161:
1.3 kristaps 162: static int
1.10 kristaps 163: post_nm(struct mdoc *mdoc)
164: {
165: char buf[64];
166:
167: assert(MDOC_ELEM == mdoc->last->type);
168: assert(MDOC_Nm == mdoc->last->tok);
169:
1.23 ! kristaps 170: /*
! 171: * The `Nm' macro sets the document's name when used the first
! 172: * time with an argument. Subsequent calls without a value will
! 173: * result in the name value being used.
! 174: */
! 175:
1.10 kristaps 176: if (mdoc->meta.name)
177: return(1);
178:
1.11 kristaps 179: if (xstrlcats(buf, mdoc->last->child, 64)) {
180: mdoc->meta.name = xstrdup(buf);
181: return(1);
182: }
1.10 kristaps 183:
1.11 kristaps 184: return(mdoc_err(mdoc, "macro parameters too long"));
1.10 kristaps 185: }
186:
187:
188: static int
1.4 kristaps 189: post_sh(struct mdoc *mdoc)
1.1 kristaps 190: {
1.10 kristaps 191: enum mdoc_sec sec;
192: char buf[64];
1.3 kristaps 193:
1.23 ! kristaps 194: /*
! 195: * We keep track of the current section /and/ the "named"
! 196: * section, which is one of the conventional ones, in order to
! 197: * check ordering.
! 198: */
! 199:
1.3 kristaps 200: if (MDOC_HEAD != mdoc->last->type)
201: return(1);
1.11 kristaps 202: if (xstrlcats(buf, mdoc->last->child, 64)) {
203: if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
1.16 kristaps 204: mdoc->lastnamed = sec;
1.19 kristaps 205: mdoc->lastsec = sec;
1.23 ! kristaps 206: } else
! 207: return(mdoc_err(mdoc, "parameters too long"));
! 208:
! 209: switch (mdoc->lastsec) {
! 210: case (SEC_RETURN_VALUES):
! 211: /* FALLTHROUGH */
! 212: case (SEC_ERRORS):
! 213: switch (mdoc->meta.msec) {
! 214: case (MSEC_2):
! 215: /* FALLTHROUGH */
! 216: case (MSEC_3):
! 217: /* FALLTHROUGH */
! 218: case (MSEC_9):
! 219: break;
! 220: default:
! 221: return(mdoc_warn(mdoc, WARN_COMPAT,
! 222: "inappropriate section for "
! 223: "manual section"));
! 224: }
! 225: break;
! 226: default:
! 227: break;
1.11 kristaps 228: }
1.23 ! kristaps 229: return(1);
1.1 kristaps 230: }
231:
1.3 kristaps 232:
1.4 kristaps 233: static int
234: post_dt(struct mdoc *mdoc)
235: {
1.5 kristaps 236: int i;
237: char *p;
238: struct mdoc_node *n;
239:
1.23 ! kristaps 240: /*
! 241: * Prologue title must be parsed into document meta-data.
! 242: */
! 243:
1.5 kristaps 244: assert(MDOC_ELEM == mdoc->last->type);
1.7 kristaps 245: assert(MDOC_Dt == mdoc->last->tok);
1.5 kristaps 246:
1.10 kristaps 247: assert(NULL == mdoc->meta.title);
1.4 kristaps 248:
1.18 kristaps 249: /* LINTED */
1.5 kristaps 250: for (i = 0, n = mdoc->last->child; n; n = n->next, i++) {
251: assert(MDOC_TEXT == n->type);
252: p = n->data.text.string;
1.4 kristaps 253:
1.5 kristaps 254: switch (i) {
255: case (0):
1.10 kristaps 256: mdoc->meta.title = xstrdup(p);
257: break;
1.5 kristaps 258: case (1):
259: mdoc->meta.msec = mdoc_atomsec(p);
260: if (MSEC_DEFAULT != mdoc->meta.msec)
261: break;
1.10 kristaps 262: return(mdoc_nerr(mdoc, n, "invalid parameter syntax"));
1.5 kristaps 263: case (2):
264: mdoc->meta.vol = mdoc_atovol(p);
265: if (VOL_DEFAULT != mdoc->meta.vol)
266: break;
267: mdoc->meta.arch = mdoc_atoarch(p);
268: if (ARCH_DEFAULT != mdoc->meta.arch)
269: break;
1.10 kristaps 270: return(mdoc_nerr(mdoc, n, "invalid parameter syntax"));
1.5 kristaps 271: default:
1.8 kristaps 272: return(mdoc_nerr(mdoc, n, "too many parameters"));
1.5 kristaps 273: }
1.4 kristaps 274: }
275:
1.10 kristaps 276: if (NULL == mdoc->meta.title)
1.17 kristaps 277: mdoc->meta.title = xstrdup("UNTITLED");
1.13 kristaps 278:
1.15 kristaps 279: mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
280:
1.13 kristaps 281: return(post_prologue(mdoc));
1.4 kristaps 282: }
283:
284:
285: static int
286: post_os(struct mdoc *mdoc)
287: {
1.10 kristaps 288: char buf[64];
1.5 kristaps 289:
1.23 ! kristaps 290: /*
! 291: * Prologue operating system must be parsed into document
! 292: * meta-data.
! 293: */
! 294:
1.5 kristaps 295: assert(MDOC_ELEM == mdoc->last->type);
1.7 kristaps 296: assert(MDOC_Os == mdoc->last->tok);
1.10 kristaps 297: assert(NULL == mdoc->meta.os);
1.5 kristaps 298:
1.10 kristaps 299: if ( ! xstrlcats(buf, mdoc->last->child, 64))
300: return(mdoc_err(mdoc, "macro parameters too long"));
1.6 kristaps 301:
1.22 kristaps 302: mdoc->meta.os = xstrdup(buf[0] ? buf : "LOCAL");
1.16 kristaps 303: mdoc->lastnamed = SEC_BODY;
1.13 kristaps 304:
305: return(post_prologue(mdoc));
1.4 kristaps 306: }
307:
308:
1.20 kristaps 309: static int
1.23 ! kristaps 310: post_bl_tagwidth(struct mdoc *mdoc)
1.20 kristaps 311: {
1.23 ! kristaps 312: struct mdoc_node *n;
! 313: struct mdoc_block *b;
! 314: int sz;
1.20 kristaps 315: char buf[32];
316:
1.23 ! kristaps 317: /*
! 318: * If -tag has been specified and -width has not been, then try
! 319: * to intuit our width from the first body element.
! 320: */
! 321:
! 322: b = &mdoc->last->data.block;
! 323:
! 324: if (NULL == (n = b->body->child))
! 325: return(1);
! 326: assert(MDOC_It == n->tok);
! 327:
! 328: /*
! 329: * Use the text width, if a text node, or the default macro
! 330: * width if a macro.
! 331: */
! 332:
! 333: if ((n = n->data.block.head->child)) {
! 334: if (MDOC_TEXT != n->type) {
! 335: if (0 == (sz = mdoc_macro2len(n->tok)))
! 336: sz = -1;
! 337: } else
! 338: sz = (int)strlen(n->data.text.string) + 1;
! 339: } else
! 340: sz = -1;
! 341:
! 342: if (-1 == sz) {
! 343: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
! 344: "cannot determine default %s",
! 345: mdoc_argnames[MDOC_Width]))
! 346: return(0);
! 347: sz = 10;
! 348: }
! 349:
! 350: (void)snprintf(buf, sizeof(buf), "%dn", sz);
! 351:
! 352: /*
! 353: * We have to dynamically add this to the macro's argument list.
! 354: * We're guaranteed that a MDOC_Width doesn't already exist.
! 355: */
! 356:
! 357: (b->argc)++;
! 358: b->argv = xrealloc(b->argv, b->argc * sizeof(struct mdoc_arg));
! 359:
! 360: b->argv[b->argc - 1].arg = MDOC_Width;
! 361: b->argv[b->argc - 1].line = mdoc->last->line;
! 362: b->argv[b->argc - 1].pos = mdoc->last->pos;
! 363: b->argv[b->argc - 1].sz = 1;
! 364: b->argv[b->argc - 1].value = xcalloc(1, sizeof(char *));
! 365: b->argv[b->argc - 1].value[0] = xstrdup(buf);
! 366:
! 367: mdoc_msg(mdoc, "adding %s argument: %dn",
! 368: mdoc_argnames[MDOC_Width], sz);
! 369:
! 370: return(1);
! 371: }
1.20 kristaps 372:
373:
1.23 ! kristaps 374: static int
! 375: post_bl_width(struct mdoc *mdoc)
! 376: {
! 377: size_t width;
! 378: int i, tok;
! 379: char buf[32];
! 380: char **p;
! 381:
! 382: for (i = 0; i < (int)mdoc->last->data.block.argc; i++)
! 383: if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
1.20 kristaps 384: break;
385:
1.23 ! kristaps 386: assert(i < (int)mdoc->last->data.block.argc);
! 387: assert(1 == mdoc->last->data.block.argv[i].sz);
! 388: p = &mdoc->last->data.block.argv[i].value[0];
! 389:
! 390: /*
! 391: * If the value to -width is a macro, then we re-write it to be
! 392: * the macro's width as set in share/tmac/mdoc/doc-common.
! 393: */
1.20 kristaps 394:
1.23 ! kristaps 395: if (MDOC_MAX == (tok = mdoc_find(mdoc, *p)))
1.20 kristaps 396: return(1);
397:
398: if (0 == (width = mdoc_macro2len(tok)))
399: return(mdoc_warn(mdoc, WARN_SYNTAX,
400: "-%s macro has no length",
401: mdoc_argnames[MDOC_Width]));
402:
403: mdoc_msg(mdoc, "re-writing %s argument: %s -> %zun",
1.23 ! kristaps 404: mdoc_argnames[MDOC_Width], *p, width);
! 405:
! 406: /* The value already exists: free and reallocate it. */
1.20 kristaps 407:
408: (void)snprintf(buf, sizeof(buf), "%zun", width);
409:
1.23 ! kristaps 410: free(*p);
! 411: *p = strdup(buf);
! 412:
! 413: return(1);
! 414: }
! 415:
! 416:
! 417: static int
! 418: post_bl(struct mdoc *mdoc)
! 419: {
! 420: int i, r;
! 421:
! 422: if (MDOC_BLOCK != mdoc->last->type)
! 423: return(1);
! 424:
! 425: /*
! 426: * These are fairly complicated, so we've broken them into two
! 427: * functions. post_bl_tagwidth() is called when a -tag is
! 428: * specified, but no -width (it must be guessed). The second
! 429: * when a -width is specified (macro indicators must be
! 430: * rewritten into real lengths).
! 431: */
! 432:
! 433: for (r = i = 0; i < (int)mdoc->last->data.block.argc; i++) {
! 434: if (MDOC_Tag == mdoc->last->data.block.argv[i].arg)
! 435: r |= 1 << 0;
! 436: if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
! 437: r |= 1 << 1;
! 438: }
! 439:
! 440: if (r & (1 << 0) && ! (r & (1 << 1))) {
! 441: if ( ! post_bl_tagwidth(mdoc))
! 442: return(0);
! 443: } else if (r & (1 << 1))
! 444: if ( ! post_bl_width(mdoc))
! 445: return(0);
1.20 kristaps 446:
447: return(1);
448: }
449:
450:
1.4 kristaps 451: static int
452: post_dd(struct mdoc *mdoc)
453: {
1.15 kristaps 454: char buf[64];
1.4 kristaps 455:
1.23 ! kristaps 456: /*
! 457: * Prologue date must be parsed into document meta-data. We
! 458: * accept multiple kinds of dates, described mostly in
! 459: * mdoc_atotime().
! 460: */
! 461:
1.5 kristaps 462: assert(MDOC_ELEM == mdoc->last->type);
1.7 kristaps 463: assert(MDOC_Dd == mdoc->last->tok);
1.5 kristaps 464:
465: assert(0 == mdoc->meta.date);
1.4 kristaps 466:
1.15 kristaps 467: if ( ! xstrlcats(buf, mdoc->last->child, 64))
468: return(mdoc_err(mdoc, "macro parameters too long"));
469: if (0 == (mdoc->meta.date = mdoc_atotime(buf)))
470: return(mdoc_err(mdoc, "invalid parameter syntax"));
1.5 kristaps 471:
1.15 kristaps 472: mdoc_msg(mdoc, "date: %u", mdoc->meta.date);
1.5 kristaps 473:
1.15 kristaps 474: return(post_prologue(mdoc));
1.4 kristaps 475: }
476:
477:
1.13 kristaps 478: static int
479: post_prologue(struct mdoc *mdoc)
480: {
481: struct mdoc_node *n;
482:
1.23 ! kristaps 483: /*
! 484: * The end document shouldn't have the prologue macros as part
! 485: * of the syntax tree (they encompass only meta-data).
! 486: */
! 487:
1.13 kristaps 488: if (mdoc->last->parent->child == mdoc->last)
489: mdoc->last->parent->child = mdoc->last->prev;
490: if (mdoc->last->prev)
491: mdoc->last->prev->next = NULL;
492:
493: n = mdoc->last;
494: assert(NULL == mdoc->last->next);
495:
496: if (mdoc->last->prev) {
497: mdoc->last = mdoc->last->prev;
498: mdoc->next = MDOC_NEXT_SIBLING;
499: } else {
500: mdoc->last = mdoc->last->parent;
501: mdoc->next = MDOC_NEXT_CHILD;
502: }
503:
504: mdoc_node_freelist(n);
505: return(1);
506: }
507:
508:
1.4 kristaps 509: int
510: mdoc_action_post(struct mdoc *mdoc)
1.3 kristaps 511: {
512:
1.12 kristaps 513: if (MDOC_ACTED & mdoc->last->flags)
514: return(1);
515: mdoc->last->flags |= MDOC_ACTED;
516:
1.7 kristaps 517: if (MDOC_TEXT == mdoc->last->type)
518: return(1);
519: if (MDOC_ROOT == mdoc->last->type)
1.3 kristaps 520: return(1);
1.7 kristaps 521: if (NULL == mdoc_actions[mdoc->last->tok].post)
1.3 kristaps 522: return(1);
1.7 kristaps 523: return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
1.3 kristaps 524: }
CVSweb