Annotation of src/usr.bin/mandoc/mdoc_term.c, Revision 1.72
1.72 ! schwarze 1: /* $Id: mdoc_term.c,v 1.71 2010/03/26 01:22:05 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.72 ! schwarze 1278: if (NULL == n->child)
! 1279: return(0);
! 1280:
! 1281: assert(MDOC_TEXT == n->child->type);
1.60 schwarze 1282: nn = n->child;
1.10 schwarze 1283:
1.60 schwarze 1284: term_word(p, nn->string);
1285: if (NULL == (nn = nn->next))
1.1 kristaps 1286: return(0);
1287: p->flags |= TERMP_NOSPACE;
1288: term_word(p, "(");
1289: p->flags |= TERMP_NOSPACE;
1.60 schwarze 1290: term_word(p, nn->string);
1.1 kristaps 1291: p->flags |= TERMP_NOSPACE;
1292: term_word(p, ")");
1.60 schwarze 1293:
1.1 kristaps 1294: return(0);
1295: }
1296:
1297:
1.69 schwarze 1298: static int
1299: termp_vt_pre(DECL_ARGS)
1300: {
1301:
1302: if (MDOC_ELEM == n->type)
1303: return(termp_under_pre(p, pair, m, n));
1304: else if (MDOC_HEAD == n->type)
1305: return(0);
1306: else if (MDOC_BLOCK == n->type)
1307: return(1);
1308:
1309: return(termp_under_pre(p, pair, m, n));
1310: }
1311:
1312:
1.1 kristaps 1313: /* ARGSUSED */
1314: static void
1315: termp_vt_post(DECL_ARGS)
1316: {
1317:
1.69 schwarze 1318: if (MDOC_BLOCK != n->type)
1.30 schwarze 1319: return;
1.60 schwarze 1320: if (n->next && MDOC_Vt == n->next->tok)
1.30 schwarze 1321: term_newln(p);
1.60 schwarze 1322: else if (n->next)
1.1 kristaps 1323: term_vspace(p);
1324: }
1325:
1326:
1327: /* ARGSUSED */
1328: static int
1.54 schwarze 1329: termp_bold_pre(DECL_ARGS)
1.1 kristaps 1330: {
1331:
1.65 schwarze 1332: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1333: return(1);
1334: }
1335:
1336:
1337: /* ARGSUSED */
1338: static void
1339: termp_fd_post(DECL_ARGS)
1340: {
1341:
1.60 schwarze 1342: if (n->sec != SEC_SYNOPSIS)
1.1 kristaps 1343: return;
1.27 schwarze 1344:
1.1 kristaps 1345: term_newln(p);
1.60 schwarze 1346: if (n->next && MDOC_Fd != n->next->tok)
1.1 kristaps 1347: term_vspace(p);
1348: }
1349:
1350:
1351: /* ARGSUSED */
1352: static int
1353: termp_sh_pre(DECL_ARGS)
1354: {
1.60 schwarze 1355:
1356: /* No vspace between consecutive `Sh' calls. */
1357:
1358: switch (n->type) {
1.52 schwarze 1359: case (MDOC_BLOCK):
1.60 schwarze 1360: if (n->prev && MDOC_Sh == n->prev->tok)
1361: if (NULL == n->prev->body->child)
1.52 schwarze 1362: break;
1363: term_vspace(p);
1364: break;
1.1 kristaps 1365: case (MDOC_HEAD):
1.65 schwarze 1366: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1367: break;
1368: case (MDOC_BODY):
1369: p->offset = INDENT;
1370: break;
1371: default:
1372: break;
1373: }
1374: return(1);
1375: }
1376:
1377:
1378: /* ARGSUSED */
1379: static void
1380: termp_sh_post(DECL_ARGS)
1381: {
1382:
1.60 schwarze 1383: switch (n->type) {
1.1 kristaps 1384: case (MDOC_HEAD):
1385: term_newln(p);
1386: break;
1387: case (MDOC_BODY):
1388: term_newln(p);
1389: p->offset = 0;
1390: break;
1391: default:
1392: break;
1393: }
1394: }
1395:
1396:
1397: /* ARGSUSED */
1398: static int
1399: termp_op_pre(DECL_ARGS)
1400: {
1401:
1.60 schwarze 1402: switch (n->type) {
1.1 kristaps 1403: case (MDOC_BODY):
1404: term_word(p, "\\(lB");
1405: p->flags |= TERMP_NOSPACE;
1406: break;
1407: default:
1408: break;
1409: }
1410: return(1);
1411: }
1412:
1413:
1414: /* ARGSUSED */
1415: static int
1416: termp_bt_pre(DECL_ARGS)
1417: {
1418:
1419: term_word(p, "is currently in beta test.");
1.59 schwarze 1420: return(0);
1.1 kristaps 1421: }
1422:
1423:
1424: /* ARGSUSED */
1425: static void
1426: termp_lb_post(DECL_ARGS)
1427: {
1428:
1.60 schwarze 1429: if (SEC_LIBRARY == n->sec)
1.57 schwarze 1430: term_newln(p);
1.1 kristaps 1431: }
1432:
1433:
1434: /* ARGSUSED */
1435: static int
1436: termp_ud_pre(DECL_ARGS)
1437: {
1438:
1439: term_word(p, "currently under development.");
1.60 schwarze 1440: return(0);
1.1 kristaps 1441: }
1442:
1443:
1444: /* ARGSUSED */
1445: static int
1446: termp_d1_pre(DECL_ARGS)
1447: {
1448:
1.60 schwarze 1449: if (MDOC_BLOCK != n->type)
1.1 kristaps 1450: return(1);
1451: term_newln(p);
1.28 schwarze 1452: p->offset += (INDENT + 1);
1.1 kristaps 1453: return(1);
1454: }
1455:
1456:
1457: /* ARGSUSED */
1458: static void
1459: termp_d1_post(DECL_ARGS)
1460: {
1461:
1.60 schwarze 1462: if (MDOC_BLOCK != n->type)
1.1 kristaps 1463: return;
1464: term_newln(p);
1465: }
1466:
1467:
1468: /* ARGSUSED */
1469: static int
1470: termp_aq_pre(DECL_ARGS)
1471: {
1472:
1.60 schwarze 1473: if (MDOC_BODY != n->type)
1.1 kristaps 1474: return(1);
1475: term_word(p, "\\(la");
1476: p->flags |= TERMP_NOSPACE;
1477: return(1);
1478: }
1479:
1480:
1481: /* ARGSUSED */
1482: static void
1483: termp_aq_post(DECL_ARGS)
1484: {
1485:
1.60 schwarze 1486: if (MDOC_BODY != n->type)
1.1 kristaps 1487: return;
1488: p->flags |= TERMP_NOSPACE;
1489: term_word(p, "\\(ra");
1490: }
1491:
1492:
1493: /* ARGSUSED */
1494: static int
1495: termp_ft_pre(DECL_ARGS)
1496: {
1497:
1.60 schwarze 1498: if (SEC_SYNOPSIS == n->sec)
1499: if (n->prev && MDOC_Fo == n->prev->tok)
1.1 kristaps 1500: term_vspace(p);
1.65 schwarze 1501:
1502: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1503: return(1);
1504: }
1505:
1506:
1507: /* ARGSUSED */
1508: static void
1509: termp_ft_post(DECL_ARGS)
1510: {
1511:
1.60 schwarze 1512: if (SEC_SYNOPSIS == n->sec)
1.1 kristaps 1513: term_newln(p);
1514: }
1515:
1516:
1517: /* ARGSUSED */
1518: static int
1519: termp_fn_pre(DECL_ARGS)
1520: {
1.60 schwarze 1521: const struct mdoc_node *nn;
1.1 kristaps 1522:
1.65 schwarze 1523: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1524: term_word(p, n->child->string);
1.65 schwarze 1525: term_fontpop(p);
1.1 kristaps 1526:
1527: p->flags |= TERMP_NOSPACE;
1528: term_word(p, "(");
1529:
1.60 schwarze 1530: for (nn = n->child->next; nn; nn = nn->next) {
1.65 schwarze 1531: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 1532: term_word(p, nn->string);
1.65 schwarze 1533: term_fontpop(p);
1534:
1.60 schwarze 1535: if (nn->next)
1.1 kristaps 1536: term_word(p, ",");
1537: }
1538:
1539: term_word(p, ")");
1540:
1.60 schwarze 1541: if (SEC_SYNOPSIS == n->sec)
1.1 kristaps 1542: term_word(p, ";");
1543:
1544: return(0);
1545: }
1546:
1547:
1548: /* ARGSUSED */
1549: static void
1550: termp_fn_post(DECL_ARGS)
1551: {
1552:
1.60 schwarze 1553: if (n->sec == SEC_SYNOPSIS && n->next)
1.1 kristaps 1554: term_vspace(p);
1555: }
1556:
1557:
1558: /* ARGSUSED */
1559: static int
1560: termp_fa_pre(DECL_ARGS)
1561: {
1.60 schwarze 1562: const struct mdoc_node *nn;
1.1 kristaps 1563:
1.60 schwarze 1564: if (n->parent->tok != MDOC_Fo) {
1.65 schwarze 1565: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1566: return(1);
1567: }
1568:
1.60 schwarze 1569: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1570: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 1571: term_word(p, nn->string);
1.65 schwarze 1572: term_fontpop(p);
1573:
1.60 schwarze 1574: if (nn->next)
1.1 kristaps 1575: term_word(p, ",");
1576: }
1577:
1.60 schwarze 1578: if (n->child && n->next && n->next->tok == MDOC_Fa)
1.1 kristaps 1579: term_word(p, ",");
1580:
1581: return(0);
1582: }
1583:
1584:
1585: /* ARGSUSED */
1586: static int
1587: termp_bd_pre(DECL_ARGS)
1588: {
1.60 schwarze 1589: int i, type;
1590: const struct mdoc_node *nn;
1.1 kristaps 1591:
1.60 schwarze 1592: if (MDOC_BLOCK == n->type) {
1.61 schwarze 1593: print_bvspace(p, n, n);
1.45 schwarze 1594: return(1);
1.60 schwarze 1595: } else if (MDOC_BODY != n->type)
1.1 kristaps 1596: return(1);
1597:
1.60 schwarze 1598: nn = n->parent;
1.1 kristaps 1599:
1.60 schwarze 1600: for (type = -1, i = 0; i < (int)nn->args->argc; i++) {
1601: switch (nn->args->argv[i].arg) {
1.61 schwarze 1602: case (MDOC_Centred):
1603: /* FALLTHROUGH */
1.1 kristaps 1604: case (MDOC_Ragged):
1605: /* FALLTHROUGH */
1606: case (MDOC_Filled):
1607: /* FALLTHROUGH */
1608: case (MDOC_Unfilled):
1609: /* FALLTHROUGH */
1610: case (MDOC_Literal):
1.60 schwarze 1611: type = nn->args->argv[i].arg;
1612: break;
1613: case (MDOC_Offset):
1.62 schwarze 1614: p->offset += a2offs(&nn->args->argv[i]);
1.1 kristaps 1615: break;
1616: default:
1617: break;
1618: }
1619: }
1.60 schwarze 1620:
1621: /*
1622: * If -ragged or -filled are specified, the block does nothing
1623: * but change the indentation. If -unfilled or -literal are
1624: * specified, text is printed exactly as entered in the display:
1625: * for macro lines, a newline is appended to the line. Blank
1626: * lines are allowed.
1627: */
1.48 schwarze 1628:
1629: assert(type > -1);
1.60 schwarze 1630: if (MDOC_Literal != type && MDOC_Unfilled != type)
1.1 kristaps 1631: return(1);
1632:
1.60 schwarze 1633: for (nn = n->child; nn; nn = nn->next) {
1.48 schwarze 1634: p->flags |= TERMP_NOSPACE;
1.65 schwarze 1635: print_mdoc_node(p, pair, m, nn);
1.60 schwarze 1636: if (NULL == nn->next)
1637: continue;
1638: if (nn->prev && nn->prev->line < nn->line)
1639: term_flushln(p);
1640: else if (NULL == nn->prev)
1.1 kristaps 1641: term_flushln(p);
1642: }
1643:
1644: return(0);
1645: }
1646:
1647:
1648: /* ARGSUSED */
1649: static void
1650: termp_bd_post(DECL_ARGS)
1651: {
1652:
1.60 schwarze 1653: if (MDOC_BODY != n->type)
1.1 kristaps 1654: return;
1.48 schwarze 1655: p->flags |= TERMP_NOSPACE;
1.1 kristaps 1656: term_flushln(p);
1657: }
1658:
1659:
1660: /* ARGSUSED */
1661: static int
1662: termp_qq_pre(DECL_ARGS)
1663: {
1664:
1.60 schwarze 1665: if (MDOC_BODY != n->type)
1.1 kristaps 1666: return(1);
1667: term_word(p, "\"");
1668: p->flags |= TERMP_NOSPACE;
1669: return(1);
1670: }
1671:
1672:
1673: /* ARGSUSED */
1674: static void
1675: termp_qq_post(DECL_ARGS)
1676: {
1677:
1.60 schwarze 1678: if (MDOC_BODY != n->type)
1.1 kristaps 1679: return;
1680: p->flags |= TERMP_NOSPACE;
1681: term_word(p, "\"");
1682: }
1683:
1684:
1685: /* ARGSUSED */
1686: static void
1687: termp_bx_post(DECL_ARGS)
1688: {
1689:
1.60 schwarze 1690: if (n->child)
1.1 kristaps 1691: p->flags |= TERMP_NOSPACE;
1692: term_word(p, "BSD");
1693: }
1694:
1695:
1696: /* ARGSUSED */
1697: static int
1.26 schwarze 1698: termp_xx_pre(DECL_ARGS)
1.1 kristaps 1699: {
1.26 schwarze 1700: const char *pp;
1.1 kristaps 1701:
1.26 schwarze 1702: pp = NULL;
1.60 schwarze 1703: switch (n->tok) {
1.26 schwarze 1704: case (MDOC_Bsx):
1705: pp = "BSDI BSD/OS";
1706: break;
1707: case (MDOC_Dx):
1.64 schwarze 1708: pp = "DragonFly";
1.26 schwarze 1709: break;
1710: case (MDOC_Fx):
1711: pp = "FreeBSD";
1712: break;
1713: case (MDOC_Nx):
1714: pp = "NetBSD";
1715: break;
1716: case (MDOC_Ox):
1717: pp = "OpenBSD";
1718: break;
1719: case (MDOC_Ux):
1720: pp = "UNIX";
1721: break;
1722: default:
1723: break;
1724: }
1.1 kristaps 1725:
1.26 schwarze 1726: assert(pp);
1727: term_word(p, pp);
1.1 kristaps 1728: return(1);
1729: }
1730:
1731:
1732: /* ARGSUSED */
1733: static int
1734: termp_sq_pre(DECL_ARGS)
1735: {
1736:
1.60 schwarze 1737: if (MDOC_BODY != n->type)
1.1 kristaps 1738: return(1);
1739: term_word(p, "\\(oq");
1740: p->flags |= TERMP_NOSPACE;
1741: return(1);
1742: }
1743:
1744:
1745: /* ARGSUSED */
1746: static void
1747: termp_sq_post(DECL_ARGS)
1748: {
1749:
1.60 schwarze 1750: if (MDOC_BODY != n->type)
1.1 kristaps 1751: return;
1752: p->flags |= TERMP_NOSPACE;
1753: term_word(p, "\\(aq");
1754: }
1755:
1756:
1757: /* ARGSUSED */
1758: static int
1759: termp_pf_pre(DECL_ARGS)
1760: {
1761:
1762: p->flags |= TERMP_IGNDELIM;
1763: return(1);
1764: }
1765:
1766:
1767: /* ARGSUSED */
1768: static void
1769: termp_pf_post(DECL_ARGS)
1770: {
1771:
1772: p->flags &= ~TERMP_IGNDELIM;
1773: p->flags |= TERMP_NOSPACE;
1774: }
1775:
1776:
1777: /* ARGSUSED */
1778: static int
1779: termp_ss_pre(DECL_ARGS)
1780: {
1781:
1.60 schwarze 1782: switch (n->type) {
1.1 kristaps 1783: case (MDOC_BLOCK):
1784: term_newln(p);
1.60 schwarze 1785: if (n->prev)
1.1 kristaps 1786: term_vspace(p);
1787: break;
1788: case (MDOC_HEAD):
1.65 schwarze 1789: term_fontpush(p, TERMFONT_BOLD);
1.3 schwarze 1790: p->offset = HALFINDENT;
1.1 kristaps 1791: break;
1792: default:
1793: break;
1794: }
1795:
1796: return(1);
1797: }
1798:
1799:
1800: /* ARGSUSED */
1801: static void
1802: termp_ss_post(DECL_ARGS)
1803: {
1804:
1.60 schwarze 1805: if (MDOC_HEAD == n->type)
1.1 kristaps 1806: term_newln(p);
1807: }
1808:
1809:
1810: /* ARGSUSED */
1811: static int
1812: termp_cd_pre(DECL_ARGS)
1813: {
1814:
1.65 schwarze 1815: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1816: term_newln(p);
1817: return(1);
1818: }
1819:
1820:
1821: /* ARGSUSED */
1822: static int
1823: termp_in_pre(DECL_ARGS)
1824: {
1825:
1.65 schwarze 1826: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1827: if (SEC_SYNOPSIS == n->sec)
1.23 schwarze 1828: term_word(p, "#include");
1829:
1.1 kristaps 1830: term_word(p, "<");
1831: p->flags |= TERMP_NOSPACE;
1832: return(1);
1833: }
1834:
1835:
1836: /* ARGSUSED */
1837: static void
1838: termp_in_post(DECL_ARGS)
1839: {
1840:
1.65 schwarze 1841: term_fontpush(p, TERMFONT_BOLD);
1.59 schwarze 1842: p->flags |= TERMP_NOSPACE;
1.1 kristaps 1843: term_word(p, ">");
1.65 schwarze 1844: term_fontpop(p);
1.1 kristaps 1845:
1.60 schwarze 1846: if (SEC_SYNOPSIS != n->sec)
1.1 kristaps 1847: return;
1.23 schwarze 1848:
1849: term_newln(p);
1850: /*
1851: * XXX Not entirely correct. If `.In foo bar' is specified in
1852: * the SYNOPSIS section, then it produces a single break after
1853: * the <foo>; mandoc asserts a vertical space. Since this
1854: * construction is rarely used, I think it's fine.
1855: */
1.60 schwarze 1856: if (n->next && MDOC_In != n->next->tok)
1.1 kristaps 1857: term_vspace(p);
1.38 schwarze 1858: }
1859:
1860:
1861: /* ARGSUSED */
1862: static int
1863: termp_sp_pre(DECL_ARGS)
1864: {
1.61 schwarze 1865: size_t i, len;
1.38 schwarze 1866:
1.60 schwarze 1867: switch (n->tok) {
1.54 schwarze 1868: case (MDOC_sp):
1.62 schwarze 1869: len = n->child ? a2height(n->child) : 1;
1.54 schwarze 1870: break;
1871: case (MDOC_br):
1872: len = 0;
1873: break;
1874: default:
1875: len = 1;
1876: break;
1.38 schwarze 1877: }
1878:
1879: if (0 == len)
1880: term_newln(p);
1881: for (i = 0; i < len; i++)
1882: term_vspace(p);
1883:
1884: return(0);
1885: }
1886:
1887:
1888: /* ARGSUSED */
1889: static int
1.1 kristaps 1890: termp_brq_pre(DECL_ARGS)
1891: {
1892:
1.60 schwarze 1893: if (MDOC_BODY != n->type)
1.1 kristaps 1894: return(1);
1895: term_word(p, "\\(lC");
1896: p->flags |= TERMP_NOSPACE;
1897: return(1);
1898: }
1899:
1900:
1901: /* ARGSUSED */
1902: static void
1903: termp_brq_post(DECL_ARGS)
1904: {
1905:
1.60 schwarze 1906: if (MDOC_BODY != n->type)
1.1 kristaps 1907: return;
1908: p->flags |= TERMP_NOSPACE;
1909: term_word(p, "\\(rC");
1910: }
1911:
1912:
1913: /* ARGSUSED */
1914: static int
1915: termp_bq_pre(DECL_ARGS)
1916: {
1917:
1.60 schwarze 1918: if (MDOC_BODY != n->type)
1.1 kristaps 1919: return(1);
1920: term_word(p, "\\(lB");
1921: p->flags |= TERMP_NOSPACE;
1922: return(1);
1923: }
1924:
1925:
1926: /* ARGSUSED */
1927: static void
1928: termp_bq_post(DECL_ARGS)
1929: {
1930:
1.60 schwarze 1931: if (MDOC_BODY != n->type)
1.1 kristaps 1932: return;
1933: p->flags |= TERMP_NOSPACE;
1934: term_word(p, "\\(rB");
1935: }
1936:
1937:
1938: /* ARGSUSED */
1939: static int
1940: termp_pq_pre(DECL_ARGS)
1941: {
1942:
1.60 schwarze 1943: if (MDOC_BODY != n->type)
1.1 kristaps 1944: return(1);
1945: term_word(p, "\\&(");
1946: p->flags |= TERMP_NOSPACE;
1947: return(1);
1948: }
1949:
1950:
1951: /* ARGSUSED */
1952: static void
1953: termp_pq_post(DECL_ARGS)
1954: {
1955:
1.60 schwarze 1956: if (MDOC_BODY != n->type)
1.1 kristaps 1957: return;
1958: term_word(p, ")");
1959: }
1960:
1961:
1962: /* ARGSUSED */
1963: static int
1964: termp_fo_pre(DECL_ARGS)
1965: {
1.60 schwarze 1966: const struct mdoc_node *nn;
1.1 kristaps 1967:
1.60 schwarze 1968: if (MDOC_BODY == n->type) {
1.31 schwarze 1969: p->flags |= TERMP_NOSPACE;
1.1 kristaps 1970: term_word(p, "(");
1971: p->flags |= TERMP_NOSPACE;
1972: return(1);
1.60 schwarze 1973: } else if (MDOC_HEAD != n->type)
1.1 kristaps 1974: return(1);
1975:
1.65 schwarze 1976: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1977: for (nn = n->child; nn; nn = nn->next) {
1978: assert(MDOC_TEXT == nn->type);
1979: term_word(p, nn->string);
1.1 kristaps 1980: }
1.65 schwarze 1981: term_fontpop(p);
1.1 kristaps 1982:
1983: return(0);
1984: }
1985:
1986:
1987: /* ARGSUSED */
1988: static void
1989: termp_fo_post(DECL_ARGS)
1990: {
1991:
1.60 schwarze 1992: if (MDOC_BODY != n->type)
1.1 kristaps 1993: return;
1994: p->flags |= TERMP_NOSPACE;
1995: term_word(p, ")");
1996: p->flags |= TERMP_NOSPACE;
1997: term_word(p, ";");
1998: term_newln(p);
1999: }
2000:
2001:
2002: /* ARGSUSED */
2003: static int
2004: termp_bf_pre(DECL_ARGS)
2005: {
1.60 schwarze 2006: const struct mdoc_node *nn;
1.1 kristaps 2007:
1.60 schwarze 2008: if (MDOC_HEAD == n->type)
1.1 kristaps 2009: return(0);
1.60 schwarze 2010: else if (MDOC_BLOCK != n->type)
1.1 kristaps 2011: return(1);
2012:
1.60 schwarze 2013: if (NULL == (nn = n->head->child)) {
2014: if (arg_hasattr(MDOC_Emphasis, n))
1.65 schwarze 2015: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 2016: else if (arg_hasattr(MDOC_Symbolic, n))
1.65 schwarze 2017: term_fontpush(p, TERMFONT_BOLD);
2018: else
2019: term_fontpush(p, TERMFONT_NONE);
1.1 kristaps 2020:
2021: return(1);
2022: }
2023:
1.60 schwarze 2024: assert(MDOC_TEXT == nn->type);
2025: if (0 == strcmp("Em", nn->string))
1.65 schwarze 2026: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 2027: else if (0 == strcmp("Sy", nn->string))
1.65 schwarze 2028: term_fontpush(p, TERMFONT_BOLD);
2029: else
2030: term_fontpush(p, TERMFONT_NONE);
1.1 kristaps 2031:
2032: return(1);
2033: }
2034:
2035:
2036: /* ARGSUSED */
2037: static int
2038: termp_sm_pre(DECL_ARGS)
2039: {
2040:
1.60 schwarze 2041: assert(n->child && MDOC_TEXT == n->child->type);
1.68 schwarze 2042: if (0 == strcmp("on", n->child->string))
1.1 kristaps 2043: p->flags &= ~TERMP_NONOSPACE;
1.68 schwarze 2044: else
1.1 kristaps 2045: p->flags |= TERMP_NONOSPACE;
2046:
2047: return(0);
2048: }
2049:
2050:
2051: /* ARGSUSED */
2052: static int
2053: termp_ap_pre(DECL_ARGS)
2054: {
2055:
2056: p->flags |= TERMP_NOSPACE;
2057: term_word(p, "\\(aq");
2058: p->flags |= TERMP_NOSPACE;
2059: return(1);
2060: }
2061:
2062:
2063: /* ARGSUSED */
2064: static void
2065: termp____post(DECL_ARGS)
2066: {
2067:
1.62 schwarze 2068: /* TODO: %U. */
2069:
1.1 kristaps 2070: p->flags |= TERMP_NOSPACE;
1.60 schwarze 2071: switch (n->tok) {
1.58 schwarze 2072: case (MDOC__T):
2073: term_word(p, "\\(rq");
2074: p->flags |= TERMP_NOSPACE;
2075: break;
2076: default:
2077: break;
2078: }
1.60 schwarze 2079: term_word(p, n->next ? "," : ".");
1.1 kristaps 2080: }
2081:
2082:
2083: /* ARGSUSED */
2084: static int
1.65 schwarze 2085: termp_li_pre(DECL_ARGS)
2086: {
2087:
2088: term_fontpush(p, TERMFONT_NONE);
2089: return(1);
2090: }
2091:
2092:
2093: /* ARGSUSED */
2094: static int
1.1 kristaps 2095: termp_lk_pre(DECL_ARGS)
2096: {
1.60 schwarze 2097: const struct mdoc_node *nn;
1.1 kristaps 2098:
1.65 schwarze 2099: term_fontpush(p, TERMFONT_UNDER);
1.62 schwarze 2100: nn = n->child;
2101:
2102: if (NULL == nn->next)
1.6 schwarze 2103: return(1);
1.1 kristaps 2104:
1.60 schwarze 2105: term_word(p, nn->string);
1.65 schwarze 2106: term_fontpop(p);
1.62 schwarze 2107:
1.1 kristaps 2108: p->flags |= TERMP_NOSPACE;
2109: term_word(p, ":");
2110:
1.65 schwarze 2111: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 2112: for (nn = nn->next; nn; nn = nn->next)
2113: term_word(p, nn->string);
1.65 schwarze 2114: term_fontpop(p);
1.6 schwarze 2115:
1.1 kristaps 2116: return(0);
2117: }
2118:
2119:
2120: /* ARGSUSED */
2121: static int
1.54 schwarze 2122: termp_under_pre(DECL_ARGS)
1.1 kristaps 2123: {
2124:
1.65 schwarze 2125: term_fontpush(p, TERMFONT_UNDER);
1.58 schwarze 2126: return(1);
2127: }
2128:
2129:
2130: /* ARGSUSED */
2131: static int
2132: termp__t_pre(DECL_ARGS)
2133: {
2134:
2135: term_word(p, "\\(lq");
1.70 schwarze 2136: p->flags |= TERMP_NOSPACE;
2137: return(1);
2138: }
2139:
2140:
2141: /* ARGSUSED */
2142: static int
2143: termp_eos_pre(DECL_ARGS)
2144: {
2145: const char ascii_eos[2] = { ASCII_EOS, 0 };
2146:
2147: term_word(p, ascii_eos);
1.58 schwarze 2148: p->flags |= TERMP_NOSPACE;
1.1 kristaps 2149: return(1);
2150: }