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