Annotation of mandoc/mdoc_action.c, Revision 1.82
1.82 ! kristaps 1: /* $Id: mdoc_action.c,v 1.81 2010/11/29 13:51:03 kristaps Exp $ */
1.1 kristaps 2: /*
1.76 schwarze 3: * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.8 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.8 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.50 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.44 kristaps 21: #ifndef OSNAME
1.1 kristaps 22: #include <sys/utsname.h>
1.44 kristaps 23: #endif
1.1 kristaps 24:
25: #include <assert.h>
26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
1.44 kristaps 29: #include <time.h>
1.1 kristaps 30:
1.59 kristaps 31: #include "mandoc.h"
1.1 kristaps 32: #include "libmdoc.h"
1.46 kristaps 33: #include "libmandoc.h"
1.72 kristaps 34:
35: /*
36: * FIXME: this file is deprecated. All future "actions" should be
37: * pushed into mdoc_validate.c.
38: */
1.1 kristaps 39:
1.35 kristaps 40: #define POST_ARGS struct mdoc *m, struct mdoc_node *n
1.60 kristaps 41: #define PRE_ARGS struct mdoc *m, struct mdoc_node *n
1.1 kristaps 42:
1.46 kristaps 43: #define NUMSIZ 32
44: #define DATESIZ 32
45:
1.1 kristaps 46: struct actions {
47: int (*pre)(PRE_ARGS);
48: int (*post)(POST_ARGS);
49: };
50:
1.46 kristaps 51: static int concat(struct mdoc *, char *,
52: const struct mdoc_node *, size_t);
1.39 kristaps 53:
1.1 kristaps 54: static int post_bl(POST_ARGS);
1.14 kristaps 55: static int post_bl_head(POST_ARGS);
1.25 kristaps 56: static int post_bl_tagwidth(POST_ARGS);
1.70 kristaps 57: static int post_bl_width(POST_ARGS);
1.1 kristaps 58: static int post_dd(POST_ARGS);
59: static int post_display(POST_ARGS);
60: static int post_dt(POST_ARGS);
1.27 kristaps 61: static int post_lb(POST_ARGS);
1.1 kristaps 62: static int post_nm(POST_ARGS);
63: static int post_os(POST_ARGS);
1.46 kristaps 64: static int post_pa(POST_ARGS);
1.1 kristaps 65: static int post_prol(POST_ARGS);
1.26 kristaps 66: static int post_st(POST_ARGS);
1.1 kristaps 67: static int post_std(POST_ARGS);
68:
69: static int pre_bd(PRE_ARGS);
70: static int pre_dl(PRE_ARGS);
71:
1.37 kristaps 72: static const struct actions mdoc_actions[MDOC_MAX] = {
1.12 kristaps 73: { NULL, NULL }, /* Ap */
1.1 kristaps 74: { NULL, post_dd }, /* Dd */
75: { NULL, post_dt }, /* Dt */
76: { NULL, post_os }, /* Os */
1.81 kristaps 77: { NULL, NULL }, /* Sh */
1.1 kristaps 78: { NULL, NULL }, /* Ss */
79: { NULL, NULL }, /* Pp */
80: { NULL, NULL }, /* D1 */
81: { pre_dl, post_display }, /* Dl */
82: { pre_bd, post_display }, /* Bd */
83: { NULL, NULL }, /* Ed */
1.68 kristaps 84: { NULL, post_bl }, /* Bl */
1.1 kristaps 85: { NULL, NULL }, /* El */
86: { NULL, NULL }, /* It */
87: { NULL, NULL }, /* Ad */
88: { NULL, NULL }, /* An */
1.80 kristaps 89: { NULL, NULL }, /* Ar */
1.35 kristaps 90: { NULL, NULL }, /* Cd */
1.1 kristaps 91: { NULL, NULL }, /* Cm */
92: { NULL, NULL }, /* Dv */
93: { NULL, NULL }, /* Er */
94: { NULL, NULL }, /* Ev */
95: { NULL, post_std }, /* Ex */
96: { NULL, NULL }, /* Fa */
97: { NULL, NULL }, /* Fd */
98: { NULL, NULL }, /* Fl */
99: { NULL, NULL }, /* Fn */
100: { NULL, NULL }, /* Ft */
101: { NULL, NULL }, /* Ic */
102: { NULL, NULL }, /* In */
1.80 kristaps 103: { NULL, NULL }, /* Li */
1.1 kristaps 104: { NULL, NULL }, /* Nd */
105: { NULL, post_nm }, /* Nm */
106: { NULL, NULL }, /* Op */
107: { NULL, NULL }, /* Ot */
1.46 kristaps 108: { NULL, post_pa }, /* Pa */
1.1 kristaps 109: { NULL, post_std }, /* Rv */
1.26 kristaps 110: { NULL, post_st }, /* St */
1.1 kristaps 111: { NULL, NULL }, /* Va */
112: { NULL, NULL }, /* Vt */
113: { NULL, NULL }, /* Xr */
114: { NULL, NULL }, /* %A */
115: { NULL, NULL }, /* %B */
116: { NULL, NULL }, /* %D */
117: { NULL, NULL }, /* %I */
118: { NULL, NULL }, /* %J */
119: { NULL, NULL }, /* %N */
120: { NULL, NULL }, /* %O */
121: { NULL, NULL }, /* %P */
122: { NULL, NULL }, /* %R */
123: { NULL, NULL }, /* %T */
124: { NULL, NULL }, /* %V */
125: { NULL, NULL }, /* Ac */
126: { NULL, NULL }, /* Ao */
127: { NULL, NULL }, /* Aq */
1.82 ! kristaps 128: { NULL, NULL }, /* At */
1.1 kristaps 129: { NULL, NULL }, /* Bc */
130: { NULL, NULL }, /* Bf */
131: { NULL, NULL }, /* Bo */
132: { NULL, NULL }, /* Bq */
133: { NULL, NULL }, /* Bsx */
134: { NULL, NULL }, /* Bx */
135: { NULL, NULL }, /* Db */
136: { NULL, NULL }, /* Dc */
137: { NULL, NULL }, /* Do */
138: { NULL, NULL }, /* Dq */
139: { NULL, NULL }, /* Ec */
140: { NULL, NULL }, /* Ef */
141: { NULL, NULL }, /* Em */
142: { NULL, NULL }, /* Eo */
143: { NULL, NULL }, /* Fx */
144: { NULL, NULL }, /* Ms */
145: { NULL, NULL }, /* No */
146: { NULL, NULL }, /* Ns */
147: { NULL, NULL }, /* Nx */
148: { NULL, NULL }, /* Ox */
149: { NULL, NULL }, /* Pc */
150: { NULL, NULL }, /* Pf */
151: { NULL, NULL }, /* Po */
152: { NULL, NULL }, /* Pq */
153: { NULL, NULL }, /* Qc */
154: { NULL, NULL }, /* Ql */
155: { NULL, NULL }, /* Qo */
156: { NULL, NULL }, /* Qq */
157: { NULL, NULL }, /* Re */
1.79 kristaps 158: { NULL, NULL }, /* Rs */
1.1 kristaps 159: { NULL, NULL }, /* Sc */
160: { NULL, NULL }, /* So */
161: { NULL, NULL }, /* Sq */
162: { NULL, NULL }, /* Sm */
163: { NULL, NULL }, /* Sx */
164: { NULL, NULL }, /* Sy */
165: { NULL, NULL }, /* Tn */
166: { NULL, NULL }, /* Ux */
167: { NULL, NULL }, /* Xc */
168: { NULL, NULL }, /* Xo */
169: { NULL, NULL }, /* Fo */
170: { NULL, NULL }, /* Fc */
171: { NULL, NULL }, /* Oo */
172: { NULL, NULL }, /* Oc */
173: { NULL, NULL }, /* Bk */
174: { NULL, NULL }, /* Ek */
175: { NULL, NULL }, /* Bt */
176: { NULL, NULL }, /* Hf */
177: { NULL, NULL }, /* Fr */
178: { NULL, NULL }, /* Ud */
1.27 kristaps 179: { NULL, post_lb }, /* Lb */
1.1 kristaps 180: { NULL, NULL }, /* Lp */
1.44 kristaps 181: { NULL, NULL }, /* Lk */
1.1 kristaps 182: { NULL, NULL }, /* Mt */
183: { NULL, NULL }, /* Brq */
184: { NULL, NULL }, /* Bro */
185: { NULL, NULL }, /* Brc */
186: { NULL, NULL }, /* %C */
187: { NULL, NULL }, /* Es */
188: { NULL, NULL }, /* En */
189: { NULL, NULL }, /* Dx */
190: { NULL, NULL }, /* %Q */
1.30 kristaps 191: { NULL, NULL }, /* br */
192: { NULL, NULL }, /* sp */
1.43 kristaps 193: { NULL, NULL }, /* %U */
1.64 kristaps 194: { NULL, NULL }, /* Ta */
1.1 kristaps 195: };
196:
1.45 kristaps 197: #define RSORD_MAX 14
1.1 kristaps 198:
1.54 kristaps 199: static const enum mdoct rsord[RSORD_MAX] = {
1.39 kristaps 200: MDOC__A,
201: MDOC__T,
202: MDOC__B,
203: MDOC__I,
204: MDOC__J,
205: MDOC__R,
206: MDOC__N,
207: MDOC__V,
208: MDOC__P,
209: MDOC__Q,
210: MDOC__D,
211: MDOC__O,
1.45 kristaps 212: MDOC__C,
213: MDOC__U
1.39 kristaps 214: };
1.2 kristaps 215:
216:
1.1 kristaps 217: int
1.60 kristaps 218: mdoc_action_pre(struct mdoc *m, struct mdoc_node *n)
1.1 kristaps 219: {
220:
221: switch (n->type) {
222: case (MDOC_ROOT):
1.2 kristaps 223: /* FALLTHROUGH */
1.1 kristaps 224: case (MDOC_TEXT):
1.2 kristaps 225: return(1);
226: default:
1.1 kristaps 227: break;
228: }
1.2 kristaps 229:
1.6 kristaps 230: if (NULL == mdoc_actions[n->tok].pre)
1.2 kristaps 231: return(1);
1.6 kristaps 232: return((*mdoc_actions[n->tok].pre)(m, n));
1.1 kristaps 233: }
234:
235:
236: int
237: mdoc_action_post(struct mdoc *m)
238: {
239:
240: if (MDOC_ACTED & m->last->flags)
241: return(1);
242: m->last->flags |= MDOC_ACTED;
243:
244: switch (m->last->type) {
245: case (MDOC_TEXT):
1.2 kristaps 246: /* FALLTHROUGH */
1.1 kristaps 247: case (MDOC_ROOT):
1.2 kristaps 248: return(1);
249: default:
1.1 kristaps 250: break;
251: }
1.2 kristaps 252:
253: if (NULL == mdoc_actions[m->last->tok].post)
254: return(1);
1.35 kristaps 255: return((*mdoc_actions[m->last->tok].post)(m, m->last));
1.2 kristaps 256: }
257:
258:
1.46 kristaps 259: /*
260: * Concatenate sibling nodes together. All siblings must be of type
261: * MDOC_TEXT or an assertion is raised. Concatenation is separated by a
262: * single whitespace.
263: */
1.2 kristaps 264: static int
1.46 kristaps 265: concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz)
1.2 kristaps 266: {
267:
1.46 kristaps 268: assert(sz);
269: p[0] = '\0';
1.2 kristaps 270: for ( ; n; n = n->next) {
271: assert(MDOC_TEXT == n->type);
1.59 kristaps 272: /*
273: * XXX: yes, these can technically be resized, but it's
274: * highly unlikely that we're going to get here, so let
275: * it slip for now.
276: */
277: if (strlcat(p, n->string, sz) >= sz) {
278: mdoc_nmsg(m, n, MANDOCERR_MEM);
279: return(0);
280: }
1.2 kristaps 281: if (NULL == n->next)
282: continue;
1.59 kristaps 283: if (strlcat(p, " ", sz) >= sz) {
284: mdoc_nmsg(m, n, MANDOCERR_MEM);
285: return(0);
286: }
1.2 kristaps 287: }
288:
1.1 kristaps 289: return(1);
290: }
291:
292:
1.46 kristaps 293: /*
294: * Macros accepting `-std' as an argument have the name of the current
295: * document (`Nm') filled in as the argument if it's not provided.
296: */
1.1 kristaps 297: static int
298: post_std(POST_ARGS)
299: {
1.59 kristaps 300: struct mdoc_node *nn;
1.1 kristaps 301:
1.35 kristaps 302: if (n->child)
1.1 kristaps 303: return(1);
1.59 kristaps 304: if (NULL == m->meta.name)
305: return(1);
1.35 kristaps 306:
307: nn = n;
308: m->next = MDOC_NEXT_CHILD;
1.59 kristaps 309:
1.35 kristaps 310: if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
311: return(0);
312: m->last = nn;
1.1 kristaps 313: return(1);
314: }
315:
316:
1.46 kristaps 317: /*
318: * The `Nm' macro's first use sets the name of the document. See also
319: * post_std(), etc.
320: */
1.1 kristaps 321: static int
322: post_nm(POST_ARGS)
323: {
1.46 kristaps 324: char buf[BUFSIZ];
1.1 kristaps 325:
326: if (m->meta.name)
327: return(1);
1.46 kristaps 328: if ( ! concat(m, buf, n->child, BUFSIZ))
1.2 kristaps 329: return(0);
1.46 kristaps 330: m->meta.name = mandoc_strdup(buf);
1.1 kristaps 331: return(1);
332: }
333:
334:
1.46 kristaps 335: /*
336: * Look up the value of `Lb' for matching predefined strings. If it has
337: * one, then substitute the current value for the formatted value. Note
338: * that the lookup may fail (we can provide arbitrary strings).
339: */
340: /* ARGSUSED */
1.1 kristaps 341: static int
1.27 kristaps 342: post_lb(POST_ARGS)
343: {
344: const char *p;
345: char *buf;
346: size_t sz;
347:
1.35 kristaps 348: assert(MDOC_TEXT == n->child->type);
349: p = mdoc_a2lib(n->child->string);
1.46 kristaps 350:
351: if (p) {
1.35 kristaps 352: free(n->child->string);
1.46 kristaps 353: n->child->string = mandoc_strdup(p);
1.27 kristaps 354: return(1);
355: }
356:
1.46 kristaps 357: sz = strlen(n->child->string) +
358: 2 + strlen("\\(lqlibrary\\(rq");
359: buf = mandoc_malloc(sz);
360: snprintf(buf, sz, "library \\(lq%s\\(rq", n->child->string);
1.35 kristaps 361: free(n->child->string);
1.46 kristaps 362: n->child->string = buf;
1.27 kristaps 363: return(1);
364: }
365:
366:
1.46 kristaps 367: /*
368: * Substitute the value of `St' for the corresponding formatted string.
369: * We're guaranteed that this exists (it's been verified during the
370: * validation phase).
371: */
372: /* ARGSUSED */
1.27 kristaps 373: static int
1.26 kristaps 374: post_st(POST_ARGS)
375: {
376: const char *p;
377:
1.35 kristaps 378: assert(MDOC_TEXT == n->child->type);
379: p = mdoc_a2st(n->child->string);
1.56 kristaps 380: if (p != NULL) {
381: free(n->child->string);
382: n->child->string = mandoc_strdup(p);
383: }
1.1 kristaps 384: return(1);
385: }
386:
387:
1.46 kristaps 388: /*
389: * Parse out the contents of `Dt'. See in-line documentation for how we
390: * handle the various fields of this macro.
391: */
1.1 kristaps 392: static int
393: post_dt(POST_ARGS)
394: {
1.35 kristaps 395: struct mdoc_node *nn;
1.1 kristaps 396: const char *cp;
397:
398: if (m->meta.title)
399: free(m->meta.title);
400: if (m->meta.vol)
401: free(m->meta.vol);
402: if (m->meta.arch)
403: free(m->meta.arch);
404:
405: m->meta.title = m->meta.vol = m->meta.arch = NULL;
406: /* Handles: `.Dt'
407: * --> title = unknown, volume = local, msec = 0, arch = NULL
408: */
409:
1.35 kristaps 410: if (NULL == (nn = n->child)) {
1.46 kristaps 411: /* XXX: make these macro values. */
1.58 kristaps 412: /* FIXME: warn about missing values. */
1.63 kristaps 413: m->meta.title = mandoc_strdup("UNKNOWN");
414: m->meta.vol = mandoc_strdup("LOCAL");
1.58 kristaps 415: m->meta.msec = mandoc_strdup("1");
1.35 kristaps 416: return(post_prol(m, n));
1.1 kristaps 417: }
418:
419: /* Handles: `.Dt TITLE'
420: * --> title = TITLE, volume = local, msec = 0, arch = NULL
421: */
422:
1.63 kristaps 423: m->meta.title = mandoc_strdup
424: ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
1.1 kristaps 425:
1.35 kristaps 426: if (NULL == (nn = nn->next)) {
1.58 kristaps 427: /* FIXME: warn about missing msec. */
1.46 kristaps 428: /* XXX: make this a macro value. */
1.63 kristaps 429: m->meta.vol = mandoc_strdup("LOCAL");
1.58 kristaps 430: m->meta.msec = mandoc_strdup("1");
1.35 kristaps 431: return(post_prol(m, n));
1.1 kristaps 432: }
433:
434: /* Handles: `.Dt TITLE SEC'
435: * --> title = TITLE, volume = SEC is msec ?
436: * format(msec) : SEC,
437: * msec = SEC is msec ? atoi(msec) : 0,
438: * arch = NULL
439: */
440:
1.35 kristaps 441: cp = mdoc_a2msec(nn->string);
1.1 kristaps 442: if (cp) {
1.46 kristaps 443: m->meta.vol = mandoc_strdup(cp);
1.58 kristaps 444: m->meta.msec = mandoc_strdup(nn->string);
1.59 kristaps 445: } else if (mdoc_nmsg(m, n, MANDOCERR_BADMSEC)) {
1.46 kristaps 446: m->meta.vol = mandoc_strdup(nn->string);
1.58 kristaps 447: m->meta.msec = mandoc_strdup(nn->string);
448: } else
449: return(0);
1.1 kristaps 450:
1.35 kristaps 451: if (NULL == (nn = nn->next))
452: return(post_prol(m, n));
1.1 kristaps 453:
454: /* Handles: `.Dt TITLE SEC VOL'
455: * --> title = TITLE, volume = VOL is vol ?
456: * format(VOL) :
457: * VOL is arch ? format(arch) :
458: * VOL
459: */
460:
1.35 kristaps 461: cp = mdoc_a2vol(nn->string);
1.1 kristaps 462: if (cp) {
463: free(m->meta.vol);
1.46 kristaps 464: m->meta.vol = mandoc_strdup(cp);
1.1 kristaps 465: } else {
1.58 kristaps 466: /* FIXME: warn about bad arch. */
1.35 kristaps 467: cp = mdoc_a2arch(nn->string);
1.1 kristaps 468: if (NULL == cp) {
469: free(m->meta.vol);
1.46 kristaps 470: m->meta.vol = mandoc_strdup(nn->string);
471: } else
472: m->meta.arch = mandoc_strdup(cp);
1.1 kristaps 473: }
474:
475: /* Ignore any subsequent parameters... */
1.46 kristaps 476: /* FIXME: warn about subsequent parameters. */
1.1 kristaps 477:
1.35 kristaps 478: return(post_prol(m, n));
1.1 kristaps 479: }
480:
481:
1.46 kristaps 482: /*
483: * Set the operating system by way of the `Os' macro. Note that if an
484: * argument isn't provided and -DOSNAME="\"foo\"" is provided during
485: * compilation, this value will be used instead of filling in "sysname
486: * release" from uname().
487: */
1.1 kristaps 488: static int
489: post_os(POST_ARGS)
490: {
1.46 kristaps 491: char buf[BUFSIZ];
492: #ifndef OSNAME
1.1 kristaps 493: struct utsname utsname;
1.42 kristaps 494: #endif
495:
1.1 kristaps 496: if (m->meta.os)
497: free(m->meta.os);
1.4 kristaps 498:
1.46 kristaps 499: if ( ! concat(m, buf, n->child, BUFSIZ))
1.2 kristaps 500: return(0);
1.1 kristaps 501:
1.59 kristaps 502: /* XXX: yes, these can all be dynamically-adjusted buffers, but
503: * it's really not worth the extra hackery.
504: */
505:
1.46 kristaps 506: if ('\0' == buf[0]) {
507: #ifdef OSNAME
1.59 kristaps 508: if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
509: mdoc_nmsg(m, n, MANDOCERR_MEM);
510: return(0);
511: }
1.46 kristaps 512: #else /*!OSNAME */
1.1 kristaps 513: if (-1 == uname(&utsname))
1.59 kristaps 514: return(mdoc_nmsg(m, n, MANDOCERR_UTSNAME));
515:
516: if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
517: mdoc_nmsg(m, n, MANDOCERR_MEM);
518: return(0);
519: }
520: if (strlcat(buf, " ", 64) >= BUFSIZ) {
521: mdoc_nmsg(m, n, MANDOCERR_MEM);
522: return(0);
523: }
524: if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
525: mdoc_nmsg(m, n, MANDOCERR_MEM);
526: return(0);
527: }
1.46 kristaps 528: #endif /*!OSNAME*/
1.1 kristaps 529: }
530:
1.46 kristaps 531: m->meta.os = mandoc_strdup(buf);
1.35 kristaps 532: return(post_prol(m, n));
1.1 kristaps 533: }
534:
535:
536: /*
537: * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
1.46 kristaps 538: * Uses the first head macro. NOTE AGAIN: this is ONLY if the -width
539: * argument has NOT been provided. See post_bl_width() for converting
540: * the -width string.
1.1 kristaps 541: */
542: static int
1.35 kristaps 543: post_bl_tagwidth(POST_ARGS)
1.1 kristaps 544: {
1.46 kristaps 545: struct mdoc_node *nn;
1.69 kristaps 546: size_t sz, ssz;
1.46 kristaps 547: int i;
548: char buf[NUMSIZ];
1.1 kristaps 549:
1.69 kristaps 550: sz = 10;
1.61 joerg 551:
552: for (nn = n->body->child; nn; nn = nn->next) {
1.69 kristaps 553: if (MDOC_It != nn->tok)
554: continue;
1.46 kristaps 555:
1.35 kristaps 556: assert(MDOC_BLOCK == nn->type);
557: nn = nn->head->child;
1.78 joerg 558:
559: if (nn == NULL) {
560: /* No -width for .Bl and first .It is emtpy */
561: if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
562: return(0);
563: break;
564: }
1.69 kristaps 565:
566: if (MDOC_TEXT == nn->type) {
1.46 kristaps 567: sz = strlen(nn->string) + 1;
1.69 kristaps 568: break;
569: }
570:
571: if (0 != (ssz = mdoc_macro2len(nn->tok)))
572: sz = ssz;
573: else if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
574: return(0);
575:
576: break;
1.1 kristaps 577: }
578:
1.69 kristaps 579: /* Defaults to ten ens. */
580:
1.46 kristaps 581: snprintf(buf, NUMSIZ, "%zun", sz);
1.1 kristaps 582:
583: /*
584: * We have to dynamically add this to the macro's argument list.
585: * We're guaranteed that a MDOC_Width doesn't already exist.
586: */
587:
1.70 kristaps 588: assert(n->args);
589: i = (int)(n->args->argc)++;
590:
591: n->args->argv = mandoc_realloc(n->args->argv,
592: n->args->argc * sizeof(struct mdoc_argv));
1.1 kristaps 593:
1.70 kristaps 594: n->args->argv[i].arg = MDOC_Width;
595: n->args->argv[i].line = n->line;
596: n->args->argv[i].pos = n->pos;
597: n->args->argv[i].sz = 1;
598: n->args->argv[i].value = mandoc_malloc(sizeof(char *));
599: n->args->argv[i].value[0] = mandoc_strdup(buf);
1.1 kristaps 600:
1.70 kristaps 601: /* Set our width! */
1.74 kristaps 602: n->data.Bl->width = n->args->argv[i].value[0];
1.1 kristaps 603: return(1);
604: }
605:
606:
1.46 kristaps 607: /*
608: * Calculate the real width of a list from the -width string, which may
609: * contain a macro (with a known default width), a literal string, or a
610: * scaling width.
611: */
1.1 kristaps 612: static int
1.70 kristaps 613: post_bl_width(POST_ARGS)
1.1 kristaps 614: {
615: size_t width;
1.70 kristaps 616: int i;
1.51 kristaps 617: enum mdoct tok;
1.46 kristaps 618: char buf[NUMSIZ];
1.1 kristaps 619:
620: /*
621: * If the value to -width is a macro, then we re-write it to be
622: * the macro's width as set in share/tmac/mdoc/doc-common.
623: */
624:
1.74 kristaps 625: if (0 == strcmp(n->data.Bl->width, "Ds"))
1.18 kristaps 626: width = 6;
1.74 kristaps 627: else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width)))
1.1 kristaps 628: return(1);
629: else if (0 == (width = mdoc_macro2len(tok)))
1.59 kristaps 630: return(mdoc_nmsg(m, n, MANDOCERR_BADWIDTH));
1.1 kristaps 631:
632: /* The value already exists: free and reallocate it. */
633:
1.70 kristaps 634: assert(n->args);
635:
636: for (i = 0; i < (int)n->args->argc; i++)
637: if (MDOC_Width == n->args->argv[i].arg)
638: break;
639:
640: assert(i < (int)n->args->argc);
641:
1.46 kristaps 642: snprintf(buf, NUMSIZ, "%zun", width);
1.70 kristaps 643: free(n->args->argv[i].value[0]);
644: n->args->argv[i].value[0] = mandoc_strdup(buf);
645:
646: /* Set our width! */
1.74 kristaps 647: n->data.Bl->width = n->args->argv[i].value[0];
1.1 kristaps 648: return(1);
649: }
650:
651:
1.46 kristaps 652: /*
653: * Do processing for -column lists, which can have two distinct styles
654: * of invocation. Merge this two styles into a consistent form.
655: */
1.35 kristaps 656: /* ARGSUSED */
1.1 kristaps 657: static int
1.14 kristaps 658: post_bl_head(POST_ARGS)
659: {
660: int i, c;
1.35 kristaps 661: struct mdoc_node *np, *nn, *nnp;
1.14 kristaps 662:
1.74 kristaps 663: if (LIST_column != n->data.Bl->type)
1.69 kristaps 664: return(1);
665: else if (NULL == n->child)
1.14 kristaps 666: return(1);
667:
1.35 kristaps 668: np = n->parent;
669: assert(np->args);
1.14 kristaps 670:
1.35 kristaps 671: for (c = 0; c < (int)np->args->argc; c++)
672: if (MDOC_Column == np->args->argv[c].arg)
1.14 kristaps 673: break;
674:
1.69 kristaps 675: assert(c < (int)np->args->argc);
1.35 kristaps 676: assert(0 == np->args->argv[c].sz);
1.14 kristaps 677:
678: /*
679: * Accomodate for new-style groff column syntax. Shuffle the
680: * child nodes, all of which must be TEXT, as arguments for the
681: * column field. Then, delete the head children.
682: */
683:
1.35 kristaps 684: np->args->argv[c].sz = (size_t)n->nchild;
1.46 kristaps 685: np->args->argv[c].value = mandoc_malloc
1.35 kristaps 686: ((size_t)n->nchild * sizeof(char *));
1.75 kristaps 687:
688: n->data.Bl->ncols = np->args->argv[c].sz;
689: n->data.Bl->cols = (const char **)np->args->argv[c].value;
1.14 kristaps 690:
1.35 kristaps 691: for (i = 0, nn = n->child; nn; i++) {
692: np->args->argv[c].value[i] = nn->string;
1.14 kristaps 693: nn->string = NULL;
694: nnp = nn;
695: nn = nn->next;
1.53 kristaps 696: mdoc_node_delete(NULL, nnp);
1.14 kristaps 697: }
698:
1.35 kristaps 699: n->nchild = 0;
700: n->child = NULL;
1.14 kristaps 701: return(1);
702: }
703:
704:
705: static int
1.1 kristaps 706: post_bl(POST_ARGS)
707: {
708:
1.35 kristaps 709: if (MDOC_HEAD == n->type)
710: return(post_bl_head(m, n));
711: if (MDOC_BLOCK != n->type)
1.1 kristaps 712: return(1);
713:
714: /*
715: * These are fairly complicated, so we've broken them into two
716: * functions. post_bl_tagwidth() is called when a -tag is
717: * specified, but no -width (it must be guessed). The second
718: * when a -width is specified (macro indicators must be
719: * rewritten into real lengths).
720: */
721:
1.74 kristaps 722: if (LIST_tag == n->data.Bl->type && NULL == n->data.Bl->width) {
1.35 kristaps 723: if ( ! post_bl_tagwidth(m, n))
1.1 kristaps 724: return(0);
1.74 kristaps 725: } else if (NULL != n->data.Bl->width) {
1.70 kristaps 726: if ( ! post_bl_width(m, n))
1.1 kristaps 727: return(0);
1.70 kristaps 728: } else
729: return(1);
730:
1.74 kristaps 731: assert(n->data.Bl->width);
1.1 kristaps 732: return(1);
733: }
734:
735:
1.46 kristaps 736: /*
737: * The `Pa' macro defaults to a tilde if no value is provided as an
738: * argument.
739: */
1.1 kristaps 740: static int
1.46 kristaps 741: post_pa(POST_ARGS)
1.10 kristaps 742: {
1.35 kristaps 743: struct mdoc_node *np;
1.10 kristaps 744:
1.35 kristaps 745: if (n->child)
1.10 kristaps 746: return(1);
747:
1.35 kristaps 748: np = n;
1.10 kristaps 749: m->next = MDOC_NEXT_CHILD;
1.35 kristaps 750: if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
1.1 kristaps 751: return(0);
1.35 kristaps 752: m->last = np;
1.1 kristaps 753: return(1);
754: }
755:
756:
1.46 kristaps 757: /*
1.49 kristaps 758: * Parse the date field in `Dd'.
1.46 kristaps 759: */
1.1 kristaps 760: static int
761: post_dd(POST_ARGS)
762: {
1.46 kristaps 763: char buf[DATESIZ];
1.77 kristaps 764:
765: if (NULL == n->child) {
766: m->meta.date = time(NULL);
767: return(post_prol(m, n));
768: }
1.1 kristaps 769:
1.46 kristaps 770: if ( ! concat(m, buf, n->child, DATESIZ))
1.2 kristaps 771: return(0);
1.1 kristaps 772:
1.49 kristaps 773: m->meta.date = mandoc_a2time
774: (MTIME_MDOCDATE | MTIME_CANONICAL, buf);
775:
1.46 kristaps 776: if (0 == m->meta.date) {
1.59 kristaps 777: if ( ! mdoc_nmsg(m, n, MANDOCERR_BADDATE))
1.1 kristaps 778: return(0);
779: m->meta.date = time(NULL);
780: }
781:
1.35 kristaps 782: return(post_prol(m, n));
1.1 kristaps 783: }
784:
785:
1.46 kristaps 786: /*
787: * Remove prologue macros from the document after they're processed.
788: * The final document uses mdoc_meta for these values and discards the
789: * originals.
790: */
1.1 kristaps 791: static int
792: post_prol(POST_ARGS)
793: {
1.34 kristaps 794:
1.53 kristaps 795: mdoc_node_delete(m, n);
1.34 kristaps 796: if (m->meta.title && m->meta.date && m->meta.os)
797: m->flags |= MDOC_PBODY;
1.1 kristaps 798: return(1);
799: }
800:
801:
1.46 kristaps 802: /*
803: * Trigger a literal context.
804: */
1.1 kristaps 805: static int
806: pre_dl(PRE_ARGS)
807: {
808:
1.16 kristaps 809: if (MDOC_BODY == n->type)
810: m->flags |= MDOC_LITERAL;
1.65 kristaps 811: return(1);
1.38 kristaps 812: }
813:
814:
815: static int
1.1 kristaps 816: pre_bd(PRE_ARGS)
817: {
818:
819: if (MDOC_BODY != n->type)
820: return(1);
821:
1.74 kristaps 822: assert(n->data.Bd);
823: if (DISP_literal == n->data.Bd->type)
1.66 kristaps 824: m->flags |= MDOC_LITERAL;
1.74 kristaps 825: if (DISP_unfilled == n->data.Bd->type)
1.66 kristaps 826: m->flags |= MDOC_LITERAL;
1.1 kristaps 827:
828: return(1);
829: }
830:
831:
832: static int
833: post_display(POST_ARGS)
834: {
835:
1.35 kristaps 836: if (MDOC_BODY == n->type)
1.1 kristaps 837: m->flags &= ~MDOC_LITERAL;
1.39 kristaps 838: return(1);
839: }
CVSweb