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