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