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