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