Annotation of mandoc/mdoc_action.c, Revision 1.35
1.35 ! kristaps 1: /* $Id: mdoc_action.c,v 1.34 2009/07/26 10:29:39 kristaps Exp $ */
1.1 kristaps 2: /*
1.9 kristaps 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.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: */
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.35 ! kristaps 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.25 kristaps 36: static int post_at(POST_ARGS);
1.1 kristaps 37: static int post_bl(POST_ARGS);
1.14 kristaps 38: static int post_bl_head(POST_ARGS);
1.25 kristaps 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.27 kristaps 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.26 kristaps 49: static int post_st(POST_ARGS);
1.1 kristaps 50: static int post_std(POST_ARGS);
1.31 kristaps 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:
56: const struct actions mdoc_actions[MDOC_MAX] = {
1.12 kristaps 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.35 ! kristaps 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.31 kristaps 92: { NULL, post_tilde }, /* Pa */
1.1 kristaps 93: { NULL, post_std }, /* Rv */
1.26 kristaps 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.25 kristaps 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.27 kristaps 163: { NULL, post_lb }, /* Lb */
1.1 kristaps 164: { NULL, NULL }, /* Lp */
1.31 kristaps 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.30 kristaps 175: { NULL, NULL }, /* br */
176: { NULL, NULL }, /* sp */
1.1 kristaps 177: };
178:
1.25 kristaps 179: static int concat(struct mdoc *, const struct mdoc_node *,
180: char *, size_t);
1.1 kristaps 181:
1.2 kristaps 182: #ifdef __linux__
1.25 kristaps 183: extern size_t strlcat(char *, const char *, size_t);
1.2 kristaps 184: #endif
185:
186:
1.1 kristaps 187: int
188: mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
189: {
190:
191: switch (n->type) {
192: case (MDOC_ROOT):
1.2 kristaps 193: /* FALLTHROUGH */
1.1 kristaps 194: case (MDOC_TEXT):
1.2 kristaps 195: return(1);
196: default:
1.1 kristaps 197: break;
198: }
1.2 kristaps 199:
1.6 kristaps 200: if (NULL == mdoc_actions[n->tok].pre)
1.2 kristaps 201: return(1);
1.6 kristaps 202: return((*mdoc_actions[n->tok].pre)(m, n));
1.1 kristaps 203: }
204:
205:
206: int
207: mdoc_action_post(struct mdoc *m)
208: {
209:
210: if (MDOC_ACTED & m->last->flags)
211: return(1);
212: m->last->flags |= MDOC_ACTED;
213:
214: switch (m->last->type) {
215: case (MDOC_TEXT):
1.2 kristaps 216: /* FALLTHROUGH */
1.1 kristaps 217: case (MDOC_ROOT):
1.2 kristaps 218: return(1);
219: default:
1.1 kristaps 220: break;
221: }
1.2 kristaps 222:
223: if (NULL == mdoc_actions[m->last->tok].post)
224: return(1);
1.35 ! kristaps 225: return((*mdoc_actions[m->last->tok].post)(m, m->last));
1.2 kristaps 226: }
227:
228:
229: static int
230: concat(struct mdoc *m, const struct mdoc_node *n,
231: char *buf, size_t sz)
232: {
233:
234: for ( ; n; n = n->next) {
235: assert(MDOC_TEXT == n->type);
236: if (strlcat(buf, n->string, sz) >= sz)
1.23 kristaps 237: return(mdoc_nerr(m, n, ETOOLONG));
1.2 kristaps 238: if (NULL == n->next)
239: continue;
240: if (strlcat(buf, " ", sz) >= sz)
1.23 kristaps 241: return(mdoc_nerr(m, n, ETOOLONG));
1.2 kristaps 242: }
243:
1.1 kristaps 244: return(1);
245: }
246:
247:
248: static int
249: post_std(POST_ARGS)
250: {
1.35 ! kristaps 251: struct mdoc_node *nn;
1.1 kristaps 252:
1.35 ! kristaps 253: if (n->child)
1.1 kristaps 254: return(1);
1.35 ! kristaps 255:
! 256: nn = n;
! 257: m->next = MDOC_NEXT_CHILD;
1.1 kristaps 258: assert(m->meta.name);
1.35 ! kristaps 259: if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
! 260: return(0);
! 261: m->last = nn;
1.2 kristaps 262:
1.1 kristaps 263: return(1);
264: }
265:
266:
267: static int
268: post_nm(POST_ARGS)
269: {
270: char buf[64];
271:
272: if (m->meta.name)
273: return(1);
1.5 kristaps 274:
275: buf[0] = 0;
1.35 ! kristaps 276: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.2 kristaps 277: return(0);
278: if (NULL == (m->meta.name = strdup(buf)))
1.35 ! kristaps 279: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 280:
281: return(1);
282: }
283:
284:
285: static int
1.27 kristaps 286: post_lb(POST_ARGS)
287: {
288: const char *p;
289: char *buf;
290: size_t sz;
291:
1.35 ! kristaps 292: assert(MDOC_TEXT == n->child->type);
! 293: p = mdoc_a2lib(n->child->string);
1.27 kristaps 294: if (NULL == p) {
1.35 ! kristaps 295: sz = strlen(n->child->string) +
1.27 kristaps 296: 2 + strlen("\\(lqlibrary\\(rq");
297: buf = malloc(sz);
298: if (NULL == buf)
1.35 ! kristaps 299: return(mdoc_nerr(m, n, EMALLOC));
1.27 kristaps 300: (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
1.35 ! kristaps 301: n->child->string);
! 302: free(n->child->string);
! 303: n->child->string = buf;
1.27 kristaps 304: return(1);
305: }
306:
1.35 ! kristaps 307: free(n->child->string);
! 308: n->child->string = strdup(p);
! 309: if (NULL == n->child->string)
! 310: return(mdoc_nerr(m, n, EMALLOC));
! 311:
1.27 kristaps 312: return(1);
313: }
314:
315:
316: static int
1.26 kristaps 317: post_st(POST_ARGS)
318: {
319: const char *p;
320:
1.35 ! kristaps 321: assert(MDOC_TEXT == n->child->type);
! 322: p = mdoc_a2st(n->child->string);
1.26 kristaps 323: assert(p);
1.35 ! kristaps 324: free(n->child->string);
! 325: n->child->string = strdup(p);
! 326: if (NULL == n->child->string)
! 327: return(mdoc_nerr(m, n, EMALLOC));
! 328:
1.26 kristaps 329: return(1);
330: }
331:
332:
333: static int
1.25 kristaps 334: post_at(POST_ARGS)
335: {
1.35 ! kristaps 336: struct mdoc_node *nn;
! 337: const char *p;
1.25 kristaps 338:
1.35 ! kristaps 339: if (n->child) {
! 340: assert(MDOC_TEXT == n->child->type);
! 341: p = mdoc_a2att(n->child->string);
1.25 kristaps 342: assert(p);
1.35 ! kristaps 343: free(n->child->string);
! 344: n->child->string = strdup(p);
! 345: if (NULL == n->child->string)
! 346: return(mdoc_nerr(m, n, EMALLOC));
1.25 kristaps 347: return(1);
348: }
349:
1.35 ! kristaps 350: nn = n;
1.25 kristaps 351: m->next = MDOC_NEXT_CHILD;
352:
1.35 ! kristaps 353: if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
1.25 kristaps 354: return(0);
1.35 ! kristaps 355: m->last = nn;
1.25 kristaps 356:
357: return(1);
358: }
359:
360:
361: static int
1.1 kristaps 362: post_sh(POST_ARGS)
363: {
364: enum mdoc_sec sec;
365: char buf[64];
366:
367: /*
368: * We keep track of the current section /and/ the "named"
369: * section, which is one of the conventional ones, in order to
370: * check ordering.
371: */
372:
1.35 ! kristaps 373: if (MDOC_HEAD != n->type)
1.1 kristaps 374: return(1);
1.5 kristaps 375:
376: buf[0] = 0;
1.35 ! kristaps 377: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.2 kristaps 378: return(0);
1.1 kristaps 379: if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
380: m->lastnamed = sec;
381:
382: switch ((m->lastsec = sec)) {
383: case (SEC_RETURN_VALUES):
384: /* FALLTHROUGH */
385: case (SEC_ERRORS):
386: switch (m->meta.msec) {
387: case (2):
388: /* FALLTHROUGH */
389: case (3):
390: /* FALLTHROUGH */
391: case (9):
392: break;
393: default:
1.35 ! kristaps 394: return(mdoc_nwarn(m, n, EBADSEC));
1.1 kristaps 395: }
396: break;
397: default:
398: break;
399: }
400: return(1);
401: }
402:
403:
404: static int
405: post_dt(POST_ARGS)
406: {
1.35 ! kristaps 407: struct mdoc_node *nn;
1.1 kristaps 408: const char *cp;
409: char *ep;
410: long lval;
411:
412: if (m->meta.title)
413: free(m->meta.title);
414: if (m->meta.vol)
415: free(m->meta.vol);
416: if (m->meta.arch)
417: free(m->meta.arch);
418:
419: m->meta.title = m->meta.vol = m->meta.arch = NULL;
420: m->meta.msec = 0;
421:
422: /* Handles: `.Dt'
423: * --> title = unknown, volume = local, msec = 0, arch = NULL
424: */
425:
1.35 ! kristaps 426: if (NULL == (nn = n->child)) {
1.2 kristaps 427: if (NULL == (m->meta.title = strdup("unknown")))
1.35 ! kristaps 428: return(mdoc_nerr(m, n, EMALLOC));
1.2 kristaps 429: if (NULL == (m->meta.vol = strdup("local")))
1.35 ! kristaps 430: return(mdoc_nerr(m, n, EMALLOC));
! 431: return(post_prol(m, n));
1.1 kristaps 432: }
433:
434: /* Handles: `.Dt TITLE'
435: * --> title = TITLE, volume = local, msec = 0, arch = NULL
436: */
437:
1.35 ! kristaps 438: if (NULL == (m->meta.title = strdup(nn->string)))
! 439: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 440:
1.35 ! kristaps 441: if (NULL == (nn = nn->next)) {
1.2 kristaps 442: if (NULL == (m->meta.vol = strdup("local")))
1.35 ! kristaps 443: return(mdoc_nerr(m, n, EMALLOC));
! 444: return(post_prol(m, n));
1.1 kristaps 445: }
446:
447: /* Handles: `.Dt TITLE SEC'
448: * --> title = TITLE, volume = SEC is msec ?
449: * format(msec) : SEC,
450: * msec = SEC is msec ? atoi(msec) : 0,
451: * arch = NULL
452: */
453:
1.35 ! kristaps 454: cp = mdoc_a2msec(nn->string);
1.1 kristaps 455: if (cp) {
1.2 kristaps 456: if (NULL == (m->meta.vol = strdup(cp)))
1.35 ! kristaps 457: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 458: errno = 0;
1.35 ! kristaps 459: lval = strtol(nn->string, &ep, 10);
! 460: if (nn->string[0] != '\0' && *ep == '\0')
1.1 kristaps 461: m->meta.msec = (int)lval;
1.35 ! kristaps 462: } else if (NULL == (m->meta.vol = strdup(nn->string)))
! 463: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 464:
1.35 ! kristaps 465: if (NULL == (nn = nn->next))
! 466: return(post_prol(m, n));
1.1 kristaps 467:
468: /* Handles: `.Dt TITLE SEC VOL'
469: * --> title = TITLE, volume = VOL is vol ?
470: * format(VOL) :
471: * VOL is arch ? format(arch) :
472: * VOL
473: */
474:
1.35 ! kristaps 475: cp = mdoc_a2vol(nn->string);
1.1 kristaps 476: if (cp) {
477: free(m->meta.vol);
1.2 kristaps 478: if (NULL == (m->meta.vol = strdup(cp)))
1.35 ! kristaps 479: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 480: } else {
1.35 ! kristaps 481: cp = mdoc_a2arch(nn->string);
1.1 kristaps 482: if (NULL == cp) {
483: free(m->meta.vol);
1.35 ! kristaps 484: if (NULL == (m->meta.vol = strdup(nn->string)))
! 485: return(mdoc_nerr(m, n, EMALLOC));
1.2 kristaps 486: } else if (NULL == (m->meta.arch = strdup(cp)))
1.35 ! kristaps 487: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 488: }
489:
490: /* Ignore any subsequent parameters... */
491:
1.35 ! kristaps 492: return(post_prol(m, n));
1.1 kristaps 493: }
494:
495:
496: static int
497: post_os(POST_ARGS)
498: {
499: char buf[64];
500: struct utsname utsname;
501:
502: if (m->meta.os)
503: free(m->meta.os);
1.4 kristaps 504:
505: buf[0] = 0;
1.35 ! kristaps 506: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.2 kristaps 507: return(0);
1.1 kristaps 508:
509: if (0 == buf[0]) {
510: if (-1 == uname(&utsname))
1.35 ! kristaps 511: return(mdoc_nerr(m, n, EUTSNAME));
1.4 kristaps 512: if (strlcat(buf, utsname.sysname, 64) >= 64)
1.35 ! kristaps 513: return(mdoc_nerr(m, n, ETOOLONG));
1.2 kristaps 514: if (strlcat(buf, " ", 64) >= 64)
1.35 ! kristaps 515: return(mdoc_nerr(m, n, ETOOLONG));
1.2 kristaps 516: if (strlcat(buf, utsname.release, 64) >= 64)
1.35 ! kristaps 517: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 518: }
519:
1.2 kristaps 520: if (NULL == (m->meta.os = strdup(buf)))
1.35 ! kristaps 521: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 522:
1.35 ! kristaps 523: return(post_prol(m, n));
1.1 kristaps 524: }
525:
526:
527: /*
528: * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
529: * Uses the first head macro.
530: */
531: static int
1.35 ! kristaps 532: post_bl_tagwidth(POST_ARGS)
1.1 kristaps 533: {
1.35 ! kristaps 534: struct mdoc_node *nn;
1.1 kristaps 535: int sz;
536: char buf[32];
537:
538: /*
539: * Use the text width, if a text node, or the default macro
540: * width if a macro.
541: */
542:
1.35 ! kristaps 543: nn = n->body->child;
! 544: if (nn) {
! 545: assert(MDOC_BLOCK == nn->type);
! 546: assert(MDOC_It == nn->tok);
! 547: nn = nn->head->child;
1.1 kristaps 548: }
549:
550: sz = 10; /* Default size. */
551:
1.35 ! kristaps 552: if (nn) {
! 553: if (MDOC_TEXT != nn->type) {
! 554: if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
! 555: if ( ! mdoc_nwarn(m, n, ENOWIDTH))
1.1 kristaps 556: return(0);
557: } else
1.35 ! kristaps 558: sz = (int)strlen(nn->string) + 1;
1.1 kristaps 559: }
560:
1.2 kristaps 561: if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
1.35 ! kristaps 562: return(mdoc_nerr(m, n, ENUMFMT));
1.1 kristaps 563:
564: /*
565: * We have to dynamically add this to the macro's argument list.
566: * We're guaranteed that a MDOC_Width doesn't already exist.
567: */
568:
1.35 ! kristaps 569: nn = n;
! 570: assert(nn->args);
! 571: sz = (int)(nn->args->argc)++;
1.1 kristaps 572:
1.35 ! kristaps 573: nn->args->argv = realloc(nn->args->argv,
! 574: nn->args->argc * sizeof(struct mdoc_argv));
1.1 kristaps 575:
1.35 ! kristaps 576: if (NULL == nn->args->argv)
! 577: return(mdoc_nerr(m, n, EMALLOC));
1.2 kristaps 578:
1.35 ! kristaps 579: nn->args->argv[sz].arg = MDOC_Width;
! 580: nn->args->argv[sz].line = n->line;
! 581: nn->args->argv[sz].pos = n->pos;
! 582: nn->args->argv[sz].sz = 1;
! 583: nn->args->argv[sz].value = calloc(1, sizeof(char *));
1.2 kristaps 584:
1.35 ! kristaps 585: if (NULL == nn->args->argv[sz].value)
! 586: return(mdoc_nerr(m, n, EMALLOC));
! 587: if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
! 588: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 589:
590: return(1);
591: }
592:
593:
594: static int
1.35 ! kristaps 595: post_bl_width(POST_ARGS)
1.1 kristaps 596: {
597: size_t width;
598: int i, tok;
599: char buf[32];
600: char *p;
601:
1.35 ! kristaps 602: if (NULL == n->args)
1.1 kristaps 603: return(1);
604:
1.35 ! kristaps 605: for (i = 0; i < (int)n->args->argc; i++)
! 606: if (MDOC_Width == n->args->argv[i].arg)
1.1 kristaps 607: break;
608:
1.35 ! kristaps 609: if (i == (int)n->args->argc)
1.1 kristaps 610: return(1);
1.35 ! kristaps 611: p = n->args->argv[i].value[0];
1.1 kristaps 612:
613: /*
614: * If the value to -width is a macro, then we re-write it to be
615: * the macro's width as set in share/tmac/mdoc/doc-common.
616: */
617:
1.2 kristaps 618: if (0 == strcmp(p, "Ds"))
1.18 kristaps 619: width = 6;
1.3 kristaps 620: else if (MDOC_MAX == (tok = mdoc_hash_find(m->htab, p)))
1.1 kristaps 621: return(1);
622: else if (0 == (width = mdoc_macro2len(tok)))
1.35 ! kristaps 623: return(mdoc_nwarn(m, n, ENOWIDTH));
1.1 kristaps 624:
625: /* The value already exists: free and reallocate it. */
626:
1.2 kristaps 627: if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
1.35 ! kristaps 628: return(mdoc_nerr(m, n, ENUMFMT));
1.1 kristaps 629:
1.35 ! kristaps 630: free(n->args->argv[i].value[0]);
! 631: n->args->argv[i].value[0] = strdup(buf);
! 632: if (NULL == n->args->argv[i].value[0])
! 633: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 634:
635: return(1);
636: }
637:
638:
1.35 ! kristaps 639: /* ARGSUSED */
1.1 kristaps 640: static int
1.14 kristaps 641: post_bl_head(POST_ARGS)
642: {
643: int i, c;
1.35 ! kristaps 644: struct mdoc_node *np, *nn, *nnp;
1.14 kristaps 645:
1.35 ! kristaps 646: if (NULL == n->child)
1.14 kristaps 647: return(1);
648:
1.35 ! kristaps 649: np = n->parent;
! 650: assert(np->args);
1.14 kristaps 651:
1.35 ! kristaps 652: for (c = 0; c < (int)np->args->argc; c++)
! 653: if (MDOC_Column == np->args->argv[c].arg)
1.14 kristaps 654: break;
655:
656: /* Only process -column. */
657:
1.35 ! kristaps 658: if (c == (int)np->args->argc)
1.14 kristaps 659: return(1);
660:
1.35 ! kristaps 661: assert(0 == np->args->argv[c].sz);
1.14 kristaps 662:
663: /*
664: * Accomodate for new-style groff column syntax. Shuffle the
665: * child nodes, all of which must be TEXT, as arguments for the
666: * column field. Then, delete the head children.
667: */
668:
1.35 ! kristaps 669: np->args->argv[c].sz = (size_t)n->nchild;
! 670: np->args->argv[c].value = malloc
! 671: ((size_t)n->nchild * sizeof(char *));
1.14 kristaps 672:
1.35 ! kristaps 673: for (i = 0, nn = n->child; nn; i++) {
! 674: np->args->argv[c].value[i] = nn->string;
1.14 kristaps 675: nn->string = NULL;
676: nnp = nn;
677: nn = nn->next;
678: mdoc_node_free(nnp);
679: }
680:
1.35 ! kristaps 681: n->nchild = 0;
! 682: n->child = NULL;
1.17 kristaps 683:
1.14 kristaps 684: return(1);
685: }
686:
687:
688: static int
1.1 kristaps 689: post_bl(POST_ARGS)
690: {
691: int i, r, len;
692:
1.35 ! kristaps 693: if (MDOC_HEAD == n->type)
! 694: return(post_bl_head(m, n));
! 695: if (MDOC_BLOCK != n->type)
1.1 kristaps 696: return(1);
697:
698: /*
699: * These are fairly complicated, so we've broken them into two
700: * functions. post_bl_tagwidth() is called when a -tag is
701: * specified, but no -width (it must be guessed). The second
702: * when a -width is specified (macro indicators must be
703: * rewritten into real lengths).
704: */
705:
1.35 ! kristaps 706: len = (int)(n->args ? n->args->argc : 0);
1.1 kristaps 707:
708: for (r = i = 0; i < len; i++) {
1.35 ! kristaps 709: if (MDOC_Tag == n->args->argv[i].arg)
1.1 kristaps 710: r |= 1 << 0;
1.35 ! kristaps 711: if (MDOC_Width == n->args->argv[i].arg)
1.1 kristaps 712: r |= 1 << 1;
713: }
714:
715: if (r & (1 << 0) && ! (r & (1 << 1))) {
1.35 ! kristaps 716: if ( ! post_bl_tagwidth(m, n))
1.1 kristaps 717: return(0);
718: } else if (r & (1 << 1))
1.35 ! kristaps 719: if ( ! post_bl_width(m, n))
1.1 kristaps 720: return(0);
721:
722: return(1);
723: }
724:
725:
726: static int
1.31 kristaps 727: post_tilde(POST_ARGS)
1.10 kristaps 728: {
1.35 ! kristaps 729: struct mdoc_node *np;
1.10 kristaps 730:
1.35 ! kristaps 731: if (n->child)
1.10 kristaps 732: return(1);
733:
1.35 ! kristaps 734: np = n;
1.10 kristaps 735: m->next = MDOC_NEXT_CHILD;
1.24 kristaps 736:
1.31 kristaps 737: /* XXX: not documented for `Lk'. */
1.35 ! kristaps 738: if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
1.10 kristaps 739: return(0);
1.35 ! kristaps 740: m->last = np;
1.10 kristaps 741:
742: return(1);
743: }
744:
745:
746: static int
1.1 kristaps 747: post_ar(POST_ARGS)
748: {
1.35 ! kristaps 749: struct mdoc_node *np;
1.1 kristaps 750:
1.35 ! kristaps 751: if (n->child)
1.1 kristaps 752: return(1);
753:
1.35 ! kristaps 754: np = n;
1.1 kristaps 755: m->next = MDOC_NEXT_CHILD;
1.35 ! kristaps 756: if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
1.1 kristaps 757: return(0);
1.35 ! kristaps 758: if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
1.1 kristaps 759: return(0);
1.35 ! kristaps 760: m->last = np;
1.1 kristaps 761:
762: return(1);
763: }
764:
765:
766: static int
767: post_dd(POST_ARGS)
768: {
769: char buf[64];
770:
1.5 kristaps 771: buf[0] = 0;
1.35 ! kristaps 772: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.2 kristaps 773: return(0);
1.1 kristaps 774:
775: if (0 == (m->meta.date = mdoc_atotime(buf))) {
1.35 ! kristaps 776: if ( ! mdoc_nwarn(m, n, EBADDATE))
1.1 kristaps 777: return(0);
778: m->meta.date = time(NULL);
779: }
780:
1.35 ! kristaps 781: return(post_prol(m, n));
1.1 kristaps 782: }
783:
784:
785: static int
786: post_prol(POST_ARGS)
787: {
1.35 ! kristaps 788: struct mdoc_node *np;
1.1 kristaps 789:
1.35 ! kristaps 790: /* Remove prologue macros from AST. */
1.1 kristaps 791:
1.35 ! kristaps 792: if (n->parent->child == n)
! 793: n->parent->child = n->prev;
! 794: if (n->prev)
! 795: n->prev->next = NULL;
1.1 kristaps 796:
1.35 ! kristaps 797: np = n;
! 798: assert(NULL == n->next);
1.1 kristaps 799:
1.35 ! kristaps 800: if (n->prev) {
! 801: m->last = n->prev;
1.1 kristaps 802: m->next = MDOC_NEXT_SIBLING;
803: } else {
1.35 ! kristaps 804: m->last = n->parent;
1.1 kristaps 805: m->next = MDOC_NEXT_CHILD;
806: }
807:
1.35 ! kristaps 808: mdoc_node_freelist(np);
1.34 kristaps 809:
810: if (m->meta.title && m->meta.date && m->meta.os)
811: m->flags |= MDOC_PBODY;
1.35 ! kristaps 812:
1.1 kristaps 813: return(1);
814: }
815:
816:
817: static int
818: pre_dl(PRE_ARGS)
819: {
820:
1.16 kristaps 821: if (MDOC_BODY == n->type)
822: m->flags |= MDOC_LITERAL;
1.1 kristaps 823: return(1);
824: }
825:
826:
827: static int
828: pre_bd(PRE_ARGS)
829: {
830: int i;
831:
832: if (MDOC_BODY != n->type)
833: return(1);
834:
1.32 kristaps 835: /* Enter literal context if `Bd -literal' or `-unfilled'. */
836:
837: /*
838: * TODO: `-offset' without an argument should be the width of
839: * the literal "<string>".
840: */
1.1 kristaps 841:
1.2 kristaps 842: for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
1.1 kristaps 843: if (MDOC_Literal == n->args->argv[i].arg)
844: break;
845: else if (MDOC_Unfilled == n->args->argv[i].arg)
846: break;
847:
848: if (i < (int)n->args->argc)
849: m->flags |= MDOC_LITERAL;
850:
851: return(1);
852: }
853:
854:
855: static int
856: post_display(POST_ARGS)
857: {
858:
1.35 ! kristaps 859: if (MDOC_BODY == n->type)
1.1 kristaps 860: m->flags &= ~MDOC_LITERAL;
861: return(1);
862: }
863:
864:
CVSweb