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