Annotation of src/usr.bin/mandoc/mdoc_action.c, Revision 1.21
1.21 ! schwarze 1: /* $Id: mdoc_action.c,v 1.20 2009/08/22 22:50:17 schwarze Exp $ */
1.1 kristaps 2: /*
1.2 schwarze 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.2 schwarze 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.2 schwarze 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: */
17: #include <sys/utsname.h>
18:
19: #include <assert.h>
20: #include <errno.h>
21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
24:
25: #include "libmdoc.h"
26:
1.20 schwarze 27: #define POST_ARGS struct mdoc *m, struct mdoc_node *n
1.1 kristaps 28: #define PRE_ARGS struct mdoc *m, const struct mdoc_node *n
29:
30: struct actions {
31: int (*pre)(PRE_ARGS);
32: int (*post)(POST_ARGS);
33: };
34:
35: static int post_ar(POST_ARGS);
1.15 schwarze 36: static int post_at(POST_ARGS);
1.1 kristaps 37: static int post_bl(POST_ARGS);
1.6 schwarze 38: static int post_bl_head(POST_ARGS);
1.15 schwarze 39: static int post_bl_tagwidth(POST_ARGS);
1.1 kristaps 40: static int post_bl_width(POST_ARGS);
41: static int post_dd(POST_ARGS);
42: static int post_display(POST_ARGS);
43: static int post_dt(POST_ARGS);
1.15 schwarze 44: static int post_lb(POST_ARGS);
1.1 kristaps 45: static int post_nm(POST_ARGS);
46: static int post_os(POST_ARGS);
47: static int post_prol(POST_ARGS);
48: static int post_sh(POST_ARGS);
1.15 schwarze 49: static int post_st(POST_ARGS);
1.1 kristaps 50: static int post_std(POST_ARGS);
1.17 schwarze 51: static int post_tilde(POST_ARGS);
1.1 kristaps 52:
53: static int pre_bd(PRE_ARGS);
54: static int pre_dl(PRE_ARGS);
55:
1.21 ! schwarze 56: static const struct actions mdoc_actions[MDOC_MAX] = {
1.4 schwarze 57: { NULL, NULL }, /* Ap */
1.1 kristaps 58: { NULL, post_dd }, /* Dd */
59: { NULL, post_dt }, /* Dt */
60: { NULL, post_os }, /* Os */
61: { NULL, post_sh }, /* Sh */
62: { NULL, NULL }, /* Ss */
63: { NULL, NULL }, /* Pp */
64: { NULL, NULL }, /* D1 */
65: { pre_dl, post_display }, /* Dl */
66: { pre_bd, post_display }, /* Bd */
67: { NULL, NULL }, /* Ed */
68: { NULL, post_bl }, /* Bl */
69: { NULL, NULL }, /* El */
70: { NULL, NULL }, /* It */
71: { NULL, NULL }, /* Ad */
72: { NULL, NULL }, /* An */
73: { NULL, post_ar }, /* Ar */
1.20 schwarze 74: { NULL, NULL }, /* Cd */
1.1 kristaps 75: { NULL, NULL }, /* Cm */
76: { NULL, NULL }, /* Dv */
77: { NULL, NULL }, /* Er */
78: { NULL, NULL }, /* Ev */
79: { NULL, post_std }, /* Ex */
80: { NULL, NULL }, /* Fa */
81: { NULL, NULL }, /* Fd */
82: { NULL, NULL }, /* Fl */
83: { NULL, NULL }, /* Fn */
84: { NULL, NULL }, /* Ft */
85: { NULL, NULL }, /* Ic */
86: { NULL, NULL }, /* In */
87: { NULL, NULL }, /* Li */
88: { NULL, NULL }, /* Nd */
89: { NULL, post_nm }, /* Nm */
90: { NULL, NULL }, /* Op */
91: { NULL, NULL }, /* Ot */
1.17 schwarze 92: { NULL, post_tilde }, /* Pa */
1.1 kristaps 93: { NULL, post_std }, /* Rv */
1.15 schwarze 94: { NULL, post_st }, /* St */
1.1 kristaps 95: { NULL, NULL }, /* Va */
96: { NULL, NULL }, /* Vt */
97: { NULL, NULL }, /* Xr */
98: { NULL, NULL }, /* %A */
99: { NULL, NULL }, /* %B */
100: { NULL, NULL }, /* %D */
101: { NULL, NULL }, /* %I */
102: { NULL, NULL }, /* %J */
103: { NULL, NULL }, /* %N */
104: { NULL, NULL }, /* %O */
105: { NULL, NULL }, /* %P */
106: { NULL, NULL }, /* %R */
107: { NULL, NULL }, /* %T */
108: { NULL, NULL }, /* %V */
109: { NULL, NULL }, /* Ac */
110: { NULL, NULL }, /* Ao */
111: { NULL, NULL }, /* Aq */
1.15 schwarze 112: { NULL, post_at }, /* At */
1.1 kristaps 113: { NULL, NULL }, /* Bc */
114: { NULL, NULL }, /* Bf */
115: { NULL, NULL }, /* Bo */
116: { NULL, NULL }, /* Bq */
117: { NULL, NULL }, /* Bsx */
118: { NULL, NULL }, /* Bx */
119: { NULL, NULL }, /* Db */
120: { NULL, NULL }, /* Dc */
121: { NULL, NULL }, /* Do */
122: { NULL, NULL }, /* Dq */
123: { NULL, NULL }, /* Ec */
124: { NULL, NULL }, /* Ef */
125: { NULL, NULL }, /* Em */
126: { NULL, NULL }, /* Eo */
127: { NULL, NULL }, /* Fx */
128: { NULL, NULL }, /* Ms */
129: { NULL, NULL }, /* No */
130: { NULL, NULL }, /* Ns */
131: { NULL, NULL }, /* Nx */
132: { NULL, NULL }, /* Ox */
133: { NULL, NULL }, /* Pc */
134: { NULL, NULL }, /* Pf */
135: { NULL, NULL }, /* Po */
136: { NULL, NULL }, /* Pq */
137: { NULL, NULL }, /* Qc */
138: { NULL, NULL }, /* Ql */
139: { NULL, NULL }, /* Qo */
140: { NULL, NULL }, /* Qq */
141: { NULL, NULL }, /* Re */
142: { NULL, NULL }, /* Rs */
143: { NULL, NULL }, /* Sc */
144: { NULL, NULL }, /* So */
145: { NULL, NULL }, /* Sq */
146: { NULL, NULL }, /* Sm */
147: { NULL, NULL }, /* Sx */
148: { NULL, NULL }, /* Sy */
149: { NULL, NULL }, /* Tn */
150: { NULL, NULL }, /* Ux */
151: { NULL, NULL }, /* Xc */
152: { NULL, NULL }, /* Xo */
153: { NULL, NULL }, /* Fo */
154: { NULL, NULL }, /* Fc */
155: { NULL, NULL }, /* Oo */
156: { NULL, NULL }, /* Oc */
157: { NULL, NULL }, /* Bk */
158: { NULL, NULL }, /* Ek */
159: { NULL, NULL }, /* Bt */
160: { NULL, NULL }, /* Hf */
161: { NULL, NULL }, /* Fr */
162: { NULL, NULL }, /* Ud */
1.15 schwarze 163: { NULL, post_lb }, /* Lb */
1.1 kristaps 164: { NULL, NULL }, /* Lp */
1.17 schwarze 165: { NULL, post_tilde }, /* Lk */
1.1 kristaps 166: { NULL, NULL }, /* Mt */
167: { NULL, NULL }, /* Brq */
168: { NULL, NULL }, /* Bro */
169: { NULL, NULL }, /* Brc */
170: { NULL, NULL }, /* %C */
171: { NULL, NULL }, /* Es */
172: { NULL, NULL }, /* En */
173: { NULL, NULL }, /* Dx */
174: { NULL, NULL }, /* %Q */
1.16 schwarze 175: { NULL, NULL }, /* br */
176: { NULL, NULL }, /* sp */
1.1 kristaps 177: };
178:
1.15 schwarze 179: static int concat(struct mdoc *, const struct mdoc_node *,
180: char *, size_t);
181:
1.1 kristaps 182:
183: int
184: mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
185: {
186:
187: switch (n->type) {
188: case (MDOC_ROOT):
189: /* FALLTHROUGH */
190: case (MDOC_TEXT):
191: return(1);
192: default:
193: break;
194: }
195:
196: if (NULL == mdoc_actions[n->tok].pre)
197: return(1);
198: return((*mdoc_actions[n->tok].pre)(m, n));
199: }
200:
201:
202: int
203: mdoc_action_post(struct mdoc *m)
204: {
205:
206: if (MDOC_ACTED & m->last->flags)
207: return(1);
208: m->last->flags |= MDOC_ACTED;
209:
210: switch (m->last->type) {
211: case (MDOC_TEXT):
212: /* FALLTHROUGH */
213: case (MDOC_ROOT):
214: return(1);
215: default:
216: break;
217: }
218:
219: if (NULL == mdoc_actions[m->last->tok].post)
220: return(1);
1.20 schwarze 221: return((*mdoc_actions[m->last->tok].post)(m, m->last));
1.1 kristaps 222: }
223:
224:
225: static int
226: concat(struct mdoc *m, const struct mdoc_node *n,
227: char *buf, size_t sz)
228: {
229:
230: for ( ; n; n = n->next) {
231: assert(MDOC_TEXT == n->type);
232: if (strlcat(buf, n->string, sz) >= sz)
1.12 schwarze 233: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 234: if (NULL == n->next)
235: continue;
236: if (strlcat(buf, " ", sz) >= sz)
1.12 schwarze 237: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 238: }
239:
240: return(1);
241: }
242:
243:
244: static int
245: post_std(POST_ARGS)
246: {
1.20 schwarze 247: struct mdoc_node *nn;
1.1 kristaps 248:
1.20 schwarze 249: if (n->child)
1.1 kristaps 250: return(1);
1.20 schwarze 251:
252: nn = n;
253: m->next = MDOC_NEXT_CHILD;
1.1 kristaps 254: assert(m->meta.name);
1.20 schwarze 255: if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
256: return(0);
257: m->last = nn;
1.1 kristaps 258:
259: return(1);
260: }
261:
262:
263: static int
264: post_nm(POST_ARGS)
265: {
266: char buf[64];
267:
268: if (m->meta.name)
269: return(1);
270:
271: buf[0] = 0;
1.20 schwarze 272: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 273: return(0);
274: if (NULL == (m->meta.name = strdup(buf)))
1.20 schwarze 275: return(mdoc_nerr(m, n, EMALLOC));
1.2 schwarze 276:
1.1 kristaps 277: return(1);
278: }
279:
280:
281: static int
1.15 schwarze 282: post_lb(POST_ARGS)
283: {
284: const char *p;
285: char *buf;
286: size_t sz;
287:
1.20 schwarze 288: assert(MDOC_TEXT == n->child->type);
289: p = mdoc_a2lib(n->child->string);
1.15 schwarze 290: if (NULL == p) {
1.20 schwarze 291: sz = strlen(n->child->string) +
1.15 schwarze 292: 2 + strlen("\\(lqlibrary\\(rq");
293: buf = malloc(sz);
294: if (NULL == buf)
1.20 schwarze 295: return(mdoc_nerr(m, n, EMALLOC));
1.15 schwarze 296: (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
1.20 schwarze 297: n->child->string);
298: free(n->child->string);
299: n->child->string = buf;
1.15 schwarze 300: return(1);
301: }
302:
1.20 schwarze 303: free(n->child->string);
304: n->child->string = strdup(p);
305: if (NULL == n->child->string)
306: return(mdoc_nerr(m, n, EMALLOC));
307:
1.15 schwarze 308: return(1);
309: }
310:
311:
312: static int
313: post_st(POST_ARGS)
314: {
315: const char *p;
316:
1.20 schwarze 317: assert(MDOC_TEXT == n->child->type);
318: p = mdoc_a2st(n->child->string);
1.15 schwarze 319: assert(p);
1.20 schwarze 320: free(n->child->string);
321: n->child->string = strdup(p);
322: if (NULL == n->child->string)
323: return(mdoc_nerr(m, n, EMALLOC));
324:
1.15 schwarze 325: return(1);
326: }
327:
328:
329: static int
330: post_at(POST_ARGS)
331: {
1.20 schwarze 332: struct mdoc_node *nn;
333: const char *p;
1.15 schwarze 334:
1.20 schwarze 335: if (n->child) {
336: assert(MDOC_TEXT == n->child->type);
337: p = mdoc_a2att(n->child->string);
1.15 schwarze 338: assert(p);
1.20 schwarze 339: free(n->child->string);
340: n->child->string = strdup(p);
341: if (NULL == n->child->string)
342: return(mdoc_nerr(m, n, EMALLOC));
1.15 schwarze 343: return(1);
344: }
345:
1.20 schwarze 346: nn = n;
1.15 schwarze 347: m->next = MDOC_NEXT_CHILD;
348:
1.20 schwarze 349: if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
1.15 schwarze 350: return(0);
1.20 schwarze 351: m->last = nn;
1.15 schwarze 352:
353: return(1);
354: }
355:
356:
357: static int
1.1 kristaps 358: post_sh(POST_ARGS)
359: {
360: enum mdoc_sec sec;
361: char buf[64];
362:
363: /*
364: * We keep track of the current section /and/ the "named"
365: * section, which is one of the conventional ones, in order to
366: * check ordering.
367: */
368:
1.20 schwarze 369: if (MDOC_HEAD != n->type)
1.1 kristaps 370: return(1);
371:
372: buf[0] = 0;
1.20 schwarze 373: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 374: return(0);
375: if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
376: m->lastnamed = sec;
377:
378: switch ((m->lastsec = sec)) {
379: case (SEC_RETURN_VALUES):
380: /* FALLTHROUGH */
381: case (SEC_ERRORS):
382: switch (m->meta.msec) {
383: case (2):
384: /* FALLTHROUGH */
385: case (3):
386: /* FALLTHROUGH */
387: case (9):
388: break;
389: default:
1.20 schwarze 390: return(mdoc_nwarn(m, n, EBADSEC));
1.1 kristaps 391: }
392: break;
393: default:
394: break;
395: }
396: return(1);
397: }
398:
399:
400: static int
401: post_dt(POST_ARGS)
402: {
1.20 schwarze 403: struct mdoc_node *nn;
1.1 kristaps 404: const char *cp;
405: char *ep;
406: long lval;
407:
408: if (m->meta.title)
409: free(m->meta.title);
410: if (m->meta.vol)
411: free(m->meta.vol);
412: if (m->meta.arch)
413: free(m->meta.arch);
414:
415: m->meta.title = m->meta.vol = m->meta.arch = NULL;
416: m->meta.msec = 0;
417:
418: /* Handles: `.Dt'
419: * --> title = unknown, volume = local, msec = 0, arch = NULL
420: */
421:
1.20 schwarze 422: if (NULL == (nn = n->child)) {
1.1 kristaps 423: if (NULL == (m->meta.title = strdup("unknown")))
1.20 schwarze 424: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 425: if (NULL == (m->meta.vol = strdup("local")))
1.20 schwarze 426: return(mdoc_nerr(m, n, EMALLOC));
427: return(post_prol(m, n));
1.1 kristaps 428: }
429:
430: /* Handles: `.Dt TITLE'
431: * --> title = TITLE, volume = local, msec = 0, arch = NULL
432: */
433:
1.20 schwarze 434: if (NULL == (m->meta.title = strdup(nn->string)))
435: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 436:
1.20 schwarze 437: if (NULL == (nn = nn->next)) {
1.1 kristaps 438: if (NULL == (m->meta.vol = strdup("local")))
1.20 schwarze 439: return(mdoc_nerr(m, n, EMALLOC));
440: return(post_prol(m, n));
1.1 kristaps 441: }
442:
443: /* Handles: `.Dt TITLE SEC'
444: * --> title = TITLE, volume = SEC is msec ?
445: * format(msec) : SEC,
446: * msec = SEC is msec ? atoi(msec) : 0,
447: * arch = NULL
448: */
449:
1.20 schwarze 450: cp = mdoc_a2msec(nn->string);
1.1 kristaps 451: if (cp) {
452: if (NULL == (m->meta.vol = strdup(cp)))
1.20 schwarze 453: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 454: errno = 0;
1.20 schwarze 455: lval = strtol(nn->string, &ep, 10);
456: if (nn->string[0] != '\0' && *ep == '\0')
1.1 kristaps 457: m->meta.msec = (int)lval;
1.20 schwarze 458: } else if (NULL == (m->meta.vol = strdup(nn->string)))
459: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 460:
1.20 schwarze 461: if (NULL == (nn = nn->next))
462: return(post_prol(m, n));
1.1 kristaps 463:
464: /* Handles: `.Dt TITLE SEC VOL'
465: * --> title = TITLE, volume = VOL is vol ?
466: * format(VOL) :
467: * VOL is arch ? format(arch) :
468: * VOL
469: */
470:
1.20 schwarze 471: cp = mdoc_a2vol(nn->string);
1.1 kristaps 472: if (cp) {
473: free(m->meta.vol);
474: if (NULL == (m->meta.vol = strdup(cp)))
1.20 schwarze 475: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 476: } else {
1.20 schwarze 477: cp = mdoc_a2arch(nn->string);
1.1 kristaps 478: if (NULL == cp) {
479: free(m->meta.vol);
1.20 schwarze 480: if (NULL == (m->meta.vol = strdup(nn->string)))
481: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 482: } else if (NULL == (m->meta.arch = strdup(cp)))
1.20 schwarze 483: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 484: }
485:
486: /* Ignore any subsequent parameters... */
487:
1.20 schwarze 488: return(post_prol(m, n));
1.1 kristaps 489: }
490:
491:
492: static int
493: post_os(POST_ARGS)
494: {
495: char buf[64];
496: struct utsname utsname;
497:
498: if (m->meta.os)
499: free(m->meta.os);
500:
501: buf[0] = 0;
1.20 schwarze 502: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 503: return(0);
504:
505: if (0 == buf[0]) {
506: if (-1 == uname(&utsname))
1.20 schwarze 507: return(mdoc_nerr(m, n, EUTSNAME));
1.1 kristaps 508: if (strlcat(buf, utsname.sysname, 64) >= 64)
1.20 schwarze 509: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 510: if (strlcat(buf, " ", 64) >= 64)
1.20 schwarze 511: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 512: if (strlcat(buf, utsname.release, 64) >= 64)
1.20 schwarze 513: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 514: }
515:
516: if (NULL == (m->meta.os = strdup(buf)))
1.20 schwarze 517: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 518:
1.20 schwarze 519: return(post_prol(m, n));
1.1 kristaps 520: }
521:
522:
523: /*
524: * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
525: * Uses the first head macro.
526: */
527: static int
1.20 schwarze 528: post_bl_tagwidth(POST_ARGS)
1.1 kristaps 529: {
1.20 schwarze 530: struct mdoc_node *nn;
1.1 kristaps 531: int sz;
532: char buf[32];
533:
534: /*
535: * Use the text width, if a text node, or the default macro
536: * width if a macro.
537: */
538:
1.20 schwarze 539: nn = n->body->child;
540: if (nn) {
541: assert(MDOC_BLOCK == nn->type);
542: assert(MDOC_It == nn->tok);
543: nn = nn->head->child;
1.1 kristaps 544: }
545:
546: sz = 10; /* Default size. */
547:
1.20 schwarze 548: if (nn) {
549: if (MDOC_TEXT != nn->type) {
550: if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
551: if ( ! mdoc_nwarn(m, n, ENOWIDTH))
1.1 kristaps 552: return(0);
553: } else
1.20 schwarze 554: sz = (int)strlen(nn->string) + 1;
1.1 kristaps 555: }
556:
557: if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
1.20 schwarze 558: return(mdoc_nerr(m, n, ENUMFMT));
1.1 kristaps 559:
560: /*
561: * We have to dynamically add this to the macro's argument list.
562: * We're guaranteed that a MDOC_Width doesn't already exist.
563: */
564:
1.20 schwarze 565: nn = n;
566: assert(nn->args);
567: sz = (int)(nn->args->argc)++;
1.1 kristaps 568:
1.20 schwarze 569: nn->args->argv = realloc(nn->args->argv,
570: nn->args->argc * sizeof(struct mdoc_argv));
1.1 kristaps 571:
1.20 schwarze 572: if (NULL == nn->args->argv)
573: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 574:
1.20 schwarze 575: nn->args->argv[sz].arg = MDOC_Width;
576: nn->args->argv[sz].line = n->line;
577: nn->args->argv[sz].pos = n->pos;
578: nn->args->argv[sz].sz = 1;
579: nn->args->argv[sz].value = calloc(1, sizeof(char *));
1.1 kristaps 580:
1.20 schwarze 581: if (NULL == nn->args->argv[sz].value)
582: return(mdoc_nerr(m, n, EMALLOC));
583: if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
584: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 585:
586: return(1);
587: }
588:
589:
590: static int
1.20 schwarze 591: post_bl_width(POST_ARGS)
1.1 kristaps 592: {
593: size_t width;
594: int i, tok;
595: char buf[32];
596: char *p;
597:
1.20 schwarze 598: if (NULL == n->args)
1.1 kristaps 599: return(1);
600:
1.20 schwarze 601: for (i = 0; i < (int)n->args->argc; i++)
602: if (MDOC_Width == n->args->argv[i].arg)
1.1 kristaps 603: break;
604:
1.20 schwarze 605: if (i == (int)n->args->argc)
1.1 kristaps 606: return(1);
1.20 schwarze 607: p = n->args->argv[i].value[0];
1.1 kristaps 608:
609: /*
610: * If the value to -width is a macro, then we re-write it to be
611: * the macro's width as set in share/tmac/mdoc/doc-common.
612: */
613:
614: if (0 == strcmp(p, "Ds"))
1.9 schwarze 615: width = 6;
1.21 ! schwarze 616: else if (MDOC_MAX == (tok = mdoc_hash_find(p)))
1.1 kristaps 617: return(1);
618: else if (0 == (width = mdoc_macro2len(tok)))
1.20 schwarze 619: return(mdoc_nwarn(m, n, ENOWIDTH));
1.1 kristaps 620:
621: /* The value already exists: free and reallocate it. */
622:
623: if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
1.20 schwarze 624: return(mdoc_nerr(m, n, ENUMFMT));
1.1 kristaps 625:
1.20 schwarze 626: free(n->args->argv[i].value[0]);
627: n->args->argv[i].value[0] = strdup(buf);
628: if (NULL == n->args->argv[i].value[0])
629: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 630:
631: return(1);
632: }
633:
634:
1.20 schwarze 635: /* ARGSUSED */
1.1 kristaps 636: static int
1.6 schwarze 637: post_bl_head(POST_ARGS)
638: {
639: int i, c;
1.20 schwarze 640: struct mdoc_node *np, *nn, *nnp;
1.6 schwarze 641:
1.20 schwarze 642: if (NULL == n->child)
1.6 schwarze 643: return(1);
644:
1.20 schwarze 645: np = n->parent;
646: assert(np->args);
1.6 schwarze 647:
1.20 schwarze 648: for (c = 0; c < (int)np->args->argc; c++)
649: if (MDOC_Column == np->args->argv[c].arg)
1.6 schwarze 650: break;
651:
652: /* Only process -column. */
653:
1.20 schwarze 654: if (c == (int)np->args->argc)
1.6 schwarze 655: return(1);
656:
1.20 schwarze 657: assert(0 == np->args->argv[c].sz);
1.6 schwarze 658:
659: /*
660: * Accomodate for new-style groff column syntax. Shuffle the
661: * child nodes, all of which must be TEXT, as arguments for the
662: * column field. Then, delete the head children.
663: */
664:
1.20 schwarze 665: np->args->argv[c].sz = (size_t)n->nchild;
666: np->args->argv[c].value = malloc
667: ((size_t)n->nchild * sizeof(char *));
1.6 schwarze 668:
1.20 schwarze 669: for (i = 0, nn = n->child; nn; i++) {
670: np->args->argv[c].value[i] = nn->string;
1.6 schwarze 671: nn->string = NULL;
672: nnp = nn;
673: nn = nn->next;
674: mdoc_node_free(nnp);
675: }
676:
1.20 schwarze 677: n->nchild = 0;
678: n->child = NULL;
1.8 schwarze 679:
1.6 schwarze 680: return(1);
681: }
682:
683:
684: static int
1.1 kristaps 685: post_bl(POST_ARGS)
686: {
687: int i, r, len;
688:
1.20 schwarze 689: if (MDOC_HEAD == n->type)
690: return(post_bl_head(m, n));
691: if (MDOC_BLOCK != n->type)
1.1 kristaps 692: return(1);
693:
694: /*
695: * These are fairly complicated, so we've broken them into two
696: * functions. post_bl_tagwidth() is called when a -tag is
697: * specified, but no -width (it must be guessed). The second
698: * when a -width is specified (macro indicators must be
699: * rewritten into real lengths).
700: */
701:
1.20 schwarze 702: len = (int)(n->args ? n->args->argc : 0);
1.1 kristaps 703:
704: for (r = i = 0; i < len; i++) {
1.20 schwarze 705: if (MDOC_Tag == n->args->argv[i].arg)
1.1 kristaps 706: r |= 1 << 0;
1.20 schwarze 707: if (MDOC_Width == n->args->argv[i].arg)
1.1 kristaps 708: r |= 1 << 1;
709: }
710:
711: if (r & (1 << 0) && ! (r & (1 << 1))) {
1.20 schwarze 712: if ( ! post_bl_tagwidth(m, n))
1.1 kristaps 713: return(0);
714: } else if (r & (1 << 1))
1.20 schwarze 715: if ( ! post_bl_width(m, n))
1.1 kristaps 716: return(0);
717:
1.3 schwarze 718: return(1);
719: }
720:
721:
722: static int
1.17 schwarze 723: post_tilde(POST_ARGS)
1.3 schwarze 724: {
1.20 schwarze 725: struct mdoc_node *np;
1.3 schwarze 726:
1.20 schwarze 727: if (n->child)
1.3 schwarze 728: return(1);
729:
1.20 schwarze 730: np = n;
1.3 schwarze 731: m->next = MDOC_NEXT_CHILD;
1.15 schwarze 732:
1.17 schwarze 733: /* XXX: not documented for `Lk'. */
1.20 schwarze 734: if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
1.3 schwarze 735: return(0);
1.20 schwarze 736: m->last = np;
1.3 schwarze 737:
1.1 kristaps 738: return(1);
739: }
740:
741:
742: static int
743: post_ar(POST_ARGS)
744: {
1.20 schwarze 745: struct mdoc_node *np;
1.1 kristaps 746:
1.20 schwarze 747: if (n->child)
1.1 kristaps 748: return(1);
749:
1.20 schwarze 750: np = n;
1.1 kristaps 751: m->next = MDOC_NEXT_CHILD;
1.20 schwarze 752: if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
1.1 kristaps 753: return(0);
1.20 schwarze 754: if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
1.1 kristaps 755: return(0);
1.20 schwarze 756: m->last = np;
1.1 kristaps 757:
758: return(1);
759: }
760:
761:
762: static int
763: post_dd(POST_ARGS)
764: {
765: char buf[64];
766:
767: buf[0] = 0;
1.20 schwarze 768: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 769: return(0);
770:
771: if (0 == (m->meta.date = mdoc_atotime(buf))) {
1.20 schwarze 772: if ( ! mdoc_nwarn(m, n, EBADDATE))
1.1 kristaps 773: return(0);
774: m->meta.date = time(NULL);
775: }
776:
1.20 schwarze 777: return(post_prol(m, n));
1.1 kristaps 778: }
779:
780:
781: static int
782: post_prol(POST_ARGS)
783: {
1.20 schwarze 784: struct mdoc_node *np;
1.1 kristaps 785:
1.20 schwarze 786: /* Remove prologue macros from AST. */
1.1 kristaps 787:
1.20 schwarze 788: if (n->parent->child == n)
789: n->parent->child = n->prev;
790: if (n->prev)
791: n->prev->next = NULL;
1.1 kristaps 792:
1.20 schwarze 793: np = n;
794: assert(NULL == n->next);
1.1 kristaps 795:
1.20 schwarze 796: if (n->prev) {
797: m->last = n->prev;
1.1 kristaps 798: m->next = MDOC_NEXT_SIBLING;
799: } else {
1.20 schwarze 800: m->last = n->parent;
1.1 kristaps 801: m->next = MDOC_NEXT_CHILD;
802: }
803:
1.20 schwarze 804: mdoc_node_freelist(np);
1.18 schwarze 805:
806: if (m->meta.title && m->meta.date && m->meta.os)
807: m->flags |= MDOC_PBODY;
1.20 schwarze 808:
1.1 kristaps 809: return(1);
810: }
811:
812:
813: static int
814: pre_dl(PRE_ARGS)
815: {
816:
1.7 schwarze 817: if (MDOC_BODY == n->type)
818: m->flags |= MDOC_LITERAL;
1.1 kristaps 819: return(1);
820: }
821:
822:
823: static int
824: pre_bd(PRE_ARGS)
825: {
826: int i;
827:
828: if (MDOC_BODY != n->type)
829: return(1);
830:
1.19 schwarze 831: /* Enter literal context if `Bd -literal' or `-unfilled'. */
832:
833: /*
834: * TODO: `-offset' without an argument should be the width of
835: * the literal "<string>".
836: */
1.1 kristaps 837:
838: for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
839: if (MDOC_Literal == n->args->argv[i].arg)
840: break;
841: else if (MDOC_Unfilled == n->args->argv[i].arg)
842: break;
843:
844: if (i < (int)n->args->argc)
845: m->flags |= MDOC_LITERAL;
846:
847: return(1);
848: }
849:
850:
851: static int
852: post_display(POST_ARGS)
853: {
854:
1.20 schwarze 855: if (MDOC_BODY == n->type)
1.1 kristaps 856: m->flags &= ~MDOC_LITERAL;
857: return(1);
858: }
859:
860: