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