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