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