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