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