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