Annotation of mandoc/action.c, Revision 1.35
1.35 ! kristaps 1: /* $Id: action.c,v 1.34 2009/03/08 12:40:27 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.35 ! kristaps 244: mdoc->last->args->argv[0].value = xcalloc(1, sizeof(char *));
1.33 kristaps 245: mdoc->last->args->argv[0].sz = 1;
246: mdoc->last->args->argv[0].value[0] = xstrdup(mdoc->meta.name);
1.29 kristaps 247: return(1);
248: }
249:
250:
251: static int
1.10 kristaps 252: post_nm(struct mdoc *mdoc)
253: {
254: char buf[64];
255:
256: if (mdoc->meta.name)
257: return(1);
258:
1.31 kristaps 259: (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
260: mdoc->meta.name = xstrdup(buf);
261: mdoc_msg(mdoc, "name: %s", mdoc->meta.name);
1.10 kristaps 262:
1.31 kristaps 263: return(1);
1.10 kristaps 264: }
265:
266:
267: static int
1.4 kristaps 268: post_sh(struct mdoc *mdoc)
1.1 kristaps 269: {
1.10 kristaps 270: enum mdoc_sec sec;
271: char buf[64];
1.3 kristaps 272:
1.23 kristaps 273: /*
274: * We keep track of the current section /and/ the "named"
275: * section, which is one of the conventional ones, in order to
276: * check ordering.
277: */
278:
1.3 kristaps 279: if (MDOC_HEAD != mdoc->last->type)
280: return(1);
1.31 kristaps 281:
282: (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
283: if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
284: mdoc->lastnamed = sec;
285:
286: mdoc->lastsec = sec;
1.23 kristaps 287:
288: switch (mdoc->lastsec) {
289: case (SEC_RETURN_VALUES):
290: /* FALLTHROUGH */
291: case (SEC_ERRORS):
292: switch (mdoc->meta.msec) {
1.31 kristaps 293: case (2):
1.23 kristaps 294: /* FALLTHROUGH */
1.31 kristaps 295: case (3):
1.23 kristaps 296: /* FALLTHROUGH */
1.31 kristaps 297: case (9):
1.23 kristaps 298: break;
299: default:
1.33 kristaps 300: return(mwarn(mdoc, WBADSEC));
1.23 kristaps 301: }
302: break;
303: default:
304: break;
1.11 kristaps 305: }
1.23 kristaps 306: return(1);
1.1 kristaps 307: }
308:
1.3 kristaps 309:
1.4 kristaps 310: static int
311: post_dt(struct mdoc *mdoc)
312: {
1.5 kristaps 313: struct mdoc_node *n;
1.31 kristaps 314: const char *cp;
315: char *ep;
316: long lval;
317:
318: if (mdoc->meta.title)
319: free(mdoc->meta.title);
320: if (mdoc->meta.vol)
321: free(mdoc->meta.vol);
322: if (mdoc->meta.arch)
323: free(mdoc->meta.arch);
324:
325: mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
326: mdoc->meta.msec = 0;
327:
328: /* Handles: `.Dt'
329: * --> title = unknown, volume = local, msec = 0, arch = NULL
330: */
331:
332: if (NULL == (n = mdoc->last->child)) {
333: mdoc->meta.title = xstrdup("unknown");
334: mdoc->meta.vol = xstrdup("local");
335: mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
336: mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
337: mdoc_msg(mdoc, "arch: <unset>");
338: mdoc_msg(mdoc, "msec: <unset>");
339: return(post_prologue(mdoc));
340: }
1.5 kristaps 341:
1.31 kristaps 342: /* Handles: `.Dt TITLE'
343: * --> title = TITLE, volume = local, msec = 0, arch = NULL
1.23 kristaps 344: */
345:
1.33 kristaps 346: mdoc->meta.title = xstrdup(n->string);
1.31 kristaps 347: mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
348:
349: if (NULL == (n = n->next)) {
350: mdoc->meta.vol = xstrdup("local");
351: mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
352: mdoc_msg(mdoc, "arch: <unset>");
353: mdoc_msg(mdoc, "msec: %d", mdoc->meta.msec);
354: return(post_prologue(mdoc));
355: }
1.5 kristaps 356:
1.31 kristaps 357: /* Handles: `.Dt TITLE SEC'
358: * --> title = TITLE, volume = SEC is msec ?
359: * format(msec) : SEC,
360: * msec = SEC is msec ? atoi(msec) : 0,
361: * arch = NULL
362: */
363:
1.33 kristaps 364: if ((cp = mdoc_a2msec(n->string))) {
1.31 kristaps 365: mdoc->meta.vol = xstrdup(cp);
366: errno = 0;
1.33 kristaps 367: lval = strtol(n->string, &ep, 10);
368: if (n->string[0] != '\0' && *ep == '\0')
1.31 kristaps 369: mdoc->meta.msec = (int)lval;
370: } else
1.33 kristaps 371: mdoc->meta.vol = xstrdup(n->string);
1.31 kristaps 372:
373: if (NULL == (n = n->next)) {
374: mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
375: mdoc_msg(mdoc, "arch: <unset>");
376: mdoc_msg(mdoc, "msec: %d", mdoc->meta.msec);
377: return(post_prologue(mdoc));
378: }
1.4 kristaps 379:
1.31 kristaps 380: /* Handles: `.Dt TITLE SEC VOL'
381: * --> title = TITLE, volume = VOL is vol ?
382: * format(VOL) :
383: * VOL is arch ? format(arch) :
384: * VOL
385: */
1.4 kristaps 386:
1.33 kristaps 387: if ((cp = mdoc_a2vol(n->string))) {
1.31 kristaps 388: free(mdoc->meta.vol);
389: mdoc->meta.vol = xstrdup(cp);
390: n = n->next;
391: } else {
1.33 kristaps 392: cp = mdoc_a2arch(n->string);
1.31 kristaps 393: if (NULL == cp) {
394: free(mdoc->meta.vol);
1.33 kristaps 395: mdoc->meta.vol = xstrdup(n->string);
1.31 kristaps 396: } else
397: mdoc->meta.arch = xstrdup(cp);
398: }
1.4 kristaps 399:
1.31 kristaps 400: mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
401: mdoc_msg(mdoc, "arch: %s", mdoc->meta.arch ?
402: mdoc->meta.arch : "<unset>");
403: mdoc_msg(mdoc, "msec: %d", mdoc->meta.msec);
1.13 kristaps 404:
1.31 kristaps 405: /* Ignore any subsequent parameters... */
1.15 kristaps 406:
1.13 kristaps 407: return(post_prologue(mdoc));
1.4 kristaps 408: }
409:
410:
411: static int
412: post_os(struct mdoc *mdoc)
413: {
1.10 kristaps 414: char buf[64];
1.31 kristaps 415: struct utsname utsname;
1.5 kristaps 416:
1.31 kristaps 417: if (mdoc->meta.os)
418: free(mdoc->meta.os);
1.23 kristaps 419:
1.31 kristaps 420: (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
1.5 kristaps 421:
1.31 kristaps 422: if (0 == buf[0]) {
423: if (-1 == uname(&utsname))
424: return(mdoc_err(mdoc, "utsname"));
425: (void)xstrlcpy(buf, utsname.sysname, sizeof(buf));
426: (void)xstrlcat(buf, " ", sizeof(buf));
427: (void)xstrlcat(buf, utsname.release, sizeof(buf));
428: }
1.6 kristaps 429:
1.31 kristaps 430: mdoc->meta.os = xstrdup(buf);
431: mdoc_msg(mdoc, "system: %s", mdoc->meta.os);
432:
433: mdoc->lastnamed = mdoc->lastsec = SEC_BODY;
1.13 kristaps 434:
435: return(post_prologue(mdoc));
1.4 kristaps 436: }
437:
438:
1.20 kristaps 439: static int
1.23 kristaps 440: post_bl_tagwidth(struct mdoc *mdoc)
1.20 kristaps 441: {
1.23 kristaps 442: struct mdoc_node *n;
443: int sz;
1.20 kristaps 444: char buf[32];
445:
1.23 kristaps 446: /*
447: * If -tag has been specified and -width has not been, then try
448: * to intuit our width from the first body element.
449: */
450:
1.33 kristaps 451: if (NULL == (n = mdoc->last->body->child))
1.23 kristaps 452: return(1);
453:
454: /*
455: * Use the text width, if a text node, or the default macro
456: * width if a macro.
457: */
458:
1.33 kristaps 459: if ((n = n->head->child)) {
1.23 kristaps 460: if (MDOC_TEXT != n->type) {
1.33 kristaps 461: if (0 == (sz = (int)mdoc_macro2len(n->tok)))
1.23 kristaps 462: sz = -1;
463: } else
1.33 kristaps 464: sz = (int)strlen(n->string) + 1;
1.23 kristaps 465: } else
466: sz = -1;
467:
468: if (-1 == sz) {
1.33 kristaps 469: if ( ! mwarn(mdoc, WNOWIDTH))
1.23 kristaps 470: return(0);
471: sz = 10;
472: }
473:
474: (void)snprintf(buf, sizeof(buf), "%dn", sz);
475:
476: /*
477: * We have to dynamically add this to the macro's argument list.
478: * We're guaranteed that a MDOC_Width doesn't already exist.
479: */
480:
1.33 kristaps 481: if (NULL == mdoc->last->args) {
482: mdoc->last->args = xcalloc
483: (1, sizeof(struct mdoc_arg));
484: mdoc->last->args->refcnt = 1;
485: }
486:
487: n = mdoc->last;
488: sz = (int)n->args->argc;
489:
490: (n->args->argc)++;
491:
492: n->args->argv = xrealloc(n->args->argv,
493: n->args->argc * sizeof(struct mdoc_arg));
1.23 kristaps 494:
1.33 kristaps 495: n->args->argv[sz - 1].arg = MDOC_Width;
496: n->args->argv[sz - 1].line = mdoc->last->line;
497: n->args->argv[sz - 1].pos = mdoc->last->pos;
498: n->args->argv[sz - 1].sz = 1;
499: n->args->argv[sz - 1].value = xcalloc(1, sizeof(char *));
500: n->args->argv[sz - 1].value[0] = xstrdup(buf);
1.23 kristaps 501:
1.33 kristaps 502: mdoc_msg(mdoc, "adding %s argument: %s",
503: mdoc_argnames[MDOC_Width], buf);
1.23 kristaps 504:
505: return(1);
506: }
1.20 kristaps 507:
508:
1.23 kristaps 509: static int
1.33 kristaps 510: post_bl_width(struct mdoc *m)
1.23 kristaps 511: {
512: size_t width;
513: int i, tok;
514: char buf[32];
1.34 kristaps 515: char *p;
1.23 kristaps 516:
1.33 kristaps 517: if (NULL == m->last->args)
518: return(merr(m, ENOWIDTH));
519:
520: for (i = 0; i < (int)m->last->args->argc; i++)
521: if (MDOC_Width == m->last->args->argv[i].arg)
1.20 kristaps 522: break;
523:
1.33 kristaps 524: if (i == (int)m->last->args->argc)
525: return(merr(m, ENOWIDTH));
526:
1.34 kristaps 527: p = m->last->args->argv[i].value[0];
1.23 kristaps 528:
529: /*
530: * If the value to -width is a macro, then we re-write it to be
531: * the macro's width as set in share/tmac/mdoc/doc-common.
532: */
1.20 kristaps 533:
1.34 kristaps 534: if (xstrcmp(p, "Ds"))
1.26 kristaps 535: width = 8;
1.34 kristaps 536: else if (MDOC_MAX == (tok = mdoc_tokhash_find(m->htab, p)))
1.20 kristaps 537: return(1);
1.24 kristaps 538: else if (0 == (width = mdoc_macro2len(tok)))
1.33 kristaps 539: return(mwarn(m, WNOWIDTH));
1.20 kristaps 540:
1.33 kristaps 541: mdoc_msg(m, "re-writing %s argument: %s -> %zun",
1.34 kristaps 542: mdoc_argnames[MDOC_Width], p, width);
1.23 kristaps 543:
544: /* The value already exists: free and reallocate it. */
1.20 kristaps 545:
546: (void)snprintf(buf, sizeof(buf), "%zun", width);
547:
1.34 kristaps 548: free(m->last->args->argv[i].value[0]);
549: m->last->args->argv[i].value[0] = xstrdup(buf);
1.23 kristaps 550:
551: return(1);
552: }
553:
554:
555: static int
556: post_bl(struct mdoc *mdoc)
557: {
1.33 kristaps 558: int i, r, len;
1.23 kristaps 559:
560: if (MDOC_BLOCK != mdoc->last->type)
561: return(1);
562:
563: /*
564: * These are fairly complicated, so we've broken them into two
565: * functions. post_bl_tagwidth() is called when a -tag is
566: * specified, but no -width (it must be guessed). The second
567: * when a -width is specified (macro indicators must be
568: * rewritten into real lengths).
569: */
570:
1.33 kristaps 571: len = (int)(mdoc->last->args ? mdoc->last->args->argc : 0);
572:
573: for (r = i = 0; i < len; i++) {
574: if (MDOC_Tag == mdoc->last->args->argv[i].arg)
1.23 kristaps 575: r |= 1 << 0;
1.33 kristaps 576: if (MDOC_Width == mdoc->last->args->argv[i].arg)
1.23 kristaps 577: r |= 1 << 1;
578: }
579:
580: if (r & (1 << 0) && ! (r & (1 << 1))) {
581: if ( ! post_bl_tagwidth(mdoc))
582: return(0);
583: } else if (r & (1 << 1))
584: if ( ! post_bl_width(mdoc))
585: return(0);
1.20 kristaps 586:
587: return(1);
588: }
589:
590:
1.4 kristaps 591: static int
1.30 kristaps 592: post_ar(struct mdoc *mdoc)
593: {
594: struct mdoc_node *n;
595:
596: if (mdoc->last->child)
597: return(1);
598:
599: n = mdoc->last;
600:
601: mdoc->next = MDOC_NEXT_CHILD;
1.32 kristaps 602: if ( ! mdoc_word_alloc(mdoc, mdoc->last->line,
603: mdoc->last->pos, "file"))
604: return(0);
1.30 kristaps 605: mdoc->next = MDOC_NEXT_SIBLING;
1.32 kristaps 606: if ( ! mdoc_word_alloc(mdoc, mdoc->last->line,
607: mdoc->last->pos, "..."))
608: return(0);
1.30 kristaps 609:
610: mdoc->last = n;
611: mdoc->next = MDOC_NEXT_SIBLING;
612: return(1);
613: }
614:
615:
616: static int
1.4 kristaps 617: post_dd(struct mdoc *mdoc)
618: {
1.15 kristaps 619: char buf[64];
1.4 kristaps 620:
1.31 kristaps 621: (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
1.5 kristaps 622:
1.33 kristaps 623: if (0 == (mdoc->meta.date = mdoc_atotime(buf))) {
624: if ( ! mwarn(mdoc, WBADDATE))
625: return(0);
626: mdoc->meta.date = time(NULL);
627: }
1.5 kristaps 628:
1.15 kristaps 629: mdoc_msg(mdoc, "date: %u", mdoc->meta.date);
630: return(post_prologue(mdoc));
1.4 kristaps 631: }
632:
633:
1.13 kristaps 634: static int
635: post_prologue(struct mdoc *mdoc)
636: {
637: struct mdoc_node *n;
638:
1.23 kristaps 639: /*
640: * The end document shouldn't have the prologue macros as part
641: * of the syntax tree (they encompass only meta-data).
642: */
643:
1.13 kristaps 644: if (mdoc->last->parent->child == mdoc->last)
645: mdoc->last->parent->child = mdoc->last->prev;
646: if (mdoc->last->prev)
647: mdoc->last->prev->next = NULL;
648:
649: n = mdoc->last;
650: assert(NULL == mdoc->last->next);
651:
652: if (mdoc->last->prev) {
653: mdoc->last = mdoc->last->prev;
654: mdoc->next = MDOC_NEXT_SIBLING;
655: } else {
656: mdoc->last = mdoc->last->parent;
657: mdoc->next = MDOC_NEXT_CHILD;
658: }
659:
660: mdoc_node_freelist(n);
661: return(1);
662: }
663:
664:
1.4 kristaps 665: int
666: mdoc_action_post(struct mdoc *mdoc)
1.3 kristaps 667: {
668:
1.12 kristaps 669: if (MDOC_ACTED & mdoc->last->flags)
670: return(1);
671: mdoc->last->flags |= MDOC_ACTED;
672:
1.7 kristaps 673: if (MDOC_TEXT == mdoc->last->type)
674: return(1);
675: if (MDOC_ROOT == mdoc->last->type)
1.3 kristaps 676: return(1);
1.7 kristaps 677: if (NULL == mdoc_actions[mdoc->last->tok].post)
1.3 kristaps 678: return(1);
1.7 kristaps 679: return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
1.3 kristaps 680: }
CVSweb