Annotation of src/usr.bin/mandoc/mdoc_action.c, Revision 1.24
1.24 ! schwarze 1: /* $Id: mdoc_action.c,v 1.23 2009/10/19 16:27:52 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: */
1.24 ! schwarze 17: #ifndef OSNAME
1.1 kristaps 18: #include <sys/utsname.h>
1.24 ! schwarze 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.24 ! schwarze 26: #include <time.h>
1.1 kristaps 27:
28: #include "libmdoc.h"
29:
1.20 schwarze 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.23 schwarze 38: static int concat(struct mdoc *,
39: const struct mdoc_node *,
40: char *, size_t);
41: static inline int order_rs(int);
42:
1.1 kristaps 43: static int post_ar(POST_ARGS);
1.15 schwarze 44: static int post_at(POST_ARGS);
1.1 kristaps 45: static int post_bl(POST_ARGS);
1.6 schwarze 46: static int post_bl_head(POST_ARGS);
1.15 schwarze 47: static int post_bl_tagwidth(POST_ARGS);
1.1 kristaps 48: static int post_bl_width(POST_ARGS);
49: static int post_dd(POST_ARGS);
50: static int post_display(POST_ARGS);
51: static int post_dt(POST_ARGS);
1.15 schwarze 52: static int post_lb(POST_ARGS);
1.1 kristaps 53: static int post_nm(POST_ARGS);
54: static int post_os(POST_ARGS);
55: static int post_prol(POST_ARGS);
1.23 schwarze 56: static int post_rs(POST_ARGS);
1.1 kristaps 57: static int post_sh(POST_ARGS);
1.15 schwarze 58: static int post_st(POST_ARGS);
1.1 kristaps 59: static int post_std(POST_ARGS);
1.17 schwarze 60: static int post_tilde(POST_ARGS);
1.1 kristaps 61:
62: static int pre_bd(PRE_ARGS);
1.22 schwarze 63: static int pre_bl(PRE_ARGS);
1.1 kristaps 64: static int pre_dl(PRE_ARGS);
1.22 schwarze 65: static int pre_offset(PRE_ARGS);
1.1 kristaps 66:
1.21 schwarze 67: static const struct actions mdoc_actions[MDOC_MAX] = {
1.4 schwarze 68: { NULL, NULL }, /* Ap */
1.1 kristaps 69: { NULL, post_dd }, /* Dd */
70: { NULL, post_dt }, /* Dt */
71: { NULL, post_os }, /* Os */
72: { NULL, post_sh }, /* Sh */
73: { NULL, NULL }, /* Ss */
74: { NULL, NULL }, /* Pp */
75: { NULL, NULL }, /* D1 */
76: { pre_dl, post_display }, /* Dl */
77: { pre_bd, post_display }, /* Bd */
78: { NULL, NULL }, /* Ed */
1.22 schwarze 79: { pre_bl, post_bl }, /* Bl */
1.1 kristaps 80: { NULL, NULL }, /* El */
81: { NULL, NULL }, /* It */
82: { NULL, NULL }, /* Ad */
83: { NULL, NULL }, /* An */
84: { NULL, post_ar }, /* Ar */
1.20 schwarze 85: { NULL, NULL }, /* Cd */
1.1 kristaps 86: { NULL, NULL }, /* Cm */
87: { NULL, NULL }, /* Dv */
88: { NULL, NULL }, /* Er */
89: { NULL, NULL }, /* Ev */
90: { NULL, post_std }, /* Ex */
91: { NULL, NULL }, /* Fa */
92: { NULL, NULL }, /* Fd */
93: { NULL, NULL }, /* Fl */
94: { NULL, NULL }, /* Fn */
95: { NULL, NULL }, /* Ft */
96: { NULL, NULL }, /* Ic */
97: { NULL, NULL }, /* In */
98: { NULL, NULL }, /* Li */
99: { NULL, NULL }, /* Nd */
100: { NULL, post_nm }, /* Nm */
101: { NULL, NULL }, /* Op */
102: { NULL, NULL }, /* Ot */
1.17 schwarze 103: { NULL, post_tilde }, /* Pa */
1.1 kristaps 104: { NULL, post_std }, /* Rv */
1.15 schwarze 105: { NULL, post_st }, /* St */
1.1 kristaps 106: { NULL, NULL }, /* Va */
107: { NULL, NULL }, /* Vt */
108: { NULL, NULL }, /* Xr */
109: { NULL, NULL }, /* %A */
110: { NULL, NULL }, /* %B */
111: { NULL, NULL }, /* %D */
112: { NULL, NULL }, /* %I */
113: { NULL, NULL }, /* %J */
114: { NULL, NULL }, /* %N */
115: { NULL, NULL }, /* %O */
116: { NULL, NULL }, /* %P */
117: { NULL, NULL }, /* %R */
118: { NULL, NULL }, /* %T */
119: { NULL, NULL }, /* %V */
120: { NULL, NULL }, /* Ac */
121: { NULL, NULL }, /* Ao */
122: { NULL, NULL }, /* Aq */
1.15 schwarze 123: { NULL, post_at }, /* At */
1.1 kristaps 124: { NULL, NULL }, /* Bc */
125: { NULL, NULL }, /* Bf */
126: { NULL, NULL }, /* Bo */
127: { NULL, NULL }, /* Bq */
128: { NULL, NULL }, /* Bsx */
129: { NULL, NULL }, /* Bx */
130: { NULL, NULL }, /* Db */
131: { NULL, NULL }, /* Dc */
132: { NULL, NULL }, /* Do */
133: { NULL, NULL }, /* Dq */
134: { NULL, NULL }, /* Ec */
135: { NULL, NULL }, /* Ef */
136: { NULL, NULL }, /* Em */
137: { NULL, NULL }, /* Eo */
138: { NULL, NULL }, /* Fx */
139: { NULL, NULL }, /* Ms */
140: { NULL, NULL }, /* No */
141: { NULL, NULL }, /* Ns */
142: { NULL, NULL }, /* Nx */
143: { NULL, NULL }, /* Ox */
144: { NULL, NULL }, /* Pc */
145: { NULL, NULL }, /* Pf */
146: { NULL, NULL }, /* Po */
147: { NULL, NULL }, /* Pq */
148: { NULL, NULL }, /* Qc */
149: { NULL, NULL }, /* Ql */
150: { NULL, NULL }, /* Qo */
151: { NULL, NULL }, /* Qq */
152: { NULL, NULL }, /* Re */
1.23 schwarze 153: { NULL, post_rs }, /* Rs */
1.1 kristaps 154: { NULL, NULL }, /* Sc */
155: { NULL, NULL }, /* So */
156: { NULL, NULL }, /* Sq */
157: { NULL, NULL }, /* Sm */
158: { NULL, NULL }, /* Sx */
159: { NULL, NULL }, /* Sy */
160: { NULL, NULL }, /* Tn */
161: { NULL, NULL }, /* Ux */
162: { NULL, NULL }, /* Xc */
163: { NULL, NULL }, /* Xo */
164: { NULL, NULL }, /* Fo */
165: { NULL, NULL }, /* Fc */
166: { NULL, NULL }, /* Oo */
167: { NULL, NULL }, /* Oc */
168: { NULL, NULL }, /* Bk */
169: { NULL, NULL }, /* Ek */
170: { NULL, NULL }, /* Bt */
171: { NULL, NULL }, /* Hf */
172: { NULL, NULL }, /* Fr */
173: { NULL, NULL }, /* Ud */
1.15 schwarze 174: { NULL, post_lb }, /* Lb */
1.1 kristaps 175: { NULL, NULL }, /* Lp */
1.24 ! schwarze 176: { NULL, NULL }, /* Lk */
1.1 kristaps 177: { NULL, NULL }, /* Mt */
178: { NULL, NULL }, /* Brq */
179: { NULL, NULL }, /* Bro */
180: { NULL, NULL }, /* Brc */
181: { NULL, NULL }, /* %C */
182: { NULL, NULL }, /* Es */
183: { NULL, NULL }, /* En */
184: { NULL, NULL }, /* Dx */
185: { NULL, NULL }, /* %Q */
1.16 schwarze 186: { NULL, NULL }, /* br */
187: { NULL, NULL }, /* sp */
1.24 ! schwarze 188: { NULL, NULL }, /* %U */
1.1 kristaps 189: };
190:
1.24 ! schwarze 191: #define RSORD_MAX 14
1.23 schwarze 192:
193: static const int rsord[RSORD_MAX] = {
194: MDOC__A,
195: MDOC__T,
196: MDOC__B,
197: MDOC__I,
198: MDOC__J,
199: MDOC__R,
200: MDOC__N,
201: MDOC__V,
202: MDOC__P,
203: MDOC__Q,
204: MDOC__D,
205: MDOC__O,
1.24 ! schwarze 206: MDOC__C,
! 207: MDOC__U
1.23 schwarze 208: };
1.15 schwarze 209:
1.1 kristaps 210:
211: int
212: mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
213: {
214:
215: switch (n->type) {
216: case (MDOC_ROOT):
217: /* FALLTHROUGH */
218: case (MDOC_TEXT):
219: return(1);
220: default:
221: break;
222: }
223:
224: if (NULL == mdoc_actions[n->tok].pre)
225: return(1);
226: return((*mdoc_actions[n->tok].pre)(m, n));
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):
240: /* FALLTHROUGH */
241: case (MDOC_ROOT):
242: return(1);
243: default:
244: break;
245: }
246:
247: if (NULL == mdoc_actions[m->last->tok].post)
248: return(1);
1.20 schwarze 249: return((*mdoc_actions[m->last->tok].post)(m, m->last));
1.1 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.12 schwarze 261: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 262: if (NULL == n->next)
263: continue;
264: if (strlcat(buf, " ", sz) >= sz)
1.12 schwarze 265: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 266: }
267:
268: return(1);
269: }
270:
271:
272: static int
273: post_std(POST_ARGS)
274: {
1.20 schwarze 275: struct mdoc_node *nn;
1.1 kristaps 276:
1.20 schwarze 277: if (n->child)
1.1 kristaps 278: return(1);
1.20 schwarze 279:
280: nn = n;
281: m->next = MDOC_NEXT_CHILD;
1.1 kristaps 282: assert(m->meta.name);
1.20 schwarze 283: if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
284: return(0);
285: m->last = nn;
1.1 kristaps 286:
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);
298:
299: buf[0] = 0;
1.20 schwarze 300: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 301: return(0);
302: if (NULL == (m->meta.name = strdup(buf)))
1.20 schwarze 303: return(mdoc_nerr(m, n, EMALLOC));
1.2 schwarze 304:
1.1 kristaps 305: return(1);
306: }
307:
308:
309: static int
1.15 schwarze 310: post_lb(POST_ARGS)
311: {
312: const char *p;
313: char *buf;
314: size_t sz;
315:
1.20 schwarze 316: assert(MDOC_TEXT == n->child->type);
317: p = mdoc_a2lib(n->child->string);
1.15 schwarze 318: if (NULL == p) {
1.20 schwarze 319: sz = strlen(n->child->string) +
1.15 schwarze 320: 2 + strlen("\\(lqlibrary\\(rq");
321: buf = malloc(sz);
322: if (NULL == buf)
1.20 schwarze 323: return(mdoc_nerr(m, n, EMALLOC));
1.15 schwarze 324: (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
1.20 schwarze 325: n->child->string);
326: free(n->child->string);
327: n->child->string = buf;
1.15 schwarze 328: return(1);
329: }
330:
1.20 schwarze 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.15 schwarze 336: return(1);
337: }
338:
339:
340: static int
341: post_st(POST_ARGS)
342: {
343: const char *p;
344:
1.20 schwarze 345: assert(MDOC_TEXT == n->child->type);
346: p = mdoc_a2st(n->child->string);
1.15 schwarze 347: assert(p);
1.20 schwarze 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.15 schwarze 353: return(1);
354: }
355:
356:
357: static int
358: post_at(POST_ARGS)
359: {
1.20 schwarze 360: struct mdoc_node *nn;
361: const char *p;
1.15 schwarze 362:
1.20 schwarze 363: if (n->child) {
364: assert(MDOC_TEXT == n->child->type);
365: p = mdoc_a2att(n->child->string);
1.15 schwarze 366: assert(p);
1.20 schwarze 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.15 schwarze 371: return(1);
372: }
373:
1.20 schwarze 374: nn = n;
1.15 schwarze 375: m->next = MDOC_NEXT_CHILD;
376:
1.20 schwarze 377: if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
1.15 schwarze 378: return(0);
1.20 schwarze 379: m->last = nn;
1.15 schwarze 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.20 schwarze 397: if (MDOC_HEAD != n->type)
1.1 kristaps 398: return(1);
399:
400: buf[0] = 0;
1.20 schwarze 401: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 402: return(0);
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.20 schwarze 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.20 schwarze 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.20 schwarze 450: if (NULL == (nn = n->child)) {
1.1 kristaps 451: if (NULL == (m->meta.title = strdup("unknown")))
1.20 schwarze 452: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 453: if (NULL == (m->meta.vol = strdup("local")))
1.20 schwarze 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.20 schwarze 462: if (NULL == (m->meta.title = strdup(nn->string)))
463: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 464:
1.20 schwarze 465: if (NULL == (nn = nn->next)) {
1.1 kristaps 466: if (NULL == (m->meta.vol = strdup("local")))
1.20 schwarze 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.20 schwarze 478: cp = mdoc_a2msec(nn->string);
1.1 kristaps 479: if (cp) {
480: if (NULL == (m->meta.vol = strdup(cp)))
1.20 schwarze 481: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 482: errno = 0;
1.20 schwarze 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.20 schwarze 486: } else if (NULL == (m->meta.vol = strdup(nn->string)))
487: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 488:
1.20 schwarze 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.20 schwarze 499: cp = mdoc_a2vol(nn->string);
1.1 kristaps 500: if (cp) {
501: free(m->meta.vol);
502: if (NULL == (m->meta.vol = strdup(cp)))
1.20 schwarze 503: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 504: } else {
1.20 schwarze 505: cp = mdoc_a2arch(nn->string);
1.1 kristaps 506: if (NULL == cp) {
507: free(m->meta.vol);
1.20 schwarze 508: if (NULL == (m->meta.vol = strdup(nn->string)))
509: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 510: } else if (NULL == (m->meta.arch = strdup(cp)))
1.20 schwarze 511: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 512: }
513:
514: /* Ignore any subsequent parameters... */
515:
1.20 schwarze 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.24 ! schwarze 524: #ifndef OSNAME
1.1 kristaps 525: struct utsname utsname;
1.24 ! schwarze 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);
536:
537: buf[0] = 0;
1.20 schwarze 538: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 539: return(0);
540:
541: if (0 == buf[0]) {
1.24 ! schwarze 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.20 schwarze 547: return(mdoc_nerr(m, n, EUTSNAME));
1.1 kristaps 548: if (strlcat(buf, utsname.sysname, 64) >= 64)
1.20 schwarze 549: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 550: if (strlcat(buf, " ", 64) >= 64)
1.20 schwarze 551: return(mdoc_nerr(m, n, ETOOLONG));
1.1 kristaps 552: if (strlcat(buf, utsname.release, 64) >= 64)
1.20 schwarze 553: return(mdoc_nerr(m, n, ETOOLONG));
1.24 ! schwarze 554: #endif
1.1 kristaps 555: }
556:
557: if (NULL == (m->meta.os = strdup(buf)))
1.20 schwarze 558: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 559:
1.20 schwarze 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.20 schwarze 569: post_bl_tagwidth(POST_ARGS)
1.1 kristaps 570: {
1.20 schwarze 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.20 schwarze 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.20 schwarze 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.20 schwarze 595: sz = (int)strlen(nn->string) + 1;
1.1 kristaps 596: }
597:
598: if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
1.20 schwarze 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.20 schwarze 606: nn = n;
607: assert(nn->args);
608: sz = (int)(nn->args->argc)++;
1.1 kristaps 609:
1.20 schwarze 610: nn->args->argv = realloc(nn->args->argv,
611: nn->args->argc * sizeof(struct mdoc_argv));
1.1 kristaps 612:
1.20 schwarze 613: if (NULL == nn->args->argv)
614: return(mdoc_nerr(m, n, EMALLOC));
1.1 kristaps 615:
1.20 schwarze 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.1 kristaps 621:
1.20 schwarze 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.20 schwarze 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.20 schwarze 639: if (NULL == n->args)
1.1 kristaps 640: return(1);
641:
1.20 schwarze 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.20 schwarze 646: if (i == (int)n->args->argc)
1.1 kristaps 647: return(1);
1.20 schwarze 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:
655: if (0 == strcmp(p, "Ds"))
1.9 schwarze 656: width = 6;
1.21 schwarze 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.20 schwarze 660: return(mdoc_nwarn(m, n, ENOWIDTH));
1.1 kristaps 661:
662: /* The value already exists: free and reallocate it. */
663:
664: if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
1.20 schwarze 665: return(mdoc_nerr(m, n, ENUMFMT));
1.1 kristaps 666:
1.20 schwarze 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.20 schwarze 676: /* ARGSUSED */
1.1 kristaps 677: static int
1.6 schwarze 678: post_bl_head(POST_ARGS)
679: {
680: int i, c;
1.20 schwarze 681: struct mdoc_node *np, *nn, *nnp;
1.6 schwarze 682:
1.20 schwarze 683: if (NULL == n->child)
1.6 schwarze 684: return(1);
685:
1.20 schwarze 686: np = n->parent;
687: assert(np->args);
1.6 schwarze 688:
1.20 schwarze 689: for (c = 0; c < (int)np->args->argc; c++)
690: if (MDOC_Column == np->args->argv[c].arg)
1.6 schwarze 691: break;
692:
693: /* Only process -column. */
694:
1.20 schwarze 695: if (c == (int)np->args->argc)
1.6 schwarze 696: return(1);
697:
1.20 schwarze 698: assert(0 == np->args->argv[c].sz);
1.6 schwarze 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.20 schwarze 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.6 schwarze 709:
1.20 schwarze 710: for (i = 0, nn = n->child; nn; i++) {
711: np->args->argv[c].value[i] = nn->string;
1.6 schwarze 712: nn->string = NULL;
713: nnp = nn;
714: nn = nn->next;
715: mdoc_node_free(nnp);
716: }
717:
1.20 schwarze 718: n->nchild = 0;
719: n->child = NULL;
1.8 schwarze 720:
1.6 schwarze 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.20 schwarze 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.20 schwarze 743: len = (int)(n->args ? n->args->argc : 0);
1.1 kristaps 744:
745: for (r = i = 0; i < len; i++) {
1.20 schwarze 746: if (MDOC_Tag == n->args->argv[i].arg)
1.1 kristaps 747: r |= 1 << 0;
1.20 schwarze 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.20 schwarze 753: if ( ! post_bl_tagwidth(m, n))
1.1 kristaps 754: return(0);
755: } else if (r & (1 << 1))
1.20 schwarze 756: if ( ! post_bl_width(m, n))
1.1 kristaps 757: return(0);
758:
1.3 schwarze 759: return(1);
760: }
761:
762:
763: static int
1.17 schwarze 764: post_tilde(POST_ARGS)
1.3 schwarze 765: {
1.20 schwarze 766: struct mdoc_node *np;
1.3 schwarze 767:
1.20 schwarze 768: if (n->child)
1.3 schwarze 769: return(1);
770:
1.20 schwarze 771: np = n;
1.3 schwarze 772: m->next = MDOC_NEXT_CHILD;
1.15 schwarze 773:
1.20 schwarze 774: if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
1.3 schwarze 775: return(0);
1.20 schwarze 776: m->last = np;
1.3 schwarze 777:
1.1 kristaps 778: return(1);
779: }
780:
781:
782: static int
783: post_ar(POST_ARGS)
784: {
1.20 schwarze 785: struct mdoc_node *np;
1.1 kristaps 786:
1.20 schwarze 787: if (n->child)
1.1 kristaps 788: return(1);
789:
1.20 schwarze 790: np = n;
1.1 kristaps 791: m->next = MDOC_NEXT_CHILD;
1.20 schwarze 792: if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
1.1 kristaps 793: return(0);
1.20 schwarze 794: if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
1.1 kristaps 795: return(0);
1.20 schwarze 796: m->last = np;
1.1 kristaps 797:
798: return(1);
799: }
800:
801:
802: static int
803: post_dd(POST_ARGS)
804: {
805: char buf[64];
806:
807: buf[0] = 0;
1.20 schwarze 808: if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1 kristaps 809: return(0);
810:
811: if (0 == (m->meta.date = mdoc_atotime(buf))) {
1.20 schwarze 812: if ( ! mdoc_nwarn(m, n, EBADDATE))
1.1 kristaps 813: return(0);
814: m->meta.date = time(NULL);
815: }
816:
1.20 schwarze 817: return(post_prol(m, n));
1.1 kristaps 818: }
819:
820:
821: static int
822: post_prol(POST_ARGS)
823: {
1.20 schwarze 824: struct mdoc_node *np;
1.1 kristaps 825:
1.20 schwarze 826: /* Remove prologue macros from AST. */
1.1 kristaps 827:
1.20 schwarze 828: if (n->parent->child == n)
829: n->parent->child = n->prev;
830: if (n->prev)
831: n->prev->next = NULL;
1.1 kristaps 832:
1.20 schwarze 833: np = n;
834: assert(NULL == n->next);
1.1 kristaps 835:
1.20 schwarze 836: if (n->prev) {
837: m->last = n->prev;
1.1 kristaps 838: m->next = MDOC_NEXT_SIBLING;
839: } else {
1.20 schwarze 840: m->last = n->parent;
1.1 kristaps 841: m->next = MDOC_NEXT_CHILD;
842: }
843:
1.20 schwarze 844: mdoc_node_freelist(np);
1.18 schwarze 845:
846: if (m->meta.title && m->meta.date && m->meta.os)
847: m->flags |= MDOC_PBODY;
1.20 schwarze 848:
1.1 kristaps 849: return(1);
850: }
851:
852:
853: static int
854: pre_dl(PRE_ARGS)
855: {
856:
1.7 schwarze 857: if (MDOC_BODY == n->type)
858: m->flags |= MDOC_LITERAL;
1.1 kristaps 859: return(1);
860: }
861:
862:
863: static int
1.22 schwarze 864: pre_offset(PRE_ARGS)
865: {
866: int i;
867:
868: /*
869: * Make sure that an empty offset produces an 8n length space as
870: * stipulated by mdoc.samples.
871: */
872:
873: assert(n->args);
874: for (i = 0; i < (int)n->args->argc; i++) {
875: if (MDOC_Offset != n->args->argv[i].arg)
876: continue;
877: if (n->args->argv[i].sz)
878: break;
879: assert(1 == n->args->refcnt);
880: /* If no value set, length of <string>. */
881: n->args->argv[i].value =
882: calloc(1, sizeof(char *));
883: if (NULL == n->args->argv[i].value)
884: return(mdoc_nerr(m, n, EMALLOC));
885: n->args->argv[i].sz++;
886: n->args->argv[i].value[0] = strdup("8n");
887: if (NULL == n->args->argv[i].value[0])
888: return(mdoc_nerr(m, n, EMALLOC));
889: break;
890: }
891:
892: return(1);
893: }
894:
895:
896: static int
897: pre_bl(PRE_ARGS)
898: {
899:
900: return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
901: }
902:
903:
904: static int
1.1 kristaps 905: pre_bd(PRE_ARGS)
906: {
907: int i;
908:
1.22 schwarze 909: if (MDOC_BLOCK == n->type)
910: return(pre_offset(m, n));
1.1 kristaps 911: if (MDOC_BODY != n->type)
912: return(1);
913:
1.19 schwarze 914: /* Enter literal context if `Bd -literal' or `-unfilled'. */
915:
1.1 kristaps 916: for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
917: if (MDOC_Literal == n->args->argv[i].arg)
1.22 schwarze 918: m->flags |= MDOC_LITERAL;
1.1 kristaps 919: else if (MDOC_Unfilled == n->args->argv[i].arg)
1.22 schwarze 920: m->flags |= MDOC_LITERAL;
1.1 kristaps 921:
922: return(1);
923: }
924:
925:
926: static int
927: post_display(POST_ARGS)
928: {
929:
1.20 schwarze 930: if (MDOC_BODY == n->type)
1.1 kristaps 931: m->flags &= ~MDOC_LITERAL;
932: return(1);
933: }
934:
935:
1.23 schwarze 936: static inline int
937: order_rs(int t)
938: {
939: int i;
940:
941: for (i = 0; i < RSORD_MAX; i++)
942: if (rsord[i] == t)
943: return(i);
944:
945: abort();
946: /* NOTREACHED */
947: }
948:
949:
950: /* ARGSUSED */
951: static int
952: post_rs(POST_ARGS)
953: {
954: struct mdoc_node *nn, *next, *prev;
955: int o;
956:
957: if (MDOC_BLOCK != n->type)
958: return(1);
959:
960: assert(n->body->child);
961: for (next = NULL, nn = n->body->child->next; nn; nn = next) {
962: o = order_rs(nn->tok);
963:
964: /* Remove `nn' from the chain. */
965: next = nn->next;
966: if (next)
967: next->prev = nn->prev;
968:
969: prev = nn->prev;
970: if (prev)
971: prev->next = nn->next;
972:
973: nn->prev = nn->next = NULL;
974:
975: /*
976: * Scan back until we reach a node that's ordered before
977: * us, then set ourselves as being the next.
978: */
979: for ( ; prev; prev = prev->prev)
980: if (order_rs(prev->tok) <= o)
981: break;
982:
983: nn->prev = prev;
984: if (prev) {
985: if (prev->next)
986: prev->next->prev = nn;
987: nn->next = prev->next;
988: prev->next = nn;
989: continue;
990: }
991:
992: n->body->child->prev = nn;
993: nn->next = n->body->child;
994: n->body->child = nn;
995: }
996: return(1);
997: }