Annotation of src/usr.bin/mandoc/mdoc_term.c, Revision 1.81
1.81 ! schwarze 1: /* $Id: mdoc_term.c,v 1.80 2010/05/15 21:09:53 schwarze Exp $ */
1.1 kristaps 2: /*
1.2 schwarze 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.2 schwarze 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.2 schwarze 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
17: #include <sys/types.h>
18:
19: #include <assert.h>
20: #include <ctype.h>
1.77 schwarze 21: #include <stdint.h>
1.1 kristaps 22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <string.h>
25:
1.81 ! schwarze 26: #include "mandoc.h"
1.61 schwarze 27: #include "out.h"
1.1 kristaps 28: #include "term.h"
29: #include "mdoc.h"
1.61 schwarze 30: #include "chars.h"
31: #include "main.h"
1.54 schwarze 32:
1.51 schwarze 33: #define INDENT 5
34: #define HALFINDENT 3
1.1 kristaps 35:
36: struct termpair {
37: struct termpair *ppair;
1.27 schwarze 38: int count;
1.1 kristaps 39: };
40:
1.29 schwarze 41: #define DECL_ARGS struct termp *p, \
42: struct termpair *pair, \
1.60 schwarze 43: const struct mdoc_meta *m, \
44: const struct mdoc_node *n
1.1 kristaps 45:
46: struct termact {
47: int (*pre)(DECL_ARGS);
48: void (*post)(DECL_ARGS);
49: };
1.29 schwarze 50:
1.62 schwarze 51: static size_t a2width(const struct mdoc_argv *, int);
52: static size_t a2height(const struct mdoc_node *);
53: static size_t a2offs(const struct mdoc_argv *);
54:
55: static int arg_hasattr(int, const struct mdoc_node *);
56: static int arg_getattrs(const int *, int *, size_t,
57: const struct mdoc_node *);
58: static int arg_getattr(int, const struct mdoc_node *);
1.77 schwarze 59: static int arg_disptype(const struct mdoc_node *);
1.62 schwarze 60: static int arg_listtype(const struct mdoc_node *);
61: static void print_bvspace(struct termp *,
62: const struct mdoc_node *,
63: const struct mdoc_node *);
1.65 schwarze 64: static void print_mdoc_node(DECL_ARGS);
65: static void print_mdoc_head(DECL_ARGS);
66: static void print_mdoc_nodelist(DECL_ARGS);
1.62 schwarze 67: static void print_foot(DECL_ARGS);
68:
1.29 schwarze 69: static void termp____post(DECL_ARGS);
1.49 schwarze 70: static void termp_an_post(DECL_ARGS);
1.29 schwarze 71: static void termp_aq_post(DECL_ARGS);
72: static void termp_bd_post(DECL_ARGS);
73: static void termp_bl_post(DECL_ARGS);
74: static void termp_bq_post(DECL_ARGS);
75: static void termp_brq_post(DECL_ARGS);
76: static void termp_bx_post(DECL_ARGS);
77: static void termp_d1_post(DECL_ARGS);
78: static void termp_dq_post(DECL_ARGS);
79: static void termp_fd_post(DECL_ARGS);
80: static void termp_fn_post(DECL_ARGS);
81: static void termp_fo_post(DECL_ARGS);
82: static void termp_ft_post(DECL_ARGS);
83: static void termp_in_post(DECL_ARGS);
84: static void termp_it_post(DECL_ARGS);
85: static void termp_lb_post(DECL_ARGS);
86: static void termp_op_post(DECL_ARGS);
87: static void termp_pf_post(DECL_ARGS);
88: static void termp_pq_post(DECL_ARGS);
89: static void termp_qq_post(DECL_ARGS);
90: static void termp_sh_post(DECL_ARGS);
91: static void termp_sq_post(DECL_ARGS);
92: static void termp_ss_post(DECL_ARGS);
93: static void termp_vt_post(DECL_ARGS);
94:
1.49 schwarze 95: static int termp_an_pre(DECL_ARGS);
1.29 schwarze 96: static int termp_ap_pre(DECL_ARGS);
97: static int termp_aq_pre(DECL_ARGS);
98: static int termp_bd_pre(DECL_ARGS);
99: static int termp_bf_pre(DECL_ARGS);
1.73 schwarze 100: static int termp_bl_pre(DECL_ARGS);
1.54 schwarze 101: static int termp_bold_pre(DECL_ARGS);
1.29 schwarze 102: static int termp_bq_pre(DECL_ARGS);
103: static int termp_brq_pre(DECL_ARGS);
104: static int termp_bt_pre(DECL_ARGS);
105: static int termp_cd_pre(DECL_ARGS);
106: static int termp_d1_pre(DECL_ARGS);
107: static int termp_dq_pre(DECL_ARGS);
108: static int termp_ex_pre(DECL_ARGS);
109: static int termp_fa_pre(DECL_ARGS);
110: static int termp_fl_pre(DECL_ARGS);
111: static int termp_fn_pre(DECL_ARGS);
112: static int termp_fo_pre(DECL_ARGS);
113: static int termp_ft_pre(DECL_ARGS);
114: static int termp_in_pre(DECL_ARGS);
115: static int termp_it_pre(DECL_ARGS);
1.65 schwarze 116: static int termp_li_pre(DECL_ARGS);
1.29 schwarze 117: static int termp_lk_pre(DECL_ARGS);
118: static int termp_nd_pre(DECL_ARGS);
119: static int termp_nm_pre(DECL_ARGS);
120: static int termp_ns_pre(DECL_ARGS);
121: static int termp_op_pre(DECL_ARGS);
122: static int termp_pf_pre(DECL_ARGS);
123: static int termp_pq_pre(DECL_ARGS);
124: static int termp_qq_pre(DECL_ARGS);
125: static int termp_rs_pre(DECL_ARGS);
126: static int termp_rv_pre(DECL_ARGS);
127: static int termp_sh_pre(DECL_ARGS);
128: static int termp_sm_pre(DECL_ARGS);
1.38 schwarze 129: static int termp_sp_pre(DECL_ARGS);
1.29 schwarze 130: static int termp_sq_pre(DECL_ARGS);
131: static int termp_ss_pre(DECL_ARGS);
1.54 schwarze 132: static int termp_under_pre(DECL_ARGS);
1.29 schwarze 133: static int termp_ud_pre(DECL_ARGS);
1.69 schwarze 134: static int termp_vt_pre(DECL_ARGS);
1.29 schwarze 135: static int termp_xr_pre(DECL_ARGS);
136: static int termp_xx_pre(DECL_ARGS);
1.1 kristaps 137:
1.54 schwarze 138: static const struct termact termacts[MDOC_MAX] = {
1.11 schwarze 139: { termp_ap_pre, NULL }, /* Ap */
1.1 kristaps 140: { NULL, NULL }, /* Dd */
141: { NULL, NULL }, /* Dt */
142: { NULL, NULL }, /* Os */
143: { termp_sh_pre, termp_sh_post }, /* Sh */
144: { termp_ss_pre, termp_ss_post }, /* Ss */
1.54 schwarze 145: { termp_sp_pre, NULL }, /* Pp */
1.1 kristaps 146: { termp_d1_pre, termp_d1_post }, /* D1 */
147: { termp_d1_pre, termp_d1_post }, /* Dl */
148: { termp_bd_pre, termp_bd_post }, /* Bd */
149: { NULL, NULL }, /* Ed */
1.73 schwarze 150: { termp_bl_pre, termp_bl_post }, /* Bl */
1.1 kristaps 151: { NULL, NULL }, /* El */
152: { termp_it_pre, termp_it_post }, /* It */
153: { NULL, NULL }, /* Ad */
1.49 schwarze 154: { termp_an_pre, termp_an_post }, /* An */
1.54 schwarze 155: { termp_under_pre, NULL }, /* Ar */
1.1 kristaps 156: { termp_cd_pre, NULL }, /* Cd */
1.54 schwarze 157: { termp_bold_pre, NULL }, /* Cm */
1.1 kristaps 158: { NULL, NULL }, /* Dv */
159: { NULL, NULL }, /* Er */
160: { NULL, NULL }, /* Ev */
161: { termp_ex_pre, NULL }, /* Ex */
162: { termp_fa_pre, NULL }, /* Fa */
1.54 schwarze 163: { termp_bold_pre, termp_fd_post }, /* Fd */
1.1 kristaps 164: { termp_fl_pre, NULL }, /* Fl */
165: { termp_fn_pre, termp_fn_post }, /* Fn */
166: { termp_ft_pre, termp_ft_post }, /* Ft */
1.54 schwarze 167: { termp_bold_pre, NULL }, /* Ic */
1.1 kristaps 168: { termp_in_pre, termp_in_post }, /* In */
1.65 schwarze 169: { termp_li_pre, NULL }, /* Li */
1.1 kristaps 170: { termp_nd_pre, NULL }, /* Nd */
171: { termp_nm_pre, NULL }, /* Nm */
172: { termp_op_pre, termp_op_post }, /* Op */
173: { NULL, NULL }, /* Ot */
1.54 schwarze 174: { termp_under_pre, NULL }, /* Pa */
1.1 kristaps 175: { termp_rv_pre, NULL }, /* Rv */
1.32 schwarze 176: { NULL, NULL }, /* St */
1.54 schwarze 177: { termp_under_pre, NULL }, /* Va */
1.69 schwarze 178: { termp_vt_pre, termp_vt_post }, /* Vt */
1.1 kristaps 179: { termp_xr_pre, NULL }, /* Xr */
180: { NULL, termp____post }, /* %A */
1.58 schwarze 181: { termp_under_pre, termp____post }, /* %B */
1.1 kristaps 182: { NULL, termp____post }, /* %D */
1.58 schwarze 183: { termp_under_pre, termp____post }, /* %I */
1.54 schwarze 184: { termp_under_pre, termp____post }, /* %J */
1.1 kristaps 185: { NULL, termp____post }, /* %N */
186: { NULL, termp____post }, /* %O */
187: { NULL, termp____post }, /* %P */
188: { NULL, termp____post }, /* %R */
1.76 schwarze 189: { termp_under_pre, termp____post }, /* %T */
1.1 kristaps 190: { NULL, termp____post }, /* %V */
191: { NULL, NULL }, /* Ac */
192: { termp_aq_pre, termp_aq_post }, /* Ao */
193: { termp_aq_pre, termp_aq_post }, /* Aq */
1.32 schwarze 194: { NULL, NULL }, /* At */
1.1 kristaps 195: { NULL, NULL }, /* Bc */
196: { termp_bf_pre, NULL }, /* Bf */
197: { termp_bq_pre, termp_bq_post }, /* Bo */
198: { termp_bq_pre, termp_bq_post }, /* Bq */
1.26 schwarze 199: { termp_xx_pre, NULL }, /* Bsx */
1.1 kristaps 200: { NULL, termp_bx_post }, /* Bx */
201: { NULL, NULL }, /* Db */
202: { NULL, NULL }, /* Dc */
203: { termp_dq_pre, termp_dq_post }, /* Do */
204: { termp_dq_pre, termp_dq_post }, /* Dq */
1.73 schwarze 205: { NULL, NULL }, /* Ec */ /* FIXME: no space */
1.1 kristaps 206: { NULL, NULL }, /* Ef */
1.54 schwarze 207: { termp_under_pre, NULL }, /* Em */
1.1 kristaps 208: { NULL, NULL }, /* Eo */
1.26 schwarze 209: { termp_xx_pre, NULL }, /* Fx */
1.58 schwarze 210: { termp_bold_pre, NULL }, /* Ms */ /* FIXME: convert to symbol? */
1.1 kristaps 211: { NULL, NULL }, /* No */
212: { termp_ns_pre, NULL }, /* Ns */
1.26 schwarze 213: { termp_xx_pre, NULL }, /* Nx */
214: { termp_xx_pre, NULL }, /* Ox */
1.1 kristaps 215: { NULL, NULL }, /* Pc */
216: { termp_pf_pre, termp_pf_post }, /* Pf */
217: { termp_pq_pre, termp_pq_post }, /* Po */
218: { termp_pq_pre, termp_pq_post }, /* Pq */
219: { NULL, NULL }, /* Qc */
220: { termp_sq_pre, termp_sq_post }, /* Ql */
221: { termp_qq_pre, termp_qq_post }, /* Qo */
222: { termp_qq_pre, termp_qq_post }, /* Qq */
223: { NULL, NULL }, /* Re */
224: { termp_rs_pre, NULL }, /* Rs */
225: { NULL, NULL }, /* Sc */
226: { termp_sq_pre, termp_sq_post }, /* So */
227: { termp_sq_pre, termp_sq_post }, /* Sq */
228: { termp_sm_pre, NULL }, /* Sm */
1.54 schwarze 229: { termp_under_pre, NULL }, /* Sx */
230: { termp_bold_pre, NULL }, /* Sy */
1.1 kristaps 231: { NULL, NULL }, /* Tn */
1.26 schwarze 232: { termp_xx_pre, NULL }, /* Ux */
1.1 kristaps 233: { NULL, NULL }, /* Xc */
234: { NULL, NULL }, /* Xo */
235: { termp_fo_pre, termp_fo_post }, /* Fo */
236: { NULL, NULL }, /* Fc */
237: { termp_op_pre, termp_op_post }, /* Oo */
238: { NULL, NULL }, /* Oc */
239: { NULL, NULL }, /* Bk */
240: { NULL, NULL }, /* Ek */
241: { termp_bt_pre, NULL }, /* Bt */
242: { NULL, NULL }, /* Hf */
243: { NULL, NULL }, /* Fr */
244: { termp_ud_pre, NULL }, /* Ud */
1.32 schwarze 245: { NULL, termp_lb_post }, /* Lb */
1.54 schwarze 246: { termp_sp_pre, NULL }, /* Lp */
1.1 kristaps 247: { termp_lk_pre, NULL }, /* Lk */
1.54 schwarze 248: { termp_under_pre, NULL }, /* Mt */
1.1 kristaps 249: { termp_brq_pre, termp_brq_post }, /* Brq */
250: { termp_brq_pre, termp_brq_post }, /* Bro */
251: { NULL, NULL }, /* Brc */
1.58 schwarze 252: { NULL, termp____post }, /* %C */
253: { NULL, NULL }, /* Es */ /* TODO */
254: { NULL, NULL }, /* En */ /* TODO */
1.26 schwarze 255: { termp_xx_pre, NULL }, /* Dx */
1.58 schwarze 256: { NULL, termp____post }, /* %Q */
1.54 schwarze 257: { termp_sp_pre, NULL }, /* br */
1.38 schwarze 258: { termp_sp_pre, NULL }, /* sp */
1.62 schwarze 259: { termp_under_pre, termp____post }, /* %U */
1.1 kristaps 260: };
261:
262:
1.55 schwarze 263: void
1.61 schwarze 264: terminal_mdoc(void *arg, const struct mdoc *mdoc)
1.1 kristaps 265: {
1.55 schwarze 266: const struct mdoc_node *n;
267: const struct mdoc_meta *m;
1.61 schwarze 268: struct termp *p;
269:
270: p = (struct termp *)arg;
1.71 schwarze 271:
272: p->overstep = 0;
1.80 schwarze 273: p->maxrmargin = p->defrmargin;
1.75 schwarze 274: p->tabwidth = 5;
1.61 schwarze 275:
276: if (NULL == p->symtab)
277: switch (p->enc) {
278: case (TERMENC_ASCII):
279: p->symtab = chars_init(CHARS_ASCII);
280: break;
281: default:
282: abort();
283: /* NOTREACHED */
284: }
1.55 schwarze 285:
286: n = mdoc_node(mdoc);
287: m = mdoc_meta(mdoc);
288:
1.65 schwarze 289: print_mdoc_head(p, NULL, m, n);
1.55 schwarze 290: if (n->child)
1.65 schwarze 291: print_mdoc_nodelist(p, NULL, m, n->child);
1.55 schwarze 292: print_foot(p, NULL, m, n);
1.1 kristaps 293: }
294:
295:
296: static void
1.65 schwarze 297: print_mdoc_nodelist(DECL_ARGS)
1.1 kristaps 298: {
299:
1.65 schwarze 300: print_mdoc_node(p, pair, m, n);
1.60 schwarze 301: if (n->next)
1.65 schwarze 302: print_mdoc_nodelist(p, pair, m, n->next);
1.1 kristaps 303: }
304:
305:
1.54 schwarze 306: /* ARGSUSED */
1.1 kristaps 307: static void
1.65 schwarze 308: print_mdoc_node(DECL_ARGS)
1.1 kristaps 309: {
1.65 schwarze 310: int chld;
311: const void *font;
1.1 kristaps 312: struct termpair npair;
1.28 schwarze 313: size_t offset, rmargin;
1.1 kristaps 314:
1.54 schwarze 315: chld = 1;
1.28 schwarze 316: offset = p->offset;
317: rmargin = p->rmargin;
1.65 schwarze 318: font = term_fontq(p);
1.1 kristaps 319:
1.63 schwarze 320: memset(&npair, 0, sizeof(struct termpair));
1.1 kristaps 321: npair.ppair = pair;
322:
1.60 schwarze 323: if (MDOC_TEXT != n->type) {
324: if (termacts[n->tok].pre)
325: chld = (*termacts[n->tok].pre)(p, &npair, m, n);
1.54 schwarze 326: } else
1.60 schwarze 327: term_word(p, n->string);
1.65 schwarze 328:
1.60 schwarze 329: if (chld && n->child)
1.65 schwarze 330: print_mdoc_nodelist(p, &npair, m, n->child);
1.1 kristaps 331:
1.65 schwarze 332: term_fontpopq(p, font);
1.1 kristaps 333:
1.60 schwarze 334: if (MDOC_TEXT != n->type)
335: if (termacts[n->tok].post)
336: (*termacts[n->tok].post)(p, &npair, m, n);
1.28 schwarze 337:
1.78 schwarze 338: if (MDOC_EOS & n->flags)
339: p->flags |= TERMP_SENTENCE;
340:
1.28 schwarze 341: p->offset = offset;
342: p->rmargin = rmargin;
1.1 kristaps 343: }
344:
345:
1.55 schwarze 346: /* ARGSUSED */
1.1 kristaps 347: static void
1.55 schwarze 348: print_foot(DECL_ARGS)
1.1 kristaps 349: {
1.63 schwarze 350: char buf[DATESIZ], os[BUFSIZ];
1.1 kristaps 351:
1.65 schwarze 352: term_fontrepl(p, TERMFONT_NONE);
353:
1.7 schwarze 354: /*
355: * Output the footer in new-groff style, that is, three columns
356: * with the middle being the manual date and flanking columns
357: * being the operating system:
358: *
359: * SYSTEM DATE SYSTEM
360: */
361:
1.62 schwarze 362: time2a(m->date, buf, DATESIZ);
1.63 schwarze 363: strlcpy(os, m->os, BUFSIZ);
1.1 kristaps 364:
365: term_vspace(p);
366:
1.7 schwarze 367: p->offset = 0;
368: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 369: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
370:
371: term_word(p, os);
372: term_flushln(p);
373:
1.7 schwarze 374: p->offset = p->rmargin;
375: p->rmargin = p->maxrmargin - strlen(os);
1.1 kristaps 376: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1.7 schwarze 377:
378: term_word(p, buf);
379: term_flushln(p);
380:
1.1 kristaps 381: p->offset = p->rmargin;
382: p->rmargin = p->maxrmargin;
383: p->flags &= ~TERMP_NOBREAK;
1.7 schwarze 384: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1.1 kristaps 385:
1.7 schwarze 386: term_word(p, os);
1.1 kristaps 387: term_flushln(p);
1.7 schwarze 388:
389: p->offset = 0;
390: p->rmargin = p->maxrmargin;
391: p->flags = 0;
1.1 kristaps 392: }
393:
394:
1.55 schwarze 395: /* ARGSUSED */
1.1 kristaps 396: static void
1.65 schwarze 397: print_mdoc_head(DECL_ARGS)
1.1 kristaps 398: {
1.63 schwarze 399: char buf[BUFSIZ], title[BUFSIZ];
1.1 kristaps 400:
401: p->rmargin = p->maxrmargin;
402: p->offset = 0;
403:
404: /*
405: * The header is strange. It has three components, which are
406: * really two with the first duplicated. It goes like this:
407: *
408: * IDENTIFIER TITLE IDENTIFIER
409: *
410: * The IDENTIFIER is NAME(SECTION), which is the command-name
411: * (if given, or "unknown" if not) followed by the manual page
412: * section. These are given in `Dt'. The TITLE is a free-form
413: * string depending on the manual volume. If not specified, it
414: * switches on the manual section.
415: */
416:
1.60 schwarze 417: assert(m->vol);
1.63 schwarze 418: strlcpy(buf, m->vol, BUFSIZ);
1.1 kristaps 419:
1.60 schwarze 420: if (m->arch) {
1.63 schwarze 421: strlcat(buf, " (", BUFSIZ);
422: strlcat(buf, m->arch, BUFSIZ);
423: strlcat(buf, ")", BUFSIZ);
1.1 kristaps 424: }
425:
1.79 schwarze 426: snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec);
1.1 kristaps 427:
428: p->offset = 0;
1.8 schwarze 429: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 430: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
431:
432: term_word(p, title);
433: term_flushln(p);
434:
435: p->offset = p->rmargin;
436: p->rmargin = p->maxrmargin - strlen(title);
1.8 schwarze 437: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1.1 kristaps 438:
439: term_word(p, buf);
440: term_flushln(p);
441:
442: p->offset = p->rmargin;
443: p->rmargin = p->maxrmargin;
444: p->flags &= ~TERMP_NOBREAK;
445: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
446:
447: term_word(p, title);
448: term_flushln(p);
449:
1.8 schwarze 450: p->offset = 0;
1.1 kristaps 451: p->rmargin = p->maxrmargin;
452: p->flags &= ~TERMP_NOSPACE;
453: }
454:
455:
456: static size_t
1.62 schwarze 457: a2height(const struct mdoc_node *n)
1.1 kristaps 458: {
1.61 schwarze 459: struct roffsu su;
1.1 kristaps 460:
1.61 schwarze 461: assert(MDOC_TEXT == n->type);
462: assert(n->string);
463: if ( ! a2roffsu(n->string, &su, SCALE_VS))
464: SCALE_VS_INIT(&su, strlen(n->string));
1.1 kristaps 465:
1.61 schwarze 466: return(term_vspan(&su));
467: }
1.34 schwarze 468:
1.1 kristaps 469:
1.61 schwarze 470: static size_t
1.62 schwarze 471: a2width(const struct mdoc_argv *arg, int pos)
1.61 schwarze 472: {
473: struct roffsu su;
1.1 kristaps 474:
1.61 schwarze 475: assert(arg->value[pos]);
476: if ( ! a2roffsu(arg->value[pos], &su, SCALE_MAX))
477: SCALE_HS_INIT(&su, strlen(arg->value[pos]));
1.1 kristaps 478:
1.68 schwarze 479: return(term_hspan(&su));
1.1 kristaps 480: }
481:
482:
483: static int
1.77 schwarze 484: arg_disptype(const struct mdoc_node *n)
485: {
486: int i, len;
487:
488: assert(MDOC_BLOCK == n->type);
489:
490: len = (int)(n->args ? n->args->argc : 0);
491:
492: for (i = 0; i < len; i++)
493: switch (n->args->argv[i].arg) {
494: case (MDOC_Centred):
495: /* FALLTHROUGH */
496: case (MDOC_Ragged):
497: /* FALLTHROUGH */
498: case (MDOC_Filled):
499: /* FALLTHROUGH */
500: case (MDOC_Unfilled):
501: /* FALLTHROUGH */
502: case (MDOC_Literal):
503: return(n->args->argv[i].arg);
504: default:
505: break;
506: }
507:
508: return(-1);
509: }
510:
511:
512: static int
1.1 kristaps 513: arg_listtype(const struct mdoc_node *n)
514: {
515: int i, len;
516:
517: assert(MDOC_BLOCK == n->type);
518:
519: len = (int)(n->args ? n->args->argc : 0);
520:
521: for (i = 0; i < len; i++)
522: switch (n->args->argv[i].arg) {
523: case (MDOC_Bullet):
524: /* FALLTHROUGH */
525: case (MDOC_Dash):
526: /* FALLTHROUGH */
527: case (MDOC_Enum):
528: /* FALLTHROUGH */
529: case (MDOC_Hyphen):
530: /* FALLTHROUGH */
531: case (MDOC_Tag):
532: /* FALLTHROUGH */
533: case (MDOC_Inset):
534: /* FALLTHROUGH */
535: case (MDOC_Diag):
536: /* FALLTHROUGH */
537: case (MDOC_Item):
538: /* FALLTHROUGH */
539: case (MDOC_Column):
540: /* FALLTHROUGH */
1.33 schwarze 541: case (MDOC_Hang):
542: /* FALLTHROUGH */
1.1 kristaps 543: case (MDOC_Ohang):
544: return(n->args->argv[i].arg);
545: default:
546: break;
547: }
548:
1.33 schwarze 549: return(-1);
1.1 kristaps 550: }
551:
552:
553: static size_t
1.62 schwarze 554: a2offs(const struct mdoc_argv *arg)
1.1 kristaps 555: {
1.61 schwarze 556: struct roffsu su;
1.1 kristaps 557:
1.61 schwarze 558: if ('\0' == arg->value[0][0])
559: return(0);
560: else if (0 == strcmp(arg->value[0], "left"))
1.9 schwarze 561: return(0);
1.61 schwarze 562: else if (0 == strcmp(arg->value[0], "indent"))
1.17 schwarze 563: return(INDENT + 1);
1.61 schwarze 564: else if (0 == strcmp(arg->value[0], "indent-two"))
1.20 schwarze 565: return((INDENT + 1) * 2);
1.61 schwarze 566: else if ( ! a2roffsu(arg->value[0], &su, SCALE_MAX))
567: SCALE_HS_INIT(&su, strlen(arg->value[0]));
1.10 schwarze 568:
1.61 schwarze 569: return(term_hspan(&su));
1.1 kristaps 570: }
571:
572:
1.68 schwarze 573: /*
574: * Return 1 if an argument has a particular argument value or 0 if it
575: * does not. See arg_getattr().
576: */
1.1 kristaps 577: static int
578: arg_hasattr(int arg, const struct mdoc_node *n)
579: {
580:
581: return(-1 != arg_getattr(arg, n));
582: }
583:
584:
1.68 schwarze 585: /*
586: * Get the index of an argument in a node's argument list or -1 if it
587: * does not exist. See arg_getattrs().
588: */
1.1 kristaps 589: static int
590: arg_getattr(int v, const struct mdoc_node *n)
591: {
592: int val;
593:
594: return(arg_getattrs(&v, &val, 1, n) ? val : -1);
595: }
596:
597:
1.68 schwarze 598: /*
599: * Walk through the argument list for a node and fill an array "vals"
600: * with the positions of the argument structures listed in "keys".
601: * Return the number of elements that were written into "vals", which
602: * can be zero.
603: */
1.1 kristaps 604: static int
605: arg_getattrs(const int *keys, int *vals,
606: size_t sz, const struct mdoc_node *n)
607: {
608: int i, j, k;
609:
610: if (NULL == n->args)
611: return(0);
612:
613: for (k = i = 0; i < (int)n->args->argc; i++)
614: for (j = 0; j < (int)sz; j++)
615: if (n->args->argv[i].arg == keys[j]) {
616: vals[j] = i;
617: k++;
618: }
619: return(k);
620: }
621:
622:
1.68 schwarze 623: /*
624: * Determine how much space to print out before block elements of `It'
625: * (and thus `Bl') and `Bd'. And then go ahead and print that space,
626: * too.
627: */
1.45 schwarze 628: static void
1.61 schwarze 629: print_bvspace(struct termp *p,
1.1 kristaps 630: const struct mdoc_node *bl,
1.60 schwarze 631: const struct mdoc_node *n)
1.1 kristaps 632: {
1.60 schwarze 633: const struct mdoc_node *nn;
1.1 kristaps 634:
635: term_newln(p);
1.60 schwarze 636: if (arg_hasattr(MDOC_Compact, bl))
1.45 schwarze 637: return;
638:
1.60 schwarze 639: /* Do not vspace directly after Ss/Sh. */
1.1 kristaps 640:
1.60 schwarze 641: for (nn = n; nn; nn = nn->parent) {
642: if (MDOC_BLOCK != nn->type)
1.1 kristaps 643: continue;
1.60 schwarze 644: if (MDOC_Ss == nn->tok)
1.45 schwarze 645: return;
1.60 schwarze 646: if (MDOC_Sh == nn->tok)
1.45 schwarze 647: return;
1.60 schwarze 648: if (NULL == nn->prev)
1.1 kristaps 649: continue;
650: break;
651: }
652:
1.60 schwarze 653: /* A `-column' does not assert vspace within the list. */
1.45 schwarze 654:
655: if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Column, bl))
1.60 schwarze 656: if (n->prev && MDOC_It == n->prev->tok)
1.45 schwarze 657: return;
658:
1.60 schwarze 659: /* A `-diag' without body does not vspace. */
660:
1.45 schwarze 661: if (MDOC_Bl == bl->tok && arg_hasattr(MDOC_Diag, bl))
1.60 schwarze 662: if (n->prev && MDOC_It == n->prev->tok) {
663: assert(n->prev->body);
664: if (NULL == n->prev->body->child)
1.45 schwarze 665: return;
666: }
667:
668: term_vspace(p);
1.1 kristaps 669: }
670:
671:
672: /* ARGSUSED */
673: static int
674: termp_dq_pre(DECL_ARGS)
675: {
676:
1.60 schwarze 677: if (MDOC_BODY != n->type)
1.1 kristaps 678: return(1);
679:
680: term_word(p, "\\(lq");
681: p->flags |= TERMP_NOSPACE;
682: return(1);
683: }
684:
685:
686: /* ARGSUSED */
687: static void
688: termp_dq_post(DECL_ARGS)
689: {
690:
1.60 schwarze 691: if (MDOC_BODY != n->type)
1.1 kristaps 692: return;
693:
694: p->flags |= TERMP_NOSPACE;
695: term_word(p, "\\(rq");
696: }
697:
698:
699: /* ARGSUSED */
700: static int
701: termp_it_pre(DECL_ARGS)
702: {
1.60 schwarze 703: const struct mdoc_node *bl, *nn;
1.1 kristaps 704: char buf[7];
1.28 schwarze 705: int i, type, keys[3], vals[3];
1.68 schwarze 706: size_t width, offset, ncols, dcol;
1.1 kristaps 707:
1.60 schwarze 708: if (MDOC_BLOCK == n->type) {
1.61 schwarze 709: print_bvspace(p, n->parent->parent, n);
1.45 schwarze 710: return(1);
711: }
1.1 kristaps 712:
1.60 schwarze 713: bl = n->parent->parent->parent;
1.1 kristaps 714:
1.68 schwarze 715: /* Get list width, offset, and list type from argument list. */
1.1 kristaps 716:
717: keys[0] = MDOC_Width;
718: keys[1] = MDOC_Offset;
719: keys[2] = MDOC_Column;
720:
721: vals[0] = vals[1] = vals[2] = -1;
722:
1.68 schwarze 723: arg_getattrs(keys, vals, 3, bl);
1.1 kristaps 724:
725: type = arg_listtype(bl);
1.33 schwarze 726: assert(-1 != type);
1.1 kristaps 727:
1.68 schwarze 728: /*
729: * First calculate width and offset. This is pretty easy unless
730: * we're a -column list, in which case all prior columns must
731: * be accounted for.
732: */
733:
734: width = offset = 0;
735:
1.66 schwarze 736: if (vals[1] >= 0)
737: offset = a2offs(&bl->args->argv[vals[1]]);
738:
1.1 kristaps 739: switch (type) {
740: case (MDOC_Column):
1.60 schwarze 741: if (MDOC_BODY == n->type)
1.1 kristaps 742: break;
1.66 schwarze 743: /*
1.68 schwarze 744: * Imitate groff's column handling:
745: * - For each earlier column, add its width.
746: * - For less than 5 columns, add four more blanks per
747: * column.
748: * - For exactly 5 columns, add three more blank per
749: * column.
750: * - For more than 5 columns, add only one column.
1.66 schwarze 751: */
752: ncols = bl->args->argv[vals[2]].sz;
1.68 schwarze 753: /* LINTED */
754: dcol = ncols < 5 ? 4 : ncols == 5 ? 3 : 1;
755:
756: for (i = 0, nn = n->prev;
757: nn && i < (int)ncols;
758: nn = nn->prev, i++)
759: offset += dcol + a2width
760: (&bl->args->argv[vals[2]], i);
761:
1.66 schwarze 762:
763: /*
1.68 schwarze 764: * When exceeding the declared number of columns, leave
765: * the remaining widths at 0. This will later be
766: * adjusted to the default width of 10, or, for the last
767: * column, stretched to the right margin.
1.46 schwarze 768: */
1.68 schwarze 769: if (i >= (int)ncols)
770: break;
1.46 schwarze 771:
1.66 schwarze 772: /*
1.68 schwarze 773: * Use the declared column widths, extended as explained
774: * in the preceding paragraph.
1.66 schwarze 775: */
1.68 schwarze 776: width = a2width(&bl->args->argv[vals[2]], i) + dcol;
1.1 kristaps 777: break;
778: default:
1.68 schwarze 779: if (vals[0] < 0)
780: break;
781:
782: /*
783: * Note: buffer the width by 2, which is groff's magic
784: * number for buffering single arguments. See the above
785: * handling for column for how this changes.
786: */
787: width = a2width(&bl->args->argv[vals[0]], 0) + 2;
1.1 kristaps 788: break;
789: }
790:
791: /*
792: * List-type can override the width in the case of fixed-head
793: * values (bullet, dash/hyphen, enum). Tags need a non-zero
1.53 schwarze 794: * offset.
1.1 kristaps 795: */
796:
797: switch (type) {
798: case (MDOC_Bullet):
799: /* FALLTHROUGH */
800: case (MDOC_Dash):
801: /* FALLTHROUGH */
802: case (MDOC_Hyphen):
803: if (width < 4)
804: width = 4;
1.19 schwarze 805: break;
806: case (MDOC_Enum):
807: if (width < 5)
808: width = 5;
1.1 kristaps 809: break;
1.33 schwarze 810: case (MDOC_Hang):
811: if (0 == width)
812: width = 8;
813: break;
1.41 schwarze 814: case (MDOC_Column):
815: /* FALLTHROUGH */
1.1 kristaps 816: case (MDOC_Tag):
817: if (0 == width)
818: width = 10;
819: break;
820: default:
821: break;
822: }
823:
824: /*
1.16 schwarze 825: * Whitespace control. Inset bodies need an initial space,
826: * while diagonal bodies need two.
1.1 kristaps 827: */
828:
1.42 schwarze 829: p->flags |= TERMP_NOSPACE;
830:
1.1 kristaps 831: switch (type) {
1.42 schwarze 832: case (MDOC_Diag):
1.60 schwarze 833: if (MDOC_BODY == n->type)
1.48 schwarze 834: term_word(p, "\\ \\ ");
1.42 schwarze 835: break;
1.1 kristaps 836: case (MDOC_Inset):
1.60 schwarze 837: if (MDOC_BODY == n->type)
1.42 schwarze 838: term_word(p, "\\ ");
1.1 kristaps 839: break;
840: default:
841: break;
842: }
843:
1.42 schwarze 844: p->flags |= TERMP_NOSPACE;
845:
1.1 kristaps 846: switch (type) {
847: case (MDOC_Diag):
1.60 schwarze 848: if (MDOC_HEAD == n->type)
1.65 schwarze 849: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 850: break;
851: default:
852: break;
853: }
854:
855: /*
1.68 schwarze 856: * Pad and break control. This is the tricky part. These flags
857: * are documented in term_flushln() in term.c. Note that we're
858: * going to unset all of these flags in termp_it_post() when we
859: * exit.
1.1 kristaps 860: */
861:
862: switch (type) {
863: case (MDOC_Bullet):
864: /* FALLTHROUGH */
865: case (MDOC_Dash):
866: /* FALLTHROUGH */
867: case (MDOC_Enum):
868: /* FALLTHROUGH */
869: case (MDOC_Hyphen):
1.60 schwarze 870: if (MDOC_HEAD == n->type)
1.33 schwarze 871: p->flags |= TERMP_NOBREAK;
872: else
873: p->flags |= TERMP_NOLPAD;
874: break;
875: case (MDOC_Hang):
1.60 schwarze 876: if (MDOC_HEAD == n->type)
1.33 schwarze 877: p->flags |= TERMP_NOBREAK;
878: else
879: p->flags |= TERMP_NOLPAD;
880:
1.60 schwarze 881: if (MDOC_HEAD != n->type)
1.47 schwarze 882: break;
883:
884: /*
885: * This is ugly. If `-hang' is specified and the body
886: * is a `Bl' or `Bd', then we want basically to nullify
887: * the "overstep" effect in term_flushln() and treat
888: * this as a `-ohang' list instead.
889: */
1.60 schwarze 890: if (n->next->child &&
891: (MDOC_Bl == n->next->child->tok ||
892: MDOC_Bd == n->next->child->tok)) {
1.47 schwarze 893: p->flags &= ~TERMP_NOBREAK;
894: p->flags &= ~TERMP_NOLPAD;
895: } else
1.33 schwarze 896: p->flags |= TERMP_HANG;
897: break;
1.1 kristaps 898: case (MDOC_Tag):
1.60 schwarze 899: if (MDOC_HEAD == n->type)
1.42 schwarze 900: p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE;
1.1 kristaps 901: else
902: p->flags |= TERMP_NOLPAD;
1.33 schwarze 903:
1.60 schwarze 904: if (MDOC_HEAD != n->type)
1.33 schwarze 905: break;
1.60 schwarze 906: if (NULL == n->next || NULL == n->next->child)
1.33 schwarze 907: p->flags |= TERMP_DANGLE;
1.1 kristaps 908: break;
909: case (MDOC_Column):
1.60 schwarze 910: if (MDOC_HEAD == n->type) {
911: assert(n->next);
912: if (MDOC_BODY == n->next->type)
1.1 kristaps 913: p->flags &= ~TERMP_NOBREAK;
914: else
915: p->flags |= TERMP_NOBREAK;
1.60 schwarze 916: if (n->prev)
1.1 kristaps 917: p->flags |= TERMP_NOLPAD;
918: }
919: break;
920: case (MDOC_Diag):
1.60 schwarze 921: if (MDOC_HEAD == n->type)
1.1 kristaps 922: p->flags |= TERMP_NOBREAK;
923: break;
924: default:
925: break;
926: }
927:
928: /*
929: * Margin control. Set-head-width lists have their right
930: * margins shortened. The body for these lists has the offset
931: * necessarily lengthened. Everybody gets the offset.
932: */
933:
934: p->offset += offset;
935:
936: switch (type) {
1.47 schwarze 937: case (MDOC_Hang):
938: /*
939: * Same stipulation as above, regarding `-hang'. We
940: * don't want to recalculate rmargin and offsets when
941: * using `Bd' or `Bl' within `-hang' overstep lists.
942: */
1.60 schwarze 943: if (MDOC_HEAD == n->type && n->next->child &&
944: (MDOC_Bl == n->next->child->tok ||
945: MDOC_Bd == n->next->child->tok))
1.47 schwarze 946: break;
947: /* FALLTHROUGH */
1.1 kristaps 948: case (MDOC_Bullet):
949: /* FALLTHROUGH */
950: case (MDOC_Dash):
951: /* FALLTHROUGH */
952: case (MDOC_Enum):
953: /* FALLTHROUGH */
954: case (MDOC_Hyphen):
1.33 schwarze 955: /* FALLTHROUGH */
1.1 kristaps 956: case (MDOC_Tag):
1.41 schwarze 957: assert(width);
1.60 schwarze 958: if (MDOC_HEAD == n->type)
1.1 kristaps 959: p->rmargin = p->offset + width;
960: else
961: p->offset += width;
962: break;
963: case (MDOC_Column):
1.41 schwarze 964: assert(width);
1.1 kristaps 965: p->rmargin = p->offset + width;
1.43 schwarze 966: /*
967: * XXX - this behaviour is not documented: the
968: * right-most column is filled to the right margin.
969: */
1.60 schwarze 970: if (MDOC_HEAD == n->type &&
1.66 schwarze 971: MDOC_BODY == n->next->type &&
972: p->rmargin < p->maxrmargin)
1.43 schwarze 973: p->rmargin = p->maxrmargin;
1.1 kristaps 974: break;
975: default:
976: break;
977: }
978:
979: /*
980: * The dash, hyphen, bullet and enum lists all have a special
1.12 schwarze 981: * HEAD character (temporarily bold, in some cases).
1.1 kristaps 982: */
983:
1.60 schwarze 984: if (MDOC_HEAD == n->type)
1.1 kristaps 985: switch (type) {
986: case (MDOC_Bullet):
1.65 schwarze 987: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 988: term_word(p, "\\[bu]");
1.65 schwarze 989: term_fontpop(p);
1.1 kristaps 990: break;
991: case (MDOC_Dash):
992: /* FALLTHROUGH */
993: case (MDOC_Hyphen):
1.65 schwarze 994: term_fontpush(p, TERMFONT_BOLD);
1.35 schwarze 995: term_word(p, "\\(hy");
1.65 schwarze 996: term_fontpop(p);
1.1 kristaps 997: break;
998: case (MDOC_Enum):
999: (pair->ppair->ppair->count)++;
1.68 schwarze 1000: snprintf(buf, sizeof(buf), "%d.",
1.1 kristaps 1001: pair->ppair->ppair->count);
1002: term_word(p, buf);
1003: break;
1004: default:
1005: break;
1006: }
1.12 schwarze 1007:
1.1 kristaps 1008: /*
1009: * If we're not going to process our children, indicate so here.
1010: */
1011:
1012: switch (type) {
1013: case (MDOC_Bullet):
1014: /* FALLTHROUGH */
1015: case (MDOC_Item):
1016: /* FALLTHROUGH */
1017: case (MDOC_Dash):
1018: /* FALLTHROUGH */
1019: case (MDOC_Hyphen):
1020: /* FALLTHROUGH */
1021: case (MDOC_Enum):
1.60 schwarze 1022: if (MDOC_HEAD == n->type)
1.1 kristaps 1023: return(0);
1024: break;
1025: case (MDOC_Column):
1.60 schwarze 1026: if (MDOC_BODY == n->type)
1.1 kristaps 1027: return(0);
1028: break;
1029: default:
1030: break;
1031: }
1032:
1033: return(1);
1034: }
1035:
1036:
1037: /* ARGSUSED */
1038: static void
1039: termp_it_post(DECL_ARGS)
1040: {
1041: int type;
1042:
1.68 schwarze 1043: if (MDOC_BLOCK == n->type)
1.1 kristaps 1044: return;
1045:
1.60 schwarze 1046: type = arg_listtype(n->parent->parent->parent);
1.33 schwarze 1047: assert(-1 != type);
1.1 kristaps 1048:
1049: switch (type) {
1.44 schwarze 1050: case (MDOC_Item):
1051: /* FALLTHROUGH */
1.1 kristaps 1052: case (MDOC_Diag):
1053: /* FALLTHROUGH */
1054: case (MDOC_Inset):
1.60 schwarze 1055: if (MDOC_BODY == n->type)
1.74 schwarze 1056: term_newln(p);
1.1 kristaps 1057: break;
1058: case (MDOC_Column):
1.60 schwarze 1059: if (MDOC_HEAD == n->type)
1.1 kristaps 1060: term_flushln(p);
1061: break;
1062: default:
1.74 schwarze 1063: term_newln(p);
1.1 kristaps 1064: break;
1065: }
1066:
1.68 schwarze 1067: /*
1068: * Now that our output is flushed, we can reset our tags. Since
1069: * only `It' sets these flags, we're free to assume that nobody
1070: * has munged them in the meanwhile.
1071: */
1072:
1073: p->flags &= ~TERMP_DANGLE;
1074: p->flags &= ~TERMP_NOBREAK;
1075: p->flags &= ~TERMP_TWOSPACE;
1076: p->flags &= ~TERMP_NOLPAD;
1077: p->flags &= ~TERMP_HANG;
1.1 kristaps 1078: }
1079:
1080:
1081: /* ARGSUSED */
1082: static int
1083: termp_nm_pre(DECL_ARGS)
1084: {
1085:
1.81 ! schwarze 1086: if (NULL == n->child && NULL == m->name)
! 1087:
1.77 schwarze 1088: if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags)
1.1 kristaps 1089: term_newln(p);
1.65 schwarze 1090:
1091: term_fontpush(p, TERMFONT_BOLD);
1092:
1.60 schwarze 1093: if (NULL == n->child)
1094: term_word(p, m->name);
1.81 ! schwarze 1095:
1.1 kristaps 1096: return(1);
1097: }
1098:
1099:
1100: /* ARGSUSED */
1101: static int
1102: termp_fl_pre(DECL_ARGS)
1103: {
1104:
1.65 schwarze 1105: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1106: term_word(p, "\\-");
1.67 schwarze 1107:
1108: if (n->child)
1109: p->flags |= TERMP_NOSPACE;
1.73 schwarze 1110: else if (n->next && n->next->line == n->line)
1111: p->flags |= TERMP_NOSPACE;
1.67 schwarze 1112:
1.1 kristaps 1113: return(1);
1.49 schwarze 1114: }
1115:
1116:
1117: /* ARGSUSED */
1118: static int
1119: termp_an_pre(DECL_ARGS)
1120: {
1121:
1.60 schwarze 1122: if (NULL == n->child)
1.49 schwarze 1123: return(1);
1124:
1125: /*
1.60 schwarze 1126: * If not in the AUTHORS section, `An -split' will cause
1127: * newlines to occur before the author name. If in the AUTHORS
1128: * section, by default, the first `An' invocation is nosplit,
1129: * then all subsequent ones, regardless of whether interspersed
1130: * with other macros/text, are split. -split, in this case,
1131: * will override the condition of the implied first -nosplit.
1.49 schwarze 1132: */
1133:
1.60 schwarze 1134: if (n->sec == SEC_AUTHORS) {
1.49 schwarze 1135: if ( ! (TERMP_ANPREC & p->flags)) {
1136: if (TERMP_SPLIT & p->flags)
1137: term_newln(p);
1138: return(1);
1139: }
1140: if (TERMP_NOSPLIT & p->flags)
1141: return(1);
1142: term_newln(p);
1143: return(1);
1144: }
1145:
1146: if (TERMP_SPLIT & p->flags)
1147: term_newln(p);
1148:
1149: return(1);
1150: }
1151:
1152:
1153: /* ARGSUSED */
1154: static void
1155: termp_an_post(DECL_ARGS)
1156: {
1157:
1.60 schwarze 1158: if (n->child) {
1159: if (SEC_AUTHORS == n->sec)
1.49 schwarze 1160: p->flags |= TERMP_ANPREC;
1161: return;
1162: }
1163:
1.77 schwarze 1164: if (arg_hasattr(MDOC_Split, n)) {
1.49 schwarze 1165: p->flags &= ~TERMP_NOSPLIT;
1166: p->flags |= TERMP_SPLIT;
1167: } else {
1168: p->flags &= ~TERMP_SPLIT;
1169: p->flags |= TERMP_NOSPLIT;
1170: }
1171:
1.1 kristaps 1172: }
1173:
1174:
1175: /* ARGSUSED */
1176: static int
1177: termp_ns_pre(DECL_ARGS)
1178: {
1179:
1180: p->flags |= TERMP_NOSPACE;
1181: return(1);
1182: }
1183:
1184:
1185: /* ARGSUSED */
1186: static int
1187: termp_rs_pre(DECL_ARGS)
1188: {
1189:
1.60 schwarze 1190: if (SEC_SEE_ALSO != n->sec)
1.57 schwarze 1191: return(1);
1.60 schwarze 1192: if (MDOC_BLOCK == n->type && n->prev)
1.1 kristaps 1193: term_vspace(p);
1194: return(1);
1195: }
1196:
1197:
1198: /* ARGSUSED */
1199: static int
1200: termp_rv_pre(DECL_ARGS)
1201: {
1.53 schwarze 1202: const struct mdoc_node *nn;
1.1 kristaps 1203:
1204: term_newln(p);
1205: term_word(p, "The");
1206:
1.60 schwarze 1207: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1208: term_fontpush(p, TERMFONT_BOLD);
1.53 schwarze 1209: term_word(p, nn->string);
1.65 schwarze 1210: term_fontpop(p);
1.53 schwarze 1211: p->flags |= TERMP_NOSPACE;
1212: if (nn->next && NULL == nn->next->next)
1213: term_word(p, "(), and");
1214: else if (nn->next)
1215: term_word(p, "(),");
1216: else
1217: term_word(p, "()");
1218: }
1219:
1.81 ! schwarze 1220: if (n->child && n->child->next)
1.53 schwarze 1221: term_word(p, "functions return");
1222: else
1223: term_word(p, "function returns");
1.1 kristaps 1224:
1.53 schwarze 1225: term_word(p, "the value 0 if successful; otherwise the value "
1226: "-1 is returned and the global variable");
1.1 kristaps 1227:
1.65 schwarze 1228: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1229: term_word(p, "errno");
1.65 schwarze 1230: term_fontpop(p);
1.1 kristaps 1231:
1232: term_word(p, "is set to indicate the error.");
1233:
1.53 schwarze 1234: return(0);
1.1 kristaps 1235: }
1236:
1237:
1238: /* ARGSUSED */
1239: static int
1240: termp_ex_pre(DECL_ARGS)
1241: {
1.53 schwarze 1242: const struct mdoc_node *nn;
1.1 kristaps 1243:
1.53 schwarze 1244: term_word(p, "The");
1.1 kristaps 1245:
1.60 schwarze 1246: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1247: term_fontpush(p, TERMFONT_BOLD);
1.53 schwarze 1248: term_word(p, nn->string);
1.65 schwarze 1249: term_fontpop(p);
1.53 schwarze 1250: p->flags |= TERMP_NOSPACE;
1251: if (nn->next && NULL == nn->next->next)
1252: term_word(p, ", and");
1253: else if (nn->next)
1254: term_word(p, ",");
1255: else
1256: p->flags &= ~TERMP_NOSPACE;
1257: }
1258:
1.81 ! schwarze 1259: if (n->child && n->child->next)
1.53 schwarze 1260: term_word(p, "utilities exit");
1261: else
1262: term_word(p, "utility exits");
1263:
1264: term_word(p, "0 on success, and >0 if an error occurs.");
1.1 kristaps 1265:
1.53 schwarze 1266: return(0);
1.1 kristaps 1267: }
1268:
1269:
1270: /* ARGSUSED */
1271: static int
1272: termp_nd_pre(DECL_ARGS)
1273: {
1.25 schwarze 1274:
1.60 schwarze 1275: if (MDOC_BODY != n->type)
1.25 schwarze 1276: return(1);
1277:
1278: #if defined(__OpenBSD__) || defined(__linux__)
1279: term_word(p, "\\(en");
1.24 schwarze 1280: #else
1281: term_word(p, "\\(em");
1282: #endif
1.1 kristaps 1283: return(1);
1284: }
1285:
1286:
1287: /* ARGSUSED */
1.73 schwarze 1288: static int
1289: termp_bl_pre(DECL_ARGS)
1290: {
1291:
1292: return(MDOC_HEAD != n->type);
1293: }
1294:
1295:
1296: /* ARGSUSED */
1.1 kristaps 1297: static void
1298: termp_bl_post(DECL_ARGS)
1299: {
1300:
1.60 schwarze 1301: if (MDOC_BLOCK == n->type)
1.1 kristaps 1302: term_newln(p);
1303: }
1304:
1305:
1306: /* ARGSUSED */
1307: static void
1308: termp_op_post(DECL_ARGS)
1309: {
1310:
1.60 schwarze 1311: if (MDOC_BODY != n->type)
1.1 kristaps 1312: return;
1313: p->flags |= TERMP_NOSPACE;
1314: term_word(p, "\\(rB");
1315: }
1316:
1317:
1318: /* ARGSUSED */
1319: static int
1320: termp_xr_pre(DECL_ARGS)
1321: {
1.60 schwarze 1322: const struct mdoc_node *nn;
1.1 kristaps 1323:
1.72 schwarze 1324: if (NULL == n->child)
1325: return(0);
1326:
1327: assert(MDOC_TEXT == n->child->type);
1.60 schwarze 1328: nn = n->child;
1.10 schwarze 1329:
1.60 schwarze 1330: term_word(p, nn->string);
1331: if (NULL == (nn = nn->next))
1.1 kristaps 1332: return(0);
1333: p->flags |= TERMP_NOSPACE;
1334: term_word(p, "(");
1335: p->flags |= TERMP_NOSPACE;
1.60 schwarze 1336: term_word(p, nn->string);
1.1 kristaps 1337: p->flags |= TERMP_NOSPACE;
1338: term_word(p, ")");
1.60 schwarze 1339:
1.1 kristaps 1340: return(0);
1341: }
1342:
1343:
1.69 schwarze 1344: static int
1345: termp_vt_pre(DECL_ARGS)
1346: {
1347:
1348: if (MDOC_ELEM == n->type)
1349: return(termp_under_pre(p, pair, m, n));
1350: else if (MDOC_HEAD == n->type)
1351: return(0);
1352: else if (MDOC_BLOCK == n->type)
1353: return(1);
1354:
1355: return(termp_under_pre(p, pair, m, n));
1356: }
1357:
1358:
1.1 kristaps 1359: /* ARGSUSED */
1360: static void
1361: termp_vt_post(DECL_ARGS)
1362: {
1363:
1.69 schwarze 1364: if (MDOC_BLOCK != n->type)
1.30 schwarze 1365: return;
1.60 schwarze 1366: if (n->next && MDOC_Vt == n->next->tok)
1.30 schwarze 1367: term_newln(p);
1.60 schwarze 1368: else if (n->next)
1.1 kristaps 1369: term_vspace(p);
1370: }
1371:
1372:
1373: /* ARGSUSED */
1374: static int
1.54 schwarze 1375: termp_bold_pre(DECL_ARGS)
1.1 kristaps 1376: {
1377:
1.65 schwarze 1378: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1379: return(1);
1380: }
1381:
1382:
1383: /* ARGSUSED */
1384: static void
1385: termp_fd_post(DECL_ARGS)
1386: {
1387:
1.77 schwarze 1388: if (n->sec != SEC_SYNOPSIS || ! (MDOC_LINE & n->flags))
1.1 kristaps 1389: return;
1.27 schwarze 1390:
1.1 kristaps 1391: term_newln(p);
1.60 schwarze 1392: if (n->next && MDOC_Fd != n->next->tok)
1.1 kristaps 1393: term_vspace(p);
1394: }
1395:
1396:
1397: /* ARGSUSED */
1398: static int
1399: termp_sh_pre(DECL_ARGS)
1400: {
1.60 schwarze 1401:
1402: /* No vspace between consecutive `Sh' calls. */
1403:
1404: switch (n->type) {
1.52 schwarze 1405: case (MDOC_BLOCK):
1.60 schwarze 1406: if (n->prev && MDOC_Sh == n->prev->tok)
1407: if (NULL == n->prev->body->child)
1.52 schwarze 1408: break;
1409: term_vspace(p);
1410: break;
1.1 kristaps 1411: case (MDOC_HEAD):
1.65 schwarze 1412: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1413: break;
1414: case (MDOC_BODY):
1415: p->offset = INDENT;
1416: break;
1417: default:
1418: break;
1419: }
1420: return(1);
1421: }
1422:
1423:
1424: /* ARGSUSED */
1425: static void
1426: termp_sh_post(DECL_ARGS)
1427: {
1428:
1.60 schwarze 1429: switch (n->type) {
1.1 kristaps 1430: case (MDOC_HEAD):
1431: term_newln(p);
1432: break;
1433: case (MDOC_BODY):
1434: term_newln(p);
1435: p->offset = 0;
1436: break;
1437: default:
1438: break;
1439: }
1440: }
1441:
1442:
1443: /* ARGSUSED */
1444: static int
1445: termp_op_pre(DECL_ARGS)
1446: {
1447:
1.60 schwarze 1448: switch (n->type) {
1.1 kristaps 1449: case (MDOC_BODY):
1450: term_word(p, "\\(lB");
1451: p->flags |= TERMP_NOSPACE;
1452: break;
1453: default:
1454: break;
1455: }
1456: return(1);
1457: }
1458:
1459:
1460: /* ARGSUSED */
1461: static int
1462: termp_bt_pre(DECL_ARGS)
1463: {
1464:
1465: term_word(p, "is currently in beta test.");
1.59 schwarze 1466: return(0);
1.1 kristaps 1467: }
1468:
1469:
1470: /* ARGSUSED */
1471: static void
1472: termp_lb_post(DECL_ARGS)
1473: {
1474:
1.77 schwarze 1475: if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
1.57 schwarze 1476: term_newln(p);
1.1 kristaps 1477: }
1478:
1479:
1480: /* ARGSUSED */
1481: static int
1482: termp_ud_pre(DECL_ARGS)
1483: {
1484:
1485: term_word(p, "currently under development.");
1.60 schwarze 1486: return(0);
1.1 kristaps 1487: }
1488:
1489:
1490: /* ARGSUSED */
1491: static int
1492: termp_d1_pre(DECL_ARGS)
1493: {
1494:
1.60 schwarze 1495: if (MDOC_BLOCK != n->type)
1.1 kristaps 1496: return(1);
1497: term_newln(p);
1.28 schwarze 1498: p->offset += (INDENT + 1);
1.1 kristaps 1499: return(1);
1500: }
1501:
1502:
1503: /* ARGSUSED */
1504: static void
1505: termp_d1_post(DECL_ARGS)
1506: {
1507:
1.60 schwarze 1508: if (MDOC_BLOCK != n->type)
1.1 kristaps 1509: return;
1510: term_newln(p);
1511: }
1512:
1513:
1514: /* ARGSUSED */
1515: static int
1516: termp_aq_pre(DECL_ARGS)
1517: {
1518:
1.60 schwarze 1519: if (MDOC_BODY != n->type)
1.1 kristaps 1520: return(1);
1521: term_word(p, "\\(la");
1522: p->flags |= TERMP_NOSPACE;
1523: return(1);
1524: }
1525:
1526:
1527: /* ARGSUSED */
1528: static void
1529: termp_aq_post(DECL_ARGS)
1530: {
1531:
1.60 schwarze 1532: if (MDOC_BODY != n->type)
1.1 kristaps 1533: return;
1534: p->flags |= TERMP_NOSPACE;
1535: term_word(p, "\\(ra");
1536: }
1537:
1538:
1539: /* ARGSUSED */
1540: static int
1541: termp_ft_pre(DECL_ARGS)
1542: {
1543:
1.77 schwarze 1544: if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags)
1.60 schwarze 1545: if (n->prev && MDOC_Fo == n->prev->tok)
1.1 kristaps 1546: term_vspace(p);
1.65 schwarze 1547:
1548: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1549: return(1);
1550: }
1551:
1552:
1553: /* ARGSUSED */
1554: static void
1555: termp_ft_post(DECL_ARGS)
1556: {
1557:
1.77 schwarze 1558: if (SEC_SYNOPSIS == n->sec && MDOC_LINE & n->flags)
1.1 kristaps 1559: term_newln(p);
1560: }
1561:
1562:
1563: /* ARGSUSED */
1564: static int
1565: termp_fn_pre(DECL_ARGS)
1566: {
1.60 schwarze 1567: const struct mdoc_node *nn;
1.1 kristaps 1568:
1.65 schwarze 1569: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1570: term_word(p, n->child->string);
1.65 schwarze 1571: term_fontpop(p);
1.1 kristaps 1572:
1573: p->flags |= TERMP_NOSPACE;
1574: term_word(p, "(");
1575:
1.60 schwarze 1576: for (nn = n->child->next; nn; nn = nn->next) {
1.65 schwarze 1577: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 1578: term_word(p, nn->string);
1.65 schwarze 1579: term_fontpop(p);
1580:
1.60 schwarze 1581: if (nn->next)
1.1 kristaps 1582: term_word(p, ",");
1583: }
1584:
1585: term_word(p, ")");
1586:
1.60 schwarze 1587: if (SEC_SYNOPSIS == n->sec)
1.1 kristaps 1588: term_word(p, ";");
1589:
1590: return(0);
1591: }
1592:
1593:
1594: /* ARGSUSED */
1595: static void
1596: termp_fn_post(DECL_ARGS)
1597: {
1598:
1.77 schwarze 1599: if (n->sec == SEC_SYNOPSIS && n->next && MDOC_LINE & n->flags)
1.1 kristaps 1600: term_vspace(p);
1601: }
1602:
1603:
1604: /* ARGSUSED */
1605: static int
1606: termp_fa_pre(DECL_ARGS)
1607: {
1.60 schwarze 1608: const struct mdoc_node *nn;
1.1 kristaps 1609:
1.60 schwarze 1610: if (n->parent->tok != MDOC_Fo) {
1.65 schwarze 1611: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1612: return(1);
1613: }
1614:
1.60 schwarze 1615: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1616: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 1617: term_word(p, nn->string);
1.65 schwarze 1618: term_fontpop(p);
1619:
1.60 schwarze 1620: if (nn->next)
1.1 kristaps 1621: term_word(p, ",");
1622: }
1623:
1.60 schwarze 1624: if (n->child && n->next && n->next->tok == MDOC_Fa)
1.1 kristaps 1625: term_word(p, ",");
1626:
1627: return(0);
1628: }
1629:
1630:
1631: /* ARGSUSED */
1632: static int
1633: termp_bd_pre(DECL_ARGS)
1634: {
1.75 schwarze 1635: size_t tabwidth;
1.60 schwarze 1636: int i, type;
1.77 schwarze 1637: size_t rm, rmax;
1.60 schwarze 1638: const struct mdoc_node *nn;
1.1 kristaps 1639:
1.60 schwarze 1640: if (MDOC_BLOCK == n->type) {
1.61 schwarze 1641: print_bvspace(p, n, n);
1.45 schwarze 1642: return(1);
1.73 schwarze 1643: } else if (MDOC_HEAD == n->type)
1644: return(0);
1.1 kristaps 1645:
1.60 schwarze 1646: nn = n->parent;
1.1 kristaps 1647:
1.77 schwarze 1648: type = arg_disptype(nn);
1649: assert(-1 != type);
1650:
1651: if (-1 != (i = arg_getattr(MDOC_Offset, nn)))
1652: p->offset += a2offs(&nn->args->argv[i]);
1.60 schwarze 1653:
1654: /*
1655: * If -ragged or -filled are specified, the block does nothing
1656: * but change the indentation. If -unfilled or -literal are
1657: * specified, text is printed exactly as entered in the display:
1658: * for macro lines, a newline is appended to the line. Blank
1659: * lines are allowed.
1660: */
1.48 schwarze 1661:
1.60 schwarze 1662: if (MDOC_Literal != type && MDOC_Unfilled != type)
1.1 kristaps 1663: return(1);
1664:
1.75 schwarze 1665: tabwidth = p->tabwidth;
1666: p->tabwidth = 8;
1.77 schwarze 1667: rm = p->rmargin;
1668: rmax = p->maxrmargin;
1669: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1670:
1.60 schwarze 1671: for (nn = n->child; nn; nn = nn->next) {
1.48 schwarze 1672: p->flags |= TERMP_NOSPACE;
1.65 schwarze 1673: print_mdoc_node(p, pair, m, nn);
1.75 schwarze 1674: if (NULL == nn->prev ||
1675: nn->prev->line < nn->line ||
1676: NULL == nn->next)
1.1 kristaps 1677: term_flushln(p);
1678: }
1.75 schwarze 1679: p->tabwidth = tabwidth;
1.1 kristaps 1680:
1.77 schwarze 1681: p->rmargin = rm;
1682: p->maxrmargin = rmax;
1.1 kristaps 1683: return(0);
1684: }
1685:
1686:
1687: /* ARGSUSED */
1688: static void
1689: termp_bd_post(DECL_ARGS)
1690: {
1.77 schwarze 1691: int type;
1692: size_t rm, rmax;
1.1 kristaps 1693:
1.60 schwarze 1694: if (MDOC_BODY != n->type)
1.1 kristaps 1695: return;
1.77 schwarze 1696:
1697: type = arg_disptype(n->parent);
1698: assert(-1 != type);
1699:
1700: rm = p->rmargin;
1701: rmax = p->maxrmargin;
1702:
1703: if (MDOC_Literal == type || MDOC_Unfilled == type)
1704: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1705:
1.48 schwarze 1706: p->flags |= TERMP_NOSPACE;
1.75 schwarze 1707: term_newln(p);
1.77 schwarze 1708:
1709: p->rmargin = rm;
1710: p->maxrmargin = rmax;
1.1 kristaps 1711: }
1712:
1713:
1714: /* ARGSUSED */
1715: static int
1716: termp_qq_pre(DECL_ARGS)
1717: {
1718:
1.60 schwarze 1719: if (MDOC_BODY != n->type)
1.1 kristaps 1720: return(1);
1721: term_word(p, "\"");
1722: p->flags |= TERMP_NOSPACE;
1723: return(1);
1724: }
1725:
1726:
1727: /* ARGSUSED */
1728: static void
1729: termp_qq_post(DECL_ARGS)
1730: {
1731:
1.60 schwarze 1732: if (MDOC_BODY != n->type)
1.1 kristaps 1733: return;
1734: p->flags |= TERMP_NOSPACE;
1735: term_word(p, "\"");
1736: }
1737:
1738:
1739: /* ARGSUSED */
1740: static void
1741: termp_bx_post(DECL_ARGS)
1742: {
1743:
1.60 schwarze 1744: if (n->child)
1.1 kristaps 1745: p->flags |= TERMP_NOSPACE;
1746: term_word(p, "BSD");
1747: }
1748:
1749:
1750: /* ARGSUSED */
1751: static int
1.26 schwarze 1752: termp_xx_pre(DECL_ARGS)
1.1 kristaps 1753: {
1.26 schwarze 1754: const char *pp;
1.1 kristaps 1755:
1.26 schwarze 1756: pp = NULL;
1.60 schwarze 1757: switch (n->tok) {
1.26 schwarze 1758: case (MDOC_Bsx):
1759: pp = "BSDI BSD/OS";
1760: break;
1761: case (MDOC_Dx):
1.64 schwarze 1762: pp = "DragonFly";
1.26 schwarze 1763: break;
1764: case (MDOC_Fx):
1765: pp = "FreeBSD";
1766: break;
1767: case (MDOC_Nx):
1768: pp = "NetBSD";
1769: break;
1770: case (MDOC_Ox):
1771: pp = "OpenBSD";
1772: break;
1773: case (MDOC_Ux):
1774: pp = "UNIX";
1775: break;
1776: default:
1777: break;
1778: }
1.1 kristaps 1779:
1.26 schwarze 1780: assert(pp);
1781: term_word(p, pp);
1.1 kristaps 1782: return(1);
1783: }
1784:
1785:
1786: /* ARGSUSED */
1787: static int
1788: termp_sq_pre(DECL_ARGS)
1789: {
1790:
1.60 schwarze 1791: if (MDOC_BODY != n->type)
1.1 kristaps 1792: return(1);
1793: term_word(p, "\\(oq");
1794: p->flags |= TERMP_NOSPACE;
1795: return(1);
1796: }
1797:
1798:
1799: /* ARGSUSED */
1800: static void
1801: termp_sq_post(DECL_ARGS)
1802: {
1803:
1.60 schwarze 1804: if (MDOC_BODY != n->type)
1.1 kristaps 1805: return;
1806: p->flags |= TERMP_NOSPACE;
1807: term_word(p, "\\(aq");
1808: }
1809:
1810:
1811: /* ARGSUSED */
1812: static int
1813: termp_pf_pre(DECL_ARGS)
1814: {
1815:
1816: p->flags |= TERMP_IGNDELIM;
1817: return(1);
1818: }
1819:
1820:
1821: /* ARGSUSED */
1822: static void
1823: termp_pf_post(DECL_ARGS)
1824: {
1825:
1826: p->flags &= ~TERMP_IGNDELIM;
1827: p->flags |= TERMP_NOSPACE;
1828: }
1829:
1830:
1831: /* ARGSUSED */
1832: static int
1833: termp_ss_pre(DECL_ARGS)
1834: {
1835:
1.60 schwarze 1836: switch (n->type) {
1.1 kristaps 1837: case (MDOC_BLOCK):
1838: term_newln(p);
1.60 schwarze 1839: if (n->prev)
1.1 kristaps 1840: term_vspace(p);
1841: break;
1842: case (MDOC_HEAD):
1.65 schwarze 1843: term_fontpush(p, TERMFONT_BOLD);
1.3 schwarze 1844: p->offset = HALFINDENT;
1.1 kristaps 1845: break;
1846: default:
1847: break;
1848: }
1849:
1850: return(1);
1851: }
1852:
1853:
1854: /* ARGSUSED */
1855: static void
1856: termp_ss_post(DECL_ARGS)
1857: {
1858:
1.60 schwarze 1859: if (MDOC_HEAD == n->type)
1.1 kristaps 1860: term_newln(p);
1861: }
1862:
1863:
1864: /* ARGSUSED */
1865: static int
1866: termp_cd_pre(DECL_ARGS)
1867: {
1868:
1.65 schwarze 1869: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1870: term_newln(p);
1871: return(1);
1872: }
1873:
1874:
1875: /* ARGSUSED */
1876: static int
1877: termp_in_pre(DECL_ARGS)
1878: {
1879:
1.65 schwarze 1880: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1881: if (SEC_SYNOPSIS == n->sec)
1.23 schwarze 1882: term_word(p, "#include");
1883:
1.1 kristaps 1884: term_word(p, "<");
1885: p->flags |= TERMP_NOSPACE;
1886: return(1);
1887: }
1888:
1889:
1890: /* ARGSUSED */
1891: static void
1892: termp_in_post(DECL_ARGS)
1893: {
1894:
1.65 schwarze 1895: term_fontpush(p, TERMFONT_BOLD);
1.59 schwarze 1896: p->flags |= TERMP_NOSPACE;
1.1 kristaps 1897: term_word(p, ">");
1.65 schwarze 1898: term_fontpop(p);
1.1 kristaps 1899:
1.77 schwarze 1900: if (SEC_SYNOPSIS != n->sec && ! (MDOC_LINE & n->flags))
1.1 kristaps 1901: return;
1.23 schwarze 1902:
1903: term_newln(p);
1904: /*
1905: * XXX Not entirely correct. If `.In foo bar' is specified in
1906: * the SYNOPSIS section, then it produces a single break after
1907: * the <foo>; mandoc asserts a vertical space. Since this
1908: * construction is rarely used, I think it's fine.
1909: */
1.60 schwarze 1910: if (n->next && MDOC_In != n->next->tok)
1.1 kristaps 1911: term_vspace(p);
1.38 schwarze 1912: }
1913:
1914:
1915: /* ARGSUSED */
1916: static int
1917: termp_sp_pre(DECL_ARGS)
1918: {
1.61 schwarze 1919: size_t i, len;
1.38 schwarze 1920:
1.60 schwarze 1921: switch (n->tok) {
1.54 schwarze 1922: case (MDOC_sp):
1.62 schwarze 1923: len = n->child ? a2height(n->child) : 1;
1.54 schwarze 1924: break;
1925: case (MDOC_br):
1926: len = 0;
1927: break;
1928: default:
1929: len = 1;
1930: break;
1.38 schwarze 1931: }
1932:
1933: if (0 == len)
1934: term_newln(p);
1935: for (i = 0; i < len; i++)
1936: term_vspace(p);
1937:
1938: return(0);
1939: }
1940:
1941:
1942: /* ARGSUSED */
1943: static int
1.1 kristaps 1944: termp_brq_pre(DECL_ARGS)
1945: {
1946:
1.60 schwarze 1947: if (MDOC_BODY != n->type)
1.1 kristaps 1948: return(1);
1949: term_word(p, "\\(lC");
1950: p->flags |= TERMP_NOSPACE;
1951: return(1);
1952: }
1953:
1954:
1955: /* ARGSUSED */
1956: static void
1957: termp_brq_post(DECL_ARGS)
1958: {
1959:
1.60 schwarze 1960: if (MDOC_BODY != n->type)
1.1 kristaps 1961: return;
1962: p->flags |= TERMP_NOSPACE;
1963: term_word(p, "\\(rC");
1964: }
1965:
1966:
1967: /* ARGSUSED */
1968: static int
1969: termp_bq_pre(DECL_ARGS)
1970: {
1971:
1.60 schwarze 1972: if (MDOC_BODY != n->type)
1.1 kristaps 1973: return(1);
1974: term_word(p, "\\(lB");
1975: p->flags |= TERMP_NOSPACE;
1976: return(1);
1977: }
1978:
1979:
1980: /* ARGSUSED */
1981: static void
1982: termp_bq_post(DECL_ARGS)
1983: {
1984:
1.60 schwarze 1985: if (MDOC_BODY != n->type)
1.1 kristaps 1986: return;
1987: p->flags |= TERMP_NOSPACE;
1988: term_word(p, "\\(rB");
1989: }
1990:
1991:
1992: /* ARGSUSED */
1993: static int
1994: termp_pq_pre(DECL_ARGS)
1995: {
1996:
1.60 schwarze 1997: if (MDOC_BODY != n->type)
1.1 kristaps 1998: return(1);
1999: term_word(p, "\\&(");
2000: p->flags |= TERMP_NOSPACE;
2001: return(1);
2002: }
2003:
2004:
2005: /* ARGSUSED */
2006: static void
2007: termp_pq_post(DECL_ARGS)
2008: {
2009:
1.60 schwarze 2010: if (MDOC_BODY != n->type)
1.1 kristaps 2011: return;
2012: term_word(p, ")");
2013: }
2014:
2015:
2016: /* ARGSUSED */
2017: static int
2018: termp_fo_pre(DECL_ARGS)
2019: {
1.60 schwarze 2020: const struct mdoc_node *nn;
1.1 kristaps 2021:
1.60 schwarze 2022: if (MDOC_BODY == n->type) {
1.31 schwarze 2023: p->flags |= TERMP_NOSPACE;
1.1 kristaps 2024: term_word(p, "(");
2025: p->flags |= TERMP_NOSPACE;
2026: return(1);
1.60 schwarze 2027: } else if (MDOC_HEAD != n->type)
1.1 kristaps 2028: return(1);
2029:
1.65 schwarze 2030: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 2031: for (nn = n->child; nn; nn = nn->next) {
2032: assert(MDOC_TEXT == nn->type);
2033: term_word(p, nn->string);
1.1 kristaps 2034: }
1.65 schwarze 2035: term_fontpop(p);
1.1 kristaps 2036:
2037: return(0);
2038: }
2039:
2040:
2041: /* ARGSUSED */
2042: static void
2043: termp_fo_post(DECL_ARGS)
2044: {
2045:
1.60 schwarze 2046: if (MDOC_BODY != n->type)
1.1 kristaps 2047: return;
2048: p->flags |= TERMP_NOSPACE;
2049: term_word(p, ")");
2050: p->flags |= TERMP_NOSPACE;
2051: term_word(p, ";");
2052: term_newln(p);
2053: }
2054:
2055:
2056: /* ARGSUSED */
2057: static int
2058: termp_bf_pre(DECL_ARGS)
2059: {
1.60 schwarze 2060: const struct mdoc_node *nn;
1.1 kristaps 2061:
1.60 schwarze 2062: if (MDOC_HEAD == n->type)
1.1 kristaps 2063: return(0);
1.60 schwarze 2064: else if (MDOC_BLOCK != n->type)
1.1 kristaps 2065: return(1);
2066:
1.60 schwarze 2067: if (NULL == (nn = n->head->child)) {
2068: if (arg_hasattr(MDOC_Emphasis, n))
1.65 schwarze 2069: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 2070: else if (arg_hasattr(MDOC_Symbolic, n))
1.65 schwarze 2071: term_fontpush(p, TERMFONT_BOLD);
2072: else
2073: term_fontpush(p, TERMFONT_NONE);
1.1 kristaps 2074:
2075: return(1);
2076: }
2077:
1.60 schwarze 2078: assert(MDOC_TEXT == nn->type);
2079: if (0 == strcmp("Em", nn->string))
1.65 schwarze 2080: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 2081: else if (0 == strcmp("Sy", nn->string))
1.65 schwarze 2082: term_fontpush(p, TERMFONT_BOLD);
2083: else
2084: term_fontpush(p, TERMFONT_NONE);
1.1 kristaps 2085:
2086: return(1);
2087: }
2088:
2089:
2090: /* ARGSUSED */
2091: static int
2092: termp_sm_pre(DECL_ARGS)
2093: {
2094:
1.60 schwarze 2095: assert(n->child && MDOC_TEXT == n->child->type);
1.68 schwarze 2096: if (0 == strcmp("on", n->child->string))
1.1 kristaps 2097: p->flags &= ~TERMP_NONOSPACE;
1.68 schwarze 2098: else
1.1 kristaps 2099: p->flags |= TERMP_NONOSPACE;
2100:
2101: return(0);
2102: }
2103:
2104:
2105: /* ARGSUSED */
2106: static int
2107: termp_ap_pre(DECL_ARGS)
2108: {
2109:
2110: p->flags |= TERMP_NOSPACE;
2111: term_word(p, "\\(aq");
2112: p->flags |= TERMP_NOSPACE;
2113: return(1);
2114: }
2115:
2116:
2117: /* ARGSUSED */
2118: static void
2119: termp____post(DECL_ARGS)
2120: {
2121:
1.62 schwarze 2122: /* TODO: %U. */
2123:
1.1 kristaps 2124: p->flags |= TERMP_NOSPACE;
1.60 schwarze 2125: term_word(p, n->next ? "," : ".");
1.1 kristaps 2126: }
2127:
2128:
2129: /* ARGSUSED */
2130: static int
1.65 schwarze 2131: termp_li_pre(DECL_ARGS)
2132: {
2133:
2134: term_fontpush(p, TERMFONT_NONE);
2135: return(1);
2136: }
2137:
2138:
2139: /* ARGSUSED */
2140: static int
1.1 kristaps 2141: termp_lk_pre(DECL_ARGS)
2142: {
1.60 schwarze 2143: const struct mdoc_node *nn;
1.1 kristaps 2144:
1.65 schwarze 2145: term_fontpush(p, TERMFONT_UNDER);
1.62 schwarze 2146: nn = n->child;
2147:
2148: if (NULL == nn->next)
1.6 schwarze 2149: return(1);
1.1 kristaps 2150:
1.60 schwarze 2151: term_word(p, nn->string);
1.65 schwarze 2152: term_fontpop(p);
1.62 schwarze 2153:
1.1 kristaps 2154: p->flags |= TERMP_NOSPACE;
2155: term_word(p, ":");
2156:
1.65 schwarze 2157: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 2158: for (nn = nn->next; nn; nn = nn->next)
2159: term_word(p, nn->string);
1.65 schwarze 2160: term_fontpop(p);
1.6 schwarze 2161:
1.1 kristaps 2162: return(0);
2163: }
2164:
2165:
2166: /* ARGSUSED */
2167: static int
1.54 schwarze 2168: termp_under_pre(DECL_ARGS)
1.1 kristaps 2169: {
2170:
1.65 schwarze 2171: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 2172: return(1);
2173: }