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