Annotation of src/usr.bin/mandoc/mdoc_term.c, Revision 1.106
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) {
1.105 schwarze 1030: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
1031: p->rmargin = p->offset + term_len(p, 1);
1032: if (NULL == n->child) {
1033: p->rmargin += term_strlen(p, m->name);
1034: } else if (MDOC_TEXT == n->child->type) {
1035: p->rmargin += term_strlen(p, n->child->string);
1036: if (n->child->next)
1037: p->flags |= TERMP_HANG;
1038: } else {
1039: p->rmargin += term_len(p, 5);
1040: p->flags |= TERMP_HANG;
1041: }
1.94 schwarze 1042: }
1043:
1.65 schwarze 1044: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1045: if (NULL == n->child)
1046: term_word(p, m->name);
1.1 kristaps 1047: return(1);
1048: }
1049:
1050:
1.94 schwarze 1051: /* ARGSUSED */
1052: static void
1053: termp_nm_post(DECL_ARGS)
1054: {
1055:
1056: if (MDOC_HEAD == n->type && n->next->child) {
1057: term_flushln(p);
1058: p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
1059: } else if (MDOC_BODY == n->type && n->child) {
1060: term_flushln(p);
1061: p->flags &= ~TERMP_NOLPAD;
1062: }
1063: }
1064:
1065:
1.1 kristaps 1066: /* ARGSUSED */
1067: static int
1068: termp_fl_pre(DECL_ARGS)
1069: {
1070:
1.65 schwarze 1071: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1072: term_word(p, "\\-");
1.67 schwarze 1073:
1074: if (n->child)
1075: p->flags |= TERMP_NOSPACE;
1.73 schwarze 1076: else if (n->next && n->next->line == n->line)
1077: p->flags |= TERMP_NOSPACE;
1.67 schwarze 1078:
1.1 kristaps 1079: return(1);
1.49 schwarze 1080: }
1081:
1082:
1083: /* ARGSUSED */
1084: static int
1.104 schwarze 1085: termp__a_pre(DECL_ARGS)
1086: {
1087:
1088: if (n->prev && MDOC__A == n->prev->tok)
1089: if (NULL == n->next || MDOC__A != n->next->tok)
1090: term_word(p, "and");
1091:
1092: return(1);
1093: }
1094:
1095:
1096: /* ARGSUSED */
1097: static int
1.49 schwarze 1098: termp_an_pre(DECL_ARGS)
1099: {
1100:
1.60 schwarze 1101: if (NULL == n->child)
1.49 schwarze 1102: return(1);
1103:
1104: /*
1.60 schwarze 1105: * If not in the AUTHORS section, `An -split' will cause
1106: * newlines to occur before the author name. If in the AUTHORS
1107: * section, by default, the first `An' invocation is nosplit,
1108: * then all subsequent ones, regardless of whether interspersed
1109: * with other macros/text, are split. -split, in this case,
1110: * will override the condition of the implied first -nosplit.
1.49 schwarze 1111: */
1112:
1.60 schwarze 1113: if (n->sec == SEC_AUTHORS) {
1.49 schwarze 1114: if ( ! (TERMP_ANPREC & p->flags)) {
1115: if (TERMP_SPLIT & p->flags)
1116: term_newln(p);
1117: return(1);
1118: }
1119: if (TERMP_NOSPLIT & p->flags)
1120: return(1);
1121: term_newln(p);
1122: return(1);
1123: }
1124:
1125: if (TERMP_SPLIT & p->flags)
1126: term_newln(p);
1127:
1128: return(1);
1129: }
1130:
1131:
1132: /* ARGSUSED */
1133: static void
1134: termp_an_post(DECL_ARGS)
1135: {
1136:
1.60 schwarze 1137: if (n->child) {
1138: if (SEC_AUTHORS == n->sec)
1.49 schwarze 1139: p->flags |= TERMP_ANPREC;
1140: return;
1141: }
1142:
1.95 schwarze 1143: if (AUTH_split == n->data.An.auth) {
1.49 schwarze 1144: p->flags &= ~TERMP_NOSPLIT;
1145: p->flags |= TERMP_SPLIT;
1.95 schwarze 1146: } else if (AUTH_nosplit == n->data.An.auth) {
1.49 schwarze 1147: p->flags &= ~TERMP_SPLIT;
1148: p->flags |= TERMP_NOSPLIT;
1149: }
1150:
1.1 kristaps 1151: }
1152:
1153:
1154: /* ARGSUSED */
1155: static int
1156: termp_ns_pre(DECL_ARGS)
1157: {
1158:
1159: p->flags |= TERMP_NOSPACE;
1160: return(1);
1161: }
1162:
1163:
1164: /* ARGSUSED */
1165: static int
1166: termp_rs_pre(DECL_ARGS)
1167: {
1168:
1.60 schwarze 1169: if (SEC_SEE_ALSO != n->sec)
1.57 schwarze 1170: return(1);
1.60 schwarze 1171: if (MDOC_BLOCK == n->type && n->prev)
1.1 kristaps 1172: term_vspace(p);
1173: return(1);
1174: }
1175:
1176:
1177: /* ARGSUSED */
1178: static int
1179: termp_rv_pre(DECL_ARGS)
1180: {
1.53 schwarze 1181: const struct mdoc_node *nn;
1.1 kristaps 1182:
1183: term_newln(p);
1184: term_word(p, "The");
1185:
1.60 schwarze 1186: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1187: term_fontpush(p, TERMFONT_BOLD);
1.53 schwarze 1188: term_word(p, nn->string);
1.65 schwarze 1189: term_fontpop(p);
1.53 schwarze 1190: p->flags |= TERMP_NOSPACE;
1191: if (nn->next && NULL == nn->next->next)
1192: term_word(p, "(), and");
1193: else if (nn->next)
1194: term_word(p, "(),");
1195: else
1196: term_word(p, "()");
1197: }
1198:
1.81 schwarze 1199: if (n->child && n->child->next)
1.53 schwarze 1200: term_word(p, "functions return");
1201: else
1202: term_word(p, "function returns");
1.1 kristaps 1203:
1.53 schwarze 1204: term_word(p, "the value 0 if successful; otherwise the value "
1205: "-1 is returned and the global variable");
1.1 kristaps 1206:
1.65 schwarze 1207: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1208: term_word(p, "errno");
1.65 schwarze 1209: term_fontpop(p);
1.1 kristaps 1210:
1211: term_word(p, "is set to indicate the error.");
1.84 schwarze 1212: p->flags |= TERMP_SENTENCE;
1.1 kristaps 1213:
1.53 schwarze 1214: return(0);
1.1 kristaps 1215: }
1216:
1217:
1218: /* ARGSUSED */
1219: static int
1220: termp_ex_pre(DECL_ARGS)
1221: {
1.53 schwarze 1222: const struct mdoc_node *nn;
1.1 kristaps 1223:
1.53 schwarze 1224: term_word(p, "The");
1.1 kristaps 1225:
1.60 schwarze 1226: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1227: term_fontpush(p, TERMFONT_BOLD);
1.53 schwarze 1228: term_word(p, nn->string);
1.65 schwarze 1229: term_fontpop(p);
1.53 schwarze 1230: p->flags |= TERMP_NOSPACE;
1231: if (nn->next && NULL == nn->next->next)
1232: term_word(p, ", and");
1233: else if (nn->next)
1234: term_word(p, ",");
1235: else
1236: p->flags &= ~TERMP_NOSPACE;
1237: }
1238:
1.81 schwarze 1239: if (n->child && n->child->next)
1.53 schwarze 1240: term_word(p, "utilities exit");
1241: else
1242: term_word(p, "utility exits");
1243:
1244: term_word(p, "0 on success, and >0 if an error occurs.");
1.84 schwarze 1245: p->flags |= TERMP_SENTENCE;
1.1 kristaps 1246:
1.53 schwarze 1247: return(0);
1.1 kristaps 1248: }
1249:
1250:
1251: /* ARGSUSED */
1252: static int
1253: termp_nd_pre(DECL_ARGS)
1254: {
1.25 schwarze 1255:
1.60 schwarze 1256: if (MDOC_BODY != n->type)
1.25 schwarze 1257: return(1);
1258:
1259: #if defined(__OpenBSD__) || defined(__linux__)
1260: term_word(p, "\\(en");
1.24 schwarze 1261: #else
1262: term_word(p, "\\(em");
1263: #endif
1.1 kristaps 1264: return(1);
1265: }
1266:
1267:
1268: /* ARGSUSED */
1.73 schwarze 1269: static int
1270: termp_bl_pre(DECL_ARGS)
1271: {
1272:
1273: return(MDOC_HEAD != n->type);
1274: }
1275:
1276:
1277: /* ARGSUSED */
1.1 kristaps 1278: static void
1279: termp_bl_post(DECL_ARGS)
1280: {
1281:
1.60 schwarze 1282: if (MDOC_BLOCK == n->type)
1.1 kristaps 1283: term_newln(p);
1284: }
1285:
1286:
1287: /* ARGSUSED */
1288: static void
1289: termp_op_post(DECL_ARGS)
1290: {
1291:
1.60 schwarze 1292: if (MDOC_BODY != n->type)
1.1 kristaps 1293: return;
1294: p->flags |= TERMP_NOSPACE;
1295: term_word(p, "\\(rB");
1296: }
1297:
1298:
1299: /* ARGSUSED */
1300: static int
1301: termp_xr_pre(DECL_ARGS)
1302: {
1.60 schwarze 1303: const struct mdoc_node *nn;
1.1 kristaps 1304:
1.72 schwarze 1305: if (NULL == n->child)
1306: return(0);
1307:
1308: assert(MDOC_TEXT == n->child->type);
1.60 schwarze 1309: nn = n->child;
1.10 schwarze 1310:
1.60 schwarze 1311: term_word(p, nn->string);
1312: if (NULL == (nn = nn->next))
1.1 kristaps 1313: return(0);
1314: p->flags |= TERMP_NOSPACE;
1315: term_word(p, "(");
1316: p->flags |= TERMP_NOSPACE;
1.60 schwarze 1317: term_word(p, nn->string);
1.1 kristaps 1318: p->flags |= TERMP_NOSPACE;
1319: term_word(p, ")");
1.60 schwarze 1320:
1.1 kristaps 1321: return(0);
1322: }
1323:
1324:
1.86 schwarze 1325: /*
1326: * This decides how to assert whitespace before any of the SYNOPSIS set
1327: * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
1328: * macro combos).
1329: */
1330: static void
1331: synopsis_pre(struct termp *p, const struct mdoc_node *n)
1332: {
1333: /*
1334: * Obviously, if we're not in a SYNOPSIS or no prior macros
1335: * exist, do nothing.
1336: */
1.92 schwarze 1337: if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
1.86 schwarze 1338: return;
1339:
1340: /*
1341: * If we're the second in a pair of like elements, emit our
1342: * newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
1343: * case we soldier on.
1344: */
1345: if (n->prev->tok == n->tok &&
1346: MDOC_Ft != n->tok &&
1347: MDOC_Fo != n->tok &&
1348: MDOC_Fn != n->tok) {
1349: term_newln(p);
1350: return;
1351: }
1352:
1353: /*
1354: * If we're one of the SYNOPSIS set and non-like pair-wise after
1355: * another (or Fn/Fo, which we've let slip through) then assert
1356: * vertical space, else only newline and move on.
1357: */
1358: switch (n->prev->tok) {
1359: case (MDOC_Fd):
1360: /* FALLTHROUGH */
1361: case (MDOC_Fn):
1362: /* FALLTHROUGH */
1363: case (MDOC_Fo):
1364: /* FALLTHROUGH */
1365: case (MDOC_In):
1366: /* FALLTHROUGH */
1367: case (MDOC_Vt):
1368: term_vspace(p);
1369: break;
1370: case (MDOC_Ft):
1371: if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
1372: term_vspace(p);
1373: break;
1374: }
1375: /* FALLTHROUGH */
1376: default:
1377: term_newln(p);
1378: break;
1379: }
1380: }
1381:
1382:
1.69 schwarze 1383: static int
1384: termp_vt_pre(DECL_ARGS)
1385: {
1386:
1.86 schwarze 1387: if (MDOC_ELEM == n->type) {
1388: synopsis_pre(p, n);
1.69 schwarze 1389: return(termp_under_pre(p, pair, m, n));
1.86 schwarze 1390: } else if (MDOC_BLOCK == n->type) {
1391: synopsis_pre(p, n);
1392: return(1);
1393: } else if (MDOC_HEAD == n->type)
1.69 schwarze 1394: return(0);
1395:
1396: return(termp_under_pre(p, pair, m, n));
1397: }
1398:
1399:
1.1 kristaps 1400: /* ARGSUSED */
1401: static int
1.54 schwarze 1402: termp_bold_pre(DECL_ARGS)
1.1 kristaps 1403: {
1404:
1.65 schwarze 1405: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1406: return(1);
1407: }
1408:
1409:
1410: /* ARGSUSED */
1.86 schwarze 1411: static int
1412: termp_fd_pre(DECL_ARGS)
1.1 kristaps 1413: {
1414:
1.86 schwarze 1415: synopsis_pre(p, n);
1416: return(termp_bold_pre(p, pair, m, n));
1.1 kristaps 1417: }
1418:
1419:
1420: /* ARGSUSED */
1421: static int
1422: termp_sh_pre(DECL_ARGS)
1423: {
1.60 schwarze 1424:
1425: /* No vspace between consecutive `Sh' calls. */
1426:
1427: switch (n->type) {
1.52 schwarze 1428: case (MDOC_BLOCK):
1.60 schwarze 1429: if (n->prev && MDOC_Sh == n->prev->tok)
1430: if (NULL == n->prev->body->child)
1.52 schwarze 1431: break;
1432: term_vspace(p);
1433: break;
1.1 kristaps 1434: case (MDOC_HEAD):
1.65 schwarze 1435: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1436: break;
1437: case (MDOC_BODY):
1.89 schwarze 1438: p->offset = term_len(p, INDENT);
1.1 kristaps 1439: break;
1440: default:
1441: break;
1442: }
1443: return(1);
1444: }
1445:
1446:
1447: /* ARGSUSED */
1448: static void
1449: termp_sh_post(DECL_ARGS)
1450: {
1451:
1.60 schwarze 1452: switch (n->type) {
1.1 kristaps 1453: case (MDOC_HEAD):
1454: term_newln(p);
1455: break;
1456: case (MDOC_BODY):
1457: term_newln(p);
1458: p->offset = 0;
1459: break;
1460: default:
1461: break;
1462: }
1463: }
1464:
1465:
1466: /* ARGSUSED */
1467: static int
1468: termp_op_pre(DECL_ARGS)
1469: {
1470:
1.60 schwarze 1471: switch (n->type) {
1.1 kristaps 1472: case (MDOC_BODY):
1473: term_word(p, "\\(lB");
1474: p->flags |= TERMP_NOSPACE;
1475: break;
1476: default:
1477: break;
1478: }
1479: return(1);
1480: }
1481:
1482:
1483: /* ARGSUSED */
1484: static int
1485: termp_bt_pre(DECL_ARGS)
1486: {
1487:
1488: term_word(p, "is currently in beta test.");
1.84 schwarze 1489: p->flags |= TERMP_SENTENCE;
1.59 schwarze 1490: return(0);
1.1 kristaps 1491: }
1492:
1493:
1494: /* ARGSUSED */
1495: static void
1496: termp_lb_post(DECL_ARGS)
1497: {
1498:
1.77 schwarze 1499: if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
1.57 schwarze 1500: term_newln(p);
1.1 kristaps 1501: }
1502:
1503:
1504: /* ARGSUSED */
1505: static int
1506: termp_ud_pre(DECL_ARGS)
1507: {
1508:
1509: term_word(p, "currently under development.");
1.84 schwarze 1510: p->flags |= TERMP_SENTENCE;
1.60 schwarze 1511: return(0);
1.1 kristaps 1512: }
1513:
1514:
1515: /* ARGSUSED */
1516: static int
1517: termp_d1_pre(DECL_ARGS)
1518: {
1519:
1.60 schwarze 1520: if (MDOC_BLOCK != n->type)
1.1 kristaps 1521: return(1);
1522: term_newln(p);
1.89 schwarze 1523: p->offset += term_len(p, (INDENT + 1));
1.1 kristaps 1524: return(1);
1525: }
1526:
1527:
1528: /* ARGSUSED */
1529: static void
1530: termp_d1_post(DECL_ARGS)
1531: {
1532:
1.60 schwarze 1533: if (MDOC_BLOCK != n->type)
1.1 kristaps 1534: return;
1535: term_newln(p);
1536: }
1537:
1538:
1539: /* ARGSUSED */
1540: static int
1541: termp_aq_pre(DECL_ARGS)
1542: {
1543:
1.60 schwarze 1544: if (MDOC_BODY != n->type)
1.1 kristaps 1545: return(1);
1546: term_word(p, "\\(la");
1547: p->flags |= TERMP_NOSPACE;
1548: return(1);
1549: }
1550:
1551:
1552: /* ARGSUSED */
1553: static void
1554: termp_aq_post(DECL_ARGS)
1555: {
1556:
1.60 schwarze 1557: if (MDOC_BODY != n->type)
1.1 kristaps 1558: return;
1559: p->flags |= TERMP_NOSPACE;
1560: term_word(p, "\\(ra");
1561: }
1562:
1563:
1564: /* ARGSUSED */
1565: static int
1566: termp_ft_pre(DECL_ARGS)
1567: {
1568:
1.85 schwarze 1569: /* NB: MDOC_LINE does not effect this! */
1.86 schwarze 1570: synopsis_pre(p, n);
1.65 schwarze 1571: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1572: return(1);
1573: }
1574:
1575:
1576: /* ARGSUSED */
1577: static int
1578: termp_fn_pre(DECL_ARGS)
1579: {
1.60 schwarze 1580: const struct mdoc_node *nn;
1.1 kristaps 1581:
1.86 schwarze 1582: synopsis_pre(p, n);
1.85 schwarze 1583:
1.65 schwarze 1584: term_fontpush(p, TERMFONT_BOLD);
1.60 schwarze 1585: term_word(p, n->child->string);
1.65 schwarze 1586: term_fontpop(p);
1.1 kristaps 1587:
1588: p->flags |= TERMP_NOSPACE;
1589: term_word(p, "(");
1590:
1.60 schwarze 1591: for (nn = n->child->next; nn; nn = nn->next) {
1.65 schwarze 1592: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 1593: term_word(p, nn->string);
1.65 schwarze 1594: term_fontpop(p);
1595:
1.60 schwarze 1596: if (nn->next)
1.1 kristaps 1597: term_word(p, ",");
1598: }
1599:
1600: term_word(p, ")");
1601:
1.92 schwarze 1602: if (MDOC_SYNPRETTY & n->flags)
1.1 kristaps 1603: term_word(p, ";");
1604:
1605: return(0);
1606: }
1607:
1608:
1609: /* ARGSUSED */
1610: static int
1611: termp_fa_pre(DECL_ARGS)
1612: {
1.60 schwarze 1613: const struct mdoc_node *nn;
1.1 kristaps 1614:
1.60 schwarze 1615: if (n->parent->tok != MDOC_Fo) {
1.65 schwarze 1616: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 1617: return(1);
1618: }
1619:
1.60 schwarze 1620: for (nn = n->child; nn; nn = nn->next) {
1.65 schwarze 1621: term_fontpush(p, TERMFONT_UNDER);
1.60 schwarze 1622: term_word(p, nn->string);
1.65 schwarze 1623: term_fontpop(p);
1624:
1.60 schwarze 1625: if (nn->next)
1.1 kristaps 1626: term_word(p, ",");
1627: }
1628:
1.60 schwarze 1629: if (n->child && n->next && n->next->tok == MDOC_Fa)
1.1 kristaps 1630: term_word(p, ",");
1631:
1632: return(0);
1633: }
1634:
1635:
1636: /* ARGSUSED */
1637: static int
1638: termp_bd_pre(DECL_ARGS)
1639: {
1.99 schwarze 1640: size_t tabwidth, rm, rmax;
1.60 schwarze 1641: const struct mdoc_node *nn;
1.1 kristaps 1642:
1.60 schwarze 1643: if (MDOC_BLOCK == n->type) {
1.61 schwarze 1644: print_bvspace(p, n, n);
1.45 schwarze 1645: return(1);
1.73 schwarze 1646: } else if (MDOC_HEAD == n->type)
1647: return(0);
1.1 kristaps 1648:
1.95 schwarze 1649: assert(n->data.Bd);
1650: if (n->data.Bd->offs)
1651: p->offset += a2offs(p, n->data.Bd->offs);
1.60 schwarze 1652:
1653: /*
1654: * If -ragged or -filled are specified, the block does nothing
1655: * but change the indentation. If -unfilled or -literal are
1656: * specified, text is printed exactly as entered in the display:
1657: * for macro lines, a newline is appended to the line. Blank
1658: * lines are allowed.
1659: */
1.48 schwarze 1660:
1.95 schwarze 1661: if (DISP_literal != n->data.Bd->type &&
1662: DISP_unfilled != n->data.Bd->type)
1.1 kristaps 1663: return(1);
1664:
1.75 schwarze 1665: tabwidth = p->tabwidth;
1.89 schwarze 1666: p->tabwidth = term_len(p, 8);
1.77 schwarze 1667: rm = p->rmargin;
1668: rmax = p->maxrmargin;
1669: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1670:
1.60 schwarze 1671: for (nn = n->child; nn; nn = nn->next) {
1.100 schwarze 1672: print_mdoc_node(p, pair, m, nn);
1673: if (nn->next && nn->next->line == nn->line)
1674: continue;
1675: term_flushln(p);
1.48 schwarze 1676: p->flags |= TERMP_NOSPACE;
1.1 kristaps 1677: }
1.88 schwarze 1678:
1.75 schwarze 1679: p->tabwidth = tabwidth;
1.77 schwarze 1680: p->rmargin = rm;
1681: p->maxrmargin = rmax;
1.1 kristaps 1682: return(0);
1683: }
1684:
1685:
1686: /* ARGSUSED */
1687: static void
1688: termp_bd_post(DECL_ARGS)
1689: {
1.77 schwarze 1690: size_t rm, rmax;
1.1 kristaps 1691:
1.60 schwarze 1692: if (MDOC_BODY != n->type)
1.1 kristaps 1693: return;
1.77 schwarze 1694:
1695: rm = p->rmargin;
1696: rmax = p->maxrmargin;
1697:
1.95 schwarze 1698: assert(n->data.Bd);
1699: if (DISP_literal == n->data.Bd->type ||
1700: DISP_unfilled == n->data.Bd->type)
1.77 schwarze 1701: p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
1702:
1.48 schwarze 1703: p->flags |= TERMP_NOSPACE;
1.75 schwarze 1704: term_newln(p);
1.77 schwarze 1705:
1706: p->rmargin = rm;
1707: p->maxrmargin = rmax;
1.1 kristaps 1708: }
1709:
1710:
1711: /* ARGSUSED */
1712: static int
1713: termp_qq_pre(DECL_ARGS)
1714: {
1715:
1.60 schwarze 1716: if (MDOC_BODY != n->type)
1.1 kristaps 1717: return(1);
1718: term_word(p, "\"");
1719: p->flags |= TERMP_NOSPACE;
1720: return(1);
1721: }
1722:
1723:
1724: /* ARGSUSED */
1725: static void
1726: termp_qq_post(DECL_ARGS)
1727: {
1728:
1.60 schwarze 1729: if (MDOC_BODY != n->type)
1.1 kristaps 1730: return;
1731: p->flags |= TERMP_NOSPACE;
1732: term_word(p, "\"");
1733: }
1734:
1735:
1736: /* ARGSUSED */
1737: static void
1738: termp_bx_post(DECL_ARGS)
1739: {
1740:
1.60 schwarze 1741: if (n->child)
1.1 kristaps 1742: p->flags |= TERMP_NOSPACE;
1743: term_word(p, "BSD");
1744: }
1745:
1746:
1747: /* ARGSUSED */
1748: static int
1.26 schwarze 1749: termp_xx_pre(DECL_ARGS)
1.1 kristaps 1750: {
1.26 schwarze 1751: const char *pp;
1.1 kristaps 1752:
1.26 schwarze 1753: pp = NULL;
1.60 schwarze 1754: switch (n->tok) {
1.26 schwarze 1755: case (MDOC_Bsx):
1756: pp = "BSDI BSD/OS";
1757: break;
1758: case (MDOC_Dx):
1.64 schwarze 1759: pp = "DragonFly";
1.26 schwarze 1760: break;
1761: case (MDOC_Fx):
1762: pp = "FreeBSD";
1763: break;
1764: case (MDOC_Nx):
1765: pp = "NetBSD";
1766: break;
1767: case (MDOC_Ox):
1768: pp = "OpenBSD";
1769: break;
1770: case (MDOC_Ux):
1771: pp = "UNIX";
1772: break;
1773: default:
1774: break;
1775: }
1.1 kristaps 1776:
1.26 schwarze 1777: assert(pp);
1778: term_word(p, pp);
1.1 kristaps 1779: return(1);
1780: }
1781:
1782:
1783: /* ARGSUSED */
1784: static int
1785: termp_sq_pre(DECL_ARGS)
1786: {
1787:
1.60 schwarze 1788: if (MDOC_BODY != n->type)
1.1 kristaps 1789: return(1);
1790: term_word(p, "\\(oq");
1791: p->flags |= TERMP_NOSPACE;
1792: return(1);
1793: }
1794:
1795:
1796: /* ARGSUSED */
1797: static void
1798: termp_sq_post(DECL_ARGS)
1799: {
1800:
1.60 schwarze 1801: if (MDOC_BODY != n->type)
1.1 kristaps 1802: return;
1803: p->flags |= TERMP_NOSPACE;
1804: term_word(p, "\\(aq");
1805: }
1806:
1807:
1808: /* ARGSUSED */
1809: static int
1810: termp_pf_pre(DECL_ARGS)
1811: {
1812:
1813: p->flags |= TERMP_IGNDELIM;
1814: return(1);
1815: }
1816:
1817:
1818: /* ARGSUSED */
1819: static void
1820: termp_pf_post(DECL_ARGS)
1821: {
1822:
1823: p->flags &= ~TERMP_IGNDELIM;
1824: p->flags |= TERMP_NOSPACE;
1825: }
1826:
1827:
1828: /* ARGSUSED */
1829: static int
1830: termp_ss_pre(DECL_ARGS)
1831: {
1832:
1.60 schwarze 1833: switch (n->type) {
1.1 kristaps 1834: case (MDOC_BLOCK):
1835: term_newln(p);
1.60 schwarze 1836: if (n->prev)
1.1 kristaps 1837: term_vspace(p);
1838: break;
1839: case (MDOC_HEAD):
1.65 schwarze 1840: term_fontpush(p, TERMFONT_BOLD);
1.89 schwarze 1841: p->offset = term_len(p, HALFINDENT);
1.1 kristaps 1842: break;
1843: default:
1844: break;
1845: }
1846:
1847: return(1);
1848: }
1849:
1850:
1851: /* ARGSUSED */
1852: static void
1853: termp_ss_post(DECL_ARGS)
1854: {
1855:
1.60 schwarze 1856: if (MDOC_HEAD == n->type)
1.1 kristaps 1857: term_newln(p);
1858: }
1859:
1860:
1861: /* ARGSUSED */
1862: static int
1863: termp_cd_pre(DECL_ARGS)
1864: {
1865:
1.86 schwarze 1866: synopsis_pre(p, n);
1.65 schwarze 1867: term_fontpush(p, TERMFONT_BOLD);
1.1 kristaps 1868: return(1);
1869: }
1870:
1871:
1872: /* ARGSUSED */
1873: static int
1874: termp_in_pre(DECL_ARGS)
1875: {
1876:
1.86 schwarze 1877: synopsis_pre(p, n);
1.85 schwarze 1878:
1.92 schwarze 1879: if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) {
1.85 schwarze 1880: term_fontpush(p, TERMFONT_BOLD);
1.23 schwarze 1881: term_word(p, "#include");
1.85 schwarze 1882: term_word(p, "<");
1883: } else {
1884: term_word(p, "<");
1885: term_fontpush(p, TERMFONT_UNDER);
1886: }
1.23 schwarze 1887:
1.1 kristaps 1888: p->flags |= TERMP_NOSPACE;
1889: return(1);
1890: }
1891:
1892:
1893: /* ARGSUSED */
1894: static void
1895: termp_in_post(DECL_ARGS)
1896: {
1897:
1.92 schwarze 1898: if (MDOC_SYNPRETTY & n->flags)
1.85 schwarze 1899: term_fontpush(p, TERMFONT_BOLD);
1900:
1.59 schwarze 1901: p->flags |= TERMP_NOSPACE;
1.1 kristaps 1902: term_word(p, ">");
1903:
1.92 schwarze 1904: if (MDOC_SYNPRETTY & n->flags)
1.85 schwarze 1905: term_fontpop(p);
1.38 schwarze 1906: }
1907:
1908:
1909: /* ARGSUSED */
1910: static int
1911: termp_sp_pre(DECL_ARGS)
1912: {
1.61 schwarze 1913: size_t i, len;
1.38 schwarze 1914:
1.60 schwarze 1915: switch (n->tok) {
1.54 schwarze 1916: case (MDOC_sp):
1.89 schwarze 1917: len = n->child ? a2height(p, n->child->string) : 1;
1.54 schwarze 1918: break;
1919: case (MDOC_br):
1920: len = 0;
1921: break;
1922: default:
1.98 schwarze 1923: assert(n->parent);
1924: if ((NULL == n->next || NULL == n->prev) &&
1925: (MDOC_Ss == n->parent->tok ||
1926: MDOC_Sh == n->parent->tok))
1927: return(0);
1.54 schwarze 1928: len = 1;
1929: break;
1.38 schwarze 1930: }
1931:
1932: if (0 == len)
1933: term_newln(p);
1934: for (i = 0; i < len; i++)
1935: term_vspace(p);
1936:
1937: return(0);
1938: }
1939:
1940:
1941: /* ARGSUSED */
1942: static int
1.1 kristaps 1943: termp_brq_pre(DECL_ARGS)
1944: {
1945:
1.60 schwarze 1946: if (MDOC_BODY != n->type)
1.1 kristaps 1947: return(1);
1948: term_word(p, "\\(lC");
1949: p->flags |= TERMP_NOSPACE;
1950: return(1);
1951: }
1952:
1953:
1954: /* ARGSUSED */
1955: static void
1956: termp_brq_post(DECL_ARGS)
1957: {
1958:
1.60 schwarze 1959: if (MDOC_BODY != n->type)
1.1 kristaps 1960: return;
1961: p->flags |= TERMP_NOSPACE;
1962: term_word(p, "\\(rC");
1963: }
1964:
1965:
1966: /* ARGSUSED */
1967: static int
1968: termp_bq_pre(DECL_ARGS)
1969: {
1970:
1.60 schwarze 1971: if (MDOC_BODY != n->type)
1.1 kristaps 1972: return(1);
1973: term_word(p, "\\(lB");
1974: p->flags |= TERMP_NOSPACE;
1975: return(1);
1976: }
1977:
1978:
1979: /* ARGSUSED */
1980: static void
1981: termp_bq_post(DECL_ARGS)
1982: {
1983:
1.60 schwarze 1984: if (MDOC_BODY != n->type)
1.1 kristaps 1985: return;
1986: p->flags |= TERMP_NOSPACE;
1987: term_word(p, "\\(rB");
1988: }
1989:
1990:
1991: /* ARGSUSED */
1992: static int
1993: termp_pq_pre(DECL_ARGS)
1994: {
1995:
1.60 schwarze 1996: if (MDOC_BODY != n->type)
1.1 kristaps 1997: return(1);
1998: term_word(p, "\\&(");
1999: p->flags |= TERMP_NOSPACE;
2000: return(1);
2001: }
2002:
2003:
2004: /* ARGSUSED */
2005: static void
2006: termp_pq_post(DECL_ARGS)
2007: {
2008:
1.60 schwarze 2009: if (MDOC_BODY != n->type)
1.1 kristaps 2010: return;
2011: term_word(p, ")");
2012: }
2013:
2014:
2015: /* ARGSUSED */
2016: static int
2017: termp_fo_pre(DECL_ARGS)
2018: {
2019:
1.85 schwarze 2020: if (MDOC_BLOCK == n->type) {
1.86 schwarze 2021: synopsis_pre(p, n);
1.85 schwarze 2022: return(1);
2023: } else if (MDOC_BODY == n->type) {
1.31 schwarze 2024: p->flags |= TERMP_NOSPACE;
1.1 kristaps 2025: term_word(p, "(");
2026: p->flags |= TERMP_NOSPACE;
2027: return(1);
1.85 schwarze 2028: }
2029:
1.95 schwarze 2030: if (NULL == n->child)
2031: return(0);
2032:
1.85 schwarze 2033: /* XXX: we drop non-initial arguments as per groff. */
1.1 kristaps 2034:
1.85 schwarze 2035: assert(n->child->string);
1.65 schwarze 2036: term_fontpush(p, TERMFONT_BOLD);
1.85 schwarze 2037: term_word(p, n->child->string);
1.1 kristaps 2038: return(0);
2039: }
2040:
2041:
2042: /* ARGSUSED */
2043: static void
2044: termp_fo_post(DECL_ARGS)
2045: {
2046:
1.86 schwarze 2047: if (MDOC_BODY != n->type)
2048: return;
2049:
2050: p->flags |= TERMP_NOSPACE;
2051: term_word(p, ")");
2052:
1.92 schwarze 2053: if (MDOC_SYNPRETTY & n->flags) {
1.85 schwarze 2054: p->flags |= TERMP_NOSPACE;
1.86 schwarze 2055: term_word(p, ";");
1.85 schwarze 2056: }
1.1 kristaps 2057: }
2058:
2059:
2060: /* ARGSUSED */
2061: static int
2062: termp_bf_pre(DECL_ARGS)
2063: {
2064:
1.60 schwarze 2065: if (MDOC_HEAD == n->type)
1.1 kristaps 2066: return(0);
1.60 schwarze 2067: else if (MDOC_BLOCK != n->type)
1.1 kristaps 2068: return(1);
2069:
1.95 schwarze 2070: assert(n->data.Bf);
1.1 kristaps 2071:
1.95 schwarze 2072: if (FONT_Em == n->data.Bf->font)
1.65 schwarze 2073: term_fontpush(p, TERMFONT_UNDER);
1.95 schwarze 2074: else if (FONT_Sy == n->data.Bf->font)
1.65 schwarze 2075: term_fontpush(p, TERMFONT_BOLD);
1.95 schwarze 2076: else
1.65 schwarze 2077: term_fontpush(p, TERMFONT_NONE);
1.1 kristaps 2078:
2079: return(1);
2080: }
2081:
2082:
2083: /* ARGSUSED */
2084: static int
2085: termp_sm_pre(DECL_ARGS)
2086: {
2087:
1.60 schwarze 2088: assert(n->child && MDOC_TEXT == n->child->type);
1.96 schwarze 2089: if (0 == strcmp("on", n->child->string)) {
2090: if (p->col)
2091: p->flags &= ~TERMP_NOSPACE;
1.1 kristaps 2092: p->flags &= ~TERMP_NONOSPACE;
1.96 schwarze 2093: } else
1.1 kristaps 2094: p->flags |= TERMP_NONOSPACE;
2095:
2096: return(0);
2097: }
2098:
2099:
2100: /* ARGSUSED */
2101: static int
2102: termp_ap_pre(DECL_ARGS)
2103: {
2104:
2105: p->flags |= TERMP_NOSPACE;
2106: term_word(p, "\\(aq");
2107: p->flags |= TERMP_NOSPACE;
2108: return(1);
2109: }
2110:
2111:
2112: /* ARGSUSED */
2113: static void
2114: termp____post(DECL_ARGS)
2115: {
1.104 schwarze 2116:
2117: /*
2118: * Handle lists of authors. In general, print each followed by
2119: * a comma. Don't print the comma if there are only two
2120: * authors.
2121: */
2122: if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
2123: if (NULL == n->next->next || MDOC__A != n->next->next->tok)
2124: if (NULL == n->prev || MDOC__A != n->prev->tok)
2125: return;
1.1 kristaps 2126:
1.62 schwarze 2127: /* TODO: %U. */
2128:
1.106 ! schwarze 2129: if (NULL == n->parent || MDOC_Rs != n->parent->tok)
! 2130: return;
! 2131:
! 2132: if (NULL == n->next) {
! 2133: term_word(p, ".");
! 2134: p->flags |= TERMP_SENTENCE;
! 2135: } else
! 2136: term_word(p, ",");
1.1 kristaps 2137: }
2138:
2139:
2140: /* ARGSUSED */
2141: static int
1.65 schwarze 2142: termp_li_pre(DECL_ARGS)
2143: {
2144:
2145: term_fontpush(p, TERMFONT_NONE);
2146: return(1);
2147: }
2148:
2149:
2150: /* ARGSUSED */
2151: static int
1.1 kristaps 2152: termp_lk_pre(DECL_ARGS)
2153: {
1.101 schwarze 2154: const struct mdoc_node *nn, *sv;
1.1 kristaps 2155:
1.65 schwarze 2156: term_fontpush(p, TERMFONT_UNDER);
1.101 schwarze 2157:
2158: nn = sv = n->child;
1.62 schwarze 2159:
2160: if (NULL == nn->next)
1.6 schwarze 2161: return(1);
1.1 kristaps 2162:
1.101 schwarze 2163: for (nn = nn->next; nn; nn = nn->next)
2164: term_word(p, nn->string);
2165:
1.65 schwarze 2166: term_fontpop(p);
1.62 schwarze 2167:
1.1 kristaps 2168: p->flags |= TERMP_NOSPACE;
2169: term_word(p, ":");
2170:
1.65 schwarze 2171: term_fontpush(p, TERMFONT_BOLD);
1.101 schwarze 2172: term_word(p, sv->string);
1.65 schwarze 2173: term_fontpop(p);
1.6 schwarze 2174:
1.1 kristaps 2175: return(0);
2176: }
2177:
1.90 schwarze 2178:
2179: /* ARGSUSED */
2180: static int
2181: termp_bk_pre(DECL_ARGS)
2182: {
2183:
1.91 schwarze 2184: switch (n->type) {
2185: case (MDOC_BLOCK):
1.95 schwarze 2186: break;
1.91 schwarze 2187: case (MDOC_HEAD):
2188: return(0);
2189: case (MDOC_BODY):
2190: p->flags |= TERMP_PREKEEP;
1.95 schwarze 2191: break;
1.91 schwarze 2192: default:
2193: abort();
1.95 schwarze 2194: /* NOTREACHED */
1.91 schwarze 2195: }
1.95 schwarze 2196:
2197: return(1);
1.90 schwarze 2198: }
2199:
2200:
2201: /* ARGSUSED */
2202: static void
2203: termp_bk_post(DECL_ARGS)
2204: {
2205:
1.91 schwarze 2206: if (MDOC_BODY == n->type)
2207: p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
1.90 schwarze 2208: }
1.1 kristaps 2209:
2210: /* ARGSUSED */
2211: static int
1.54 schwarze 2212: termp_under_pre(DECL_ARGS)
1.1 kristaps 2213: {
2214:
1.65 schwarze 2215: term_fontpush(p, TERMFONT_UNDER);
1.1 kristaps 2216: return(1);
2217: }