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