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