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