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