1241675Suqs/* $Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4241675Suqs * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> 5241675Suqs * 6241675Suqs * Permission to use, copy, modify, and distribute this software for any 7241675Suqs * purpose with or without fee is hereby granted, provided that the above 8241675Suqs * copyright notice and this permission notice appear in all copies. 9241675Suqs * 10241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17241675Suqs */ 18241675Suqs#ifdef HAVE_CONFIG_H 19241675Suqs#include "config.h" 20241675Suqs#endif 21241675Suqs 22241675Suqs#include <sys/types.h> 23241675Suqs 24241675Suqs#include <assert.h> 25241675Suqs#include <ctype.h> 26241675Suqs#include <stdint.h> 27241675Suqs#include <stdio.h> 28241675Suqs#include <stdlib.h> 29241675Suqs#include <string.h> 30241675Suqs 31241675Suqs#include "mandoc.h" 32241675Suqs#include "out.h" 33241675Suqs#include "term.h" 34241675Suqs#include "mdoc.h" 35241675Suqs#include "main.h" 36241675Suqs 37241675Suqsstruct termpair { 38241675Suqs struct termpair *ppair; 39241675Suqs int count; 40241675Suqs}; 41241675Suqs 42241675Suqs#define DECL_ARGS struct termp *p, \ 43241675Suqs struct termpair *pair, \ 44241675Suqs const struct mdoc_meta *m, \ 45241675Suqs const struct mdoc_node *n 46241675Suqs 47241675Suqsstruct termact { 48241675Suqs int (*pre)(DECL_ARGS); 49241675Suqs void (*post)(DECL_ARGS); 50241675Suqs}; 51241675Suqs 52241675Suqsstatic size_t a2width(const struct termp *, const char *); 53241675Suqsstatic size_t a2height(const struct termp *, const char *); 54241675Suqsstatic size_t a2offs(const struct termp *, const char *); 55241675Suqs 56241675Suqsstatic void print_bvspace(struct termp *, 57241675Suqs const struct mdoc_node *, 58241675Suqs const struct mdoc_node *); 59241675Suqsstatic void print_mdoc_node(DECL_ARGS); 60241675Suqsstatic void print_mdoc_nodelist(DECL_ARGS); 61241675Suqsstatic void print_mdoc_head(struct termp *, const void *); 62241675Suqsstatic void print_mdoc_foot(struct termp *, const void *); 63241675Suqsstatic void synopsis_pre(struct termp *, 64241675Suqs const struct mdoc_node *); 65241675Suqs 66241675Suqsstatic void termp____post(DECL_ARGS); 67241675Suqsstatic void termp__t_post(DECL_ARGS); 68241675Suqsstatic void termp_an_post(DECL_ARGS); 69241675Suqsstatic void termp_bd_post(DECL_ARGS); 70241675Suqsstatic void termp_bk_post(DECL_ARGS); 71241675Suqsstatic void termp_bl_post(DECL_ARGS); 72241675Suqsstatic void termp_d1_post(DECL_ARGS); 73241675Suqsstatic void termp_fo_post(DECL_ARGS); 74241675Suqsstatic void termp_in_post(DECL_ARGS); 75241675Suqsstatic void termp_it_post(DECL_ARGS); 76241675Suqsstatic void termp_lb_post(DECL_ARGS); 77241675Suqsstatic void termp_nm_post(DECL_ARGS); 78241675Suqsstatic void termp_pf_post(DECL_ARGS); 79241675Suqsstatic void termp_quote_post(DECL_ARGS); 80241675Suqsstatic void termp_sh_post(DECL_ARGS); 81241675Suqsstatic void termp_ss_post(DECL_ARGS); 82241675Suqs 83241675Suqsstatic int termp__a_pre(DECL_ARGS); 84241675Suqsstatic int termp__t_pre(DECL_ARGS); 85241675Suqsstatic int termp_an_pre(DECL_ARGS); 86241675Suqsstatic int termp_ap_pre(DECL_ARGS); 87241675Suqsstatic int termp_bd_pre(DECL_ARGS); 88241675Suqsstatic int termp_bf_pre(DECL_ARGS); 89241675Suqsstatic int termp_bk_pre(DECL_ARGS); 90241675Suqsstatic int termp_bl_pre(DECL_ARGS); 91241675Suqsstatic int termp_bold_pre(DECL_ARGS); 92241675Suqsstatic int termp_bt_pre(DECL_ARGS); 93241675Suqsstatic int termp_bx_pre(DECL_ARGS); 94241675Suqsstatic int termp_cd_pre(DECL_ARGS); 95241675Suqsstatic int termp_d1_pre(DECL_ARGS); 96241675Suqsstatic int termp_ex_pre(DECL_ARGS); 97241675Suqsstatic int termp_fa_pre(DECL_ARGS); 98241675Suqsstatic int termp_fd_pre(DECL_ARGS); 99241675Suqsstatic int termp_fl_pre(DECL_ARGS); 100241675Suqsstatic int termp_fn_pre(DECL_ARGS); 101241675Suqsstatic int termp_fo_pre(DECL_ARGS); 102241675Suqsstatic int termp_ft_pre(DECL_ARGS); 103241675Suqsstatic int termp_igndelim_pre(DECL_ARGS); 104241675Suqsstatic int termp_in_pre(DECL_ARGS); 105241675Suqsstatic int termp_it_pre(DECL_ARGS); 106241675Suqsstatic int termp_li_pre(DECL_ARGS); 107241675Suqsstatic int termp_lk_pre(DECL_ARGS); 108241675Suqsstatic int termp_nd_pre(DECL_ARGS); 109241675Suqsstatic int termp_nm_pre(DECL_ARGS); 110241675Suqsstatic int termp_ns_pre(DECL_ARGS); 111241675Suqsstatic int termp_quote_pre(DECL_ARGS); 112241675Suqsstatic int termp_rs_pre(DECL_ARGS); 113241675Suqsstatic int termp_rv_pre(DECL_ARGS); 114241675Suqsstatic int termp_sh_pre(DECL_ARGS); 115241675Suqsstatic int termp_sm_pre(DECL_ARGS); 116241675Suqsstatic int termp_sp_pre(DECL_ARGS); 117241675Suqsstatic int termp_ss_pre(DECL_ARGS); 118241675Suqsstatic int termp_under_pre(DECL_ARGS); 119241675Suqsstatic int termp_ud_pre(DECL_ARGS); 120241675Suqsstatic int termp_vt_pre(DECL_ARGS); 121241675Suqsstatic int termp_xr_pre(DECL_ARGS); 122241675Suqsstatic int termp_xx_pre(DECL_ARGS); 123241675Suqs 124241675Suqsstatic const struct termact termacts[MDOC_MAX] = { 125241675Suqs { termp_ap_pre, NULL }, /* Ap */ 126241675Suqs { NULL, NULL }, /* Dd */ 127241675Suqs { NULL, NULL }, /* Dt */ 128241675Suqs { NULL, NULL }, /* Os */ 129241675Suqs { termp_sh_pre, termp_sh_post }, /* Sh */ 130241675Suqs { termp_ss_pre, termp_ss_post }, /* Ss */ 131241675Suqs { termp_sp_pre, NULL }, /* Pp */ 132241675Suqs { termp_d1_pre, termp_d1_post }, /* D1 */ 133241675Suqs { termp_d1_pre, termp_d1_post }, /* Dl */ 134241675Suqs { termp_bd_pre, termp_bd_post }, /* Bd */ 135241675Suqs { NULL, NULL }, /* Ed */ 136241675Suqs { termp_bl_pre, termp_bl_post }, /* Bl */ 137241675Suqs { NULL, NULL }, /* El */ 138241675Suqs { termp_it_pre, termp_it_post }, /* It */ 139241675Suqs { termp_under_pre, NULL }, /* Ad */ 140241675Suqs { termp_an_pre, termp_an_post }, /* An */ 141241675Suqs { termp_under_pre, NULL }, /* Ar */ 142241675Suqs { termp_cd_pre, NULL }, /* Cd */ 143241675Suqs { termp_bold_pre, NULL }, /* Cm */ 144241675Suqs { NULL, NULL }, /* Dv */ 145241675Suqs { NULL, NULL }, /* Er */ 146241675Suqs { NULL, NULL }, /* Ev */ 147241675Suqs { termp_ex_pre, NULL }, /* Ex */ 148241675Suqs { termp_fa_pre, NULL }, /* Fa */ 149241675Suqs { termp_fd_pre, NULL }, /* Fd */ 150241675Suqs { termp_fl_pre, NULL }, /* Fl */ 151241675Suqs { termp_fn_pre, NULL }, /* Fn */ 152241675Suqs { termp_ft_pre, NULL }, /* Ft */ 153241675Suqs { termp_bold_pre, NULL }, /* Ic */ 154241675Suqs { termp_in_pre, termp_in_post }, /* In */ 155241675Suqs { termp_li_pre, NULL }, /* Li */ 156241675Suqs { termp_nd_pre, NULL }, /* Nd */ 157241675Suqs { termp_nm_pre, termp_nm_post }, /* Nm */ 158241675Suqs { termp_quote_pre, termp_quote_post }, /* Op */ 159241675Suqs { NULL, NULL }, /* Ot */ 160241675Suqs { termp_under_pre, NULL }, /* Pa */ 161241675Suqs { termp_rv_pre, NULL }, /* Rv */ 162241675Suqs { NULL, NULL }, /* St */ 163241675Suqs { termp_under_pre, NULL }, /* Va */ 164241675Suqs { termp_vt_pre, NULL }, /* Vt */ 165241675Suqs { termp_xr_pre, NULL }, /* Xr */ 166241675Suqs { termp__a_pre, termp____post }, /* %A */ 167241675Suqs { termp_under_pre, termp____post }, /* %B */ 168241675Suqs { NULL, termp____post }, /* %D */ 169241675Suqs { termp_under_pre, termp____post }, /* %I */ 170241675Suqs { termp_under_pre, termp____post }, /* %J */ 171241675Suqs { NULL, termp____post }, /* %N */ 172241675Suqs { NULL, termp____post }, /* %O */ 173241675Suqs { NULL, termp____post }, /* %P */ 174241675Suqs { NULL, termp____post }, /* %R */ 175241675Suqs { termp__t_pre, termp__t_post }, /* %T */ 176241675Suqs { NULL, termp____post }, /* %V */ 177241675Suqs { NULL, NULL }, /* Ac */ 178241675Suqs { termp_quote_pre, termp_quote_post }, /* Ao */ 179241675Suqs { termp_quote_pre, termp_quote_post }, /* Aq */ 180241675Suqs { NULL, NULL }, /* At */ 181241675Suqs { NULL, NULL }, /* Bc */ 182241675Suqs { termp_bf_pre, NULL }, /* Bf */ 183241675Suqs { termp_quote_pre, termp_quote_post }, /* Bo */ 184241675Suqs { termp_quote_pre, termp_quote_post }, /* Bq */ 185241675Suqs { termp_xx_pre, NULL }, /* Bsx */ 186241675Suqs { termp_bx_pre, NULL }, /* Bx */ 187241675Suqs { NULL, NULL }, /* Db */ 188241675Suqs { NULL, NULL }, /* Dc */ 189241675Suqs { termp_quote_pre, termp_quote_post }, /* Do */ 190241675Suqs { termp_quote_pre, termp_quote_post }, /* Dq */ 191241675Suqs { NULL, NULL }, /* Ec */ /* FIXME: no space */ 192241675Suqs { NULL, NULL }, /* Ef */ 193241675Suqs { termp_under_pre, NULL }, /* Em */ 194241675Suqs { termp_quote_pre, termp_quote_post }, /* Eo */ 195241675Suqs { termp_xx_pre, NULL }, /* Fx */ 196241675Suqs { termp_bold_pre, NULL }, /* Ms */ 197241675Suqs { termp_igndelim_pre, NULL }, /* No */ 198241675Suqs { termp_ns_pre, NULL }, /* Ns */ 199241675Suqs { termp_xx_pre, NULL }, /* Nx */ 200241675Suqs { termp_xx_pre, NULL }, /* Ox */ 201241675Suqs { NULL, NULL }, /* Pc */ 202241675Suqs { termp_igndelim_pre, termp_pf_post }, /* Pf */ 203241675Suqs { termp_quote_pre, termp_quote_post }, /* Po */ 204241675Suqs { termp_quote_pre, termp_quote_post }, /* Pq */ 205241675Suqs { NULL, NULL }, /* Qc */ 206241675Suqs { termp_quote_pre, termp_quote_post }, /* Ql */ 207241675Suqs { termp_quote_pre, termp_quote_post }, /* Qo */ 208241675Suqs { termp_quote_pre, termp_quote_post }, /* Qq */ 209241675Suqs { NULL, NULL }, /* Re */ 210241675Suqs { termp_rs_pre, NULL }, /* Rs */ 211241675Suqs { NULL, NULL }, /* Sc */ 212241675Suqs { termp_quote_pre, termp_quote_post }, /* So */ 213241675Suqs { termp_quote_pre, termp_quote_post }, /* Sq */ 214241675Suqs { termp_sm_pre, NULL }, /* Sm */ 215241675Suqs { termp_under_pre, NULL }, /* Sx */ 216241675Suqs { termp_bold_pre, NULL }, /* Sy */ 217241675Suqs { NULL, NULL }, /* Tn */ 218241675Suqs { termp_xx_pre, NULL }, /* Ux */ 219241675Suqs { NULL, NULL }, /* Xc */ 220241675Suqs { NULL, NULL }, /* Xo */ 221241675Suqs { termp_fo_pre, termp_fo_post }, /* Fo */ 222241675Suqs { NULL, NULL }, /* Fc */ 223241675Suqs { termp_quote_pre, termp_quote_post }, /* Oo */ 224241675Suqs { NULL, NULL }, /* Oc */ 225241675Suqs { termp_bk_pre, termp_bk_post }, /* Bk */ 226241675Suqs { NULL, NULL }, /* Ek */ 227241675Suqs { termp_bt_pre, NULL }, /* Bt */ 228241675Suqs { NULL, NULL }, /* Hf */ 229241675Suqs { NULL, NULL }, /* Fr */ 230241675Suqs { termp_ud_pre, NULL }, /* Ud */ 231241675Suqs { NULL, termp_lb_post }, /* Lb */ 232241675Suqs { termp_sp_pre, NULL }, /* Lp */ 233241675Suqs { termp_lk_pre, NULL }, /* Lk */ 234241675Suqs { termp_under_pre, NULL }, /* Mt */ 235241675Suqs { termp_quote_pre, termp_quote_post }, /* Brq */ 236241675Suqs { termp_quote_pre, termp_quote_post }, /* Bro */ 237241675Suqs { NULL, NULL }, /* Brc */ 238241675Suqs { NULL, termp____post }, /* %C */ 239241675Suqs { NULL, NULL }, /* Es */ /* TODO */ 240241675Suqs { NULL, NULL }, /* En */ /* TODO */ 241241675Suqs { termp_xx_pre, NULL }, /* Dx */ 242241675Suqs { NULL, termp____post }, /* %Q */ 243241675Suqs { termp_sp_pre, NULL }, /* br */ 244241675Suqs { termp_sp_pre, NULL }, /* sp */ 245241675Suqs { termp_under_pre, termp____post }, /* %U */ 246241675Suqs { NULL, NULL }, /* Ta */ 247241675Suqs}; 248241675Suqs 249241675Suqs 250241675Suqsvoid 251241675Suqsterminal_mdoc(void *arg, const struct mdoc *mdoc) 252241675Suqs{ 253241675Suqs const struct mdoc_node *n; 254241675Suqs const struct mdoc_meta *m; 255241675Suqs struct termp *p; 256241675Suqs 257241675Suqs p = (struct termp *)arg; 258241675Suqs 259241675Suqs if (0 == p->defindent) 260241675Suqs p->defindent = 5; 261241675Suqs 262241675Suqs p->overstep = 0; 263241675Suqs p->maxrmargin = p->defrmargin; 264241675Suqs p->tabwidth = term_len(p, 5); 265241675Suqs 266241675Suqs if (NULL == p->symtab) 267241675Suqs p->symtab = mchars_alloc(); 268241675Suqs 269241675Suqs n = mdoc_node(mdoc); 270241675Suqs m = mdoc_meta(mdoc); 271241675Suqs 272241675Suqs term_begin(p, print_mdoc_head, print_mdoc_foot, m); 273241675Suqs 274241675Suqs if (n->child) 275241675Suqs print_mdoc_nodelist(p, NULL, m, n->child); 276241675Suqs 277241675Suqs term_end(p); 278241675Suqs} 279241675Suqs 280241675Suqs 281241675Suqsstatic void 282241675Suqsprint_mdoc_nodelist(DECL_ARGS) 283241675Suqs{ 284241675Suqs 285241675Suqs print_mdoc_node(p, pair, m, n); 286241675Suqs if (n->next) 287241675Suqs print_mdoc_nodelist(p, pair, m, n->next); 288241675Suqs} 289241675Suqs 290241675Suqs 291241675Suqs/* ARGSUSED */ 292241675Suqsstatic void 293241675Suqsprint_mdoc_node(DECL_ARGS) 294241675Suqs{ 295241675Suqs int chld; 296241675Suqs const void *font; 297241675Suqs struct termpair npair; 298241675Suqs size_t offset, rmargin; 299241675Suqs 300241675Suqs chld = 1; 301241675Suqs offset = p->offset; 302241675Suqs rmargin = p->rmargin; 303241675Suqs font = term_fontq(p); 304241675Suqs 305241675Suqs memset(&npair, 0, sizeof(struct termpair)); 306241675Suqs npair.ppair = pair; 307241675Suqs 308241675Suqs /* 309241675Suqs * Keeps only work until the end of a line. If a keep was 310241675Suqs * invoked in a prior line, revert it to PREKEEP. 311241675Suqs * 312241675Suqs * Also let SYNPRETTY sections behave as if they were wrapped 313241675Suqs * in a `Bk' block. 314241675Suqs */ 315241675Suqs 316241675Suqs if (TERMP_KEEP & p->flags || MDOC_SYNPRETTY & n->flags) { 317241675Suqs if (n->prev && n->prev->line != n->line) { 318241675Suqs p->flags &= ~TERMP_KEEP; 319241675Suqs p->flags |= TERMP_PREKEEP; 320241675Suqs } else if (NULL == n->prev) { 321241675Suqs if (n->parent && n->parent->line != n->line) { 322241675Suqs p->flags &= ~TERMP_KEEP; 323241675Suqs p->flags |= TERMP_PREKEEP; 324241675Suqs } 325241675Suqs } 326241675Suqs } 327241675Suqs 328241675Suqs /* 329241675Suqs * Since SYNPRETTY sections aren't "turned off" with `Ek', 330241675Suqs * we have to intuit whether we should disable formatting. 331241675Suqs */ 332241675Suqs 333241675Suqs if ( ! (MDOC_SYNPRETTY & n->flags) && 334241675Suqs ((n->prev && MDOC_SYNPRETTY & n->prev->flags) || 335241675Suqs (n->parent && MDOC_SYNPRETTY & n->parent->flags))) 336241675Suqs p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); 337241675Suqs 338241675Suqs /* 339241675Suqs * After the keep flags have been set up, we may now 340241675Suqs * produce output. Note that some pre-handlers do so. 341241675Suqs */ 342241675Suqs 343241675Suqs switch (n->type) { 344241675Suqs case (MDOC_TEXT): 345241675Suqs if (' ' == *n->string && MDOC_LINE & n->flags) 346241675Suqs term_newln(p); 347241675Suqs if (MDOC_DELIMC & n->flags) 348241675Suqs p->flags |= TERMP_NOSPACE; 349241675Suqs term_word(p, n->string); 350241675Suqs if (MDOC_DELIMO & n->flags) 351241675Suqs p->flags |= TERMP_NOSPACE; 352241675Suqs break; 353241675Suqs case (MDOC_EQN): 354241675Suqs term_eqn(p, n->eqn); 355241675Suqs break; 356241675Suqs case (MDOC_TBL): 357241675Suqs term_tbl(p, n->span); 358241675Suqs break; 359241675Suqs default: 360241675Suqs if (termacts[n->tok].pre && ENDBODY_NOT == n->end) 361241675Suqs chld = (*termacts[n->tok].pre) 362241675Suqs (p, &npair, m, n); 363241675Suqs break; 364241675Suqs } 365241675Suqs 366241675Suqs if (chld && n->child) 367241675Suqs print_mdoc_nodelist(p, &npair, m, n->child); 368241675Suqs 369241675Suqs term_fontpopq(p, font); 370241675Suqs 371241675Suqs switch (n->type) { 372241675Suqs case (MDOC_TEXT): 373241675Suqs break; 374241675Suqs case (MDOC_TBL): 375241675Suqs break; 376241675Suqs case (MDOC_EQN): 377241675Suqs break; 378241675Suqs default: 379241675Suqs if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags) 380241675Suqs break; 381241675Suqs (void)(*termacts[n->tok].post)(p, &npair, m, n); 382241675Suqs 383241675Suqs /* 384241675Suqs * Explicit end tokens not only call the post 385241675Suqs * handler, but also tell the respective block 386241675Suqs * that it must not call the post handler again. 387241675Suqs */ 388241675Suqs if (ENDBODY_NOT != n->end) 389241675Suqs n->pending->flags |= MDOC_ENDED; 390241675Suqs 391241675Suqs /* 392241675Suqs * End of line terminating an implicit block 393241675Suqs * while an explicit block is still open. 394241675Suqs * Continue the explicit block without spacing. 395241675Suqs */ 396241675Suqs if (ENDBODY_NOSPACE == n->end) 397241675Suqs p->flags |= TERMP_NOSPACE; 398241675Suqs break; 399241675Suqs } 400241675Suqs 401241675Suqs if (MDOC_EOS & n->flags) 402241675Suqs p->flags |= TERMP_SENTENCE; 403241675Suqs 404241675Suqs p->offset = offset; 405241675Suqs p->rmargin = rmargin; 406241675Suqs} 407241675Suqs 408241675Suqs 409241675Suqsstatic void 410241675Suqsprint_mdoc_foot(struct termp *p, const void *arg) 411241675Suqs{ 412241675Suqs const struct mdoc_meta *m; 413241675Suqs 414241675Suqs m = (const struct mdoc_meta *)arg; 415241675Suqs 416241675Suqs term_fontrepl(p, TERMFONT_NONE); 417241675Suqs 418241675Suqs /* 419241675Suqs * Output the footer in new-groff style, that is, three columns 420241675Suqs * with the middle being the manual date and flanking columns 421241675Suqs * being the operating system: 422241675Suqs * 423241675Suqs * SYSTEM DATE SYSTEM 424241675Suqs */ 425241675Suqs 426241675Suqs term_vspace(p); 427241675Suqs 428241675Suqs p->offset = 0; 429241675Suqs p->rmargin = (p->maxrmargin - 430241675Suqs term_strlen(p, m->date) + term_len(p, 1)) / 2; 431241675Suqs p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 432241675Suqs 433241675Suqs term_word(p, m->os); 434241675Suqs term_flushln(p); 435241675Suqs 436241675Suqs p->offset = p->rmargin; 437241675Suqs p->rmargin = p->maxrmargin - term_strlen(p, m->os); 438241675Suqs p->flags |= TERMP_NOSPACE; 439241675Suqs 440241675Suqs term_word(p, m->date); 441241675Suqs term_flushln(p); 442241675Suqs 443241675Suqs p->offset = p->rmargin; 444241675Suqs p->rmargin = p->maxrmargin; 445241675Suqs p->flags &= ~TERMP_NOBREAK; 446241675Suqs p->flags |= TERMP_NOSPACE; 447241675Suqs 448241675Suqs term_word(p, m->os); 449241675Suqs term_flushln(p); 450241675Suqs 451241675Suqs p->offset = 0; 452241675Suqs p->rmargin = p->maxrmargin; 453241675Suqs p->flags = 0; 454241675Suqs} 455241675Suqs 456241675Suqs 457241675Suqsstatic void 458241675Suqsprint_mdoc_head(struct termp *p, const void *arg) 459241675Suqs{ 460241675Suqs char buf[BUFSIZ], title[BUFSIZ]; 461241675Suqs size_t buflen, titlen; 462241675Suqs const struct mdoc_meta *m; 463241675Suqs 464241675Suqs m = (const struct mdoc_meta *)arg; 465241675Suqs 466241675Suqs /* 467241675Suqs * The header is strange. It has three components, which are 468241675Suqs * really two with the first duplicated. It goes like this: 469241675Suqs * 470241675Suqs * IDENTIFIER TITLE IDENTIFIER 471241675Suqs * 472241675Suqs * The IDENTIFIER is NAME(SECTION), which is the command-name 473241675Suqs * (if given, or "unknown" if not) followed by the manual page 474241675Suqs * section. These are given in `Dt'. The TITLE is a free-form 475241675Suqs * string depending on the manual volume. If not specified, it 476241675Suqs * switches on the manual section. 477241675Suqs */ 478241675Suqs 479241675Suqs p->offset = 0; 480241675Suqs p->rmargin = p->maxrmargin; 481241675Suqs 482241675Suqs assert(m->vol); 483241675Suqs strlcpy(buf, m->vol, BUFSIZ); 484241675Suqs buflen = term_strlen(p, buf); 485241675Suqs 486241675Suqs if (m->arch) { 487241675Suqs strlcat(buf, " (", BUFSIZ); 488241675Suqs strlcat(buf, m->arch, BUFSIZ); 489241675Suqs strlcat(buf, ")", BUFSIZ); 490241675Suqs } 491241675Suqs 492241675Suqs snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec); 493241675Suqs titlen = term_strlen(p, title); 494241675Suqs 495241675Suqs p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; 496241675Suqs p->offset = 0; 497241675Suqs p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? 498241675Suqs (p->maxrmargin - 499241675Suqs term_strlen(p, buf) + term_len(p, 1)) / 2 : 500241675Suqs p->maxrmargin - buflen; 501241675Suqs 502241675Suqs term_word(p, title); 503241675Suqs term_flushln(p); 504241675Suqs 505241675Suqs p->flags |= TERMP_NOSPACE; 506241675Suqs p->offset = p->rmargin; 507241675Suqs p->rmargin = p->offset + buflen + titlen < p->maxrmargin ? 508241675Suqs p->maxrmargin - titlen : p->maxrmargin; 509241675Suqs 510241675Suqs term_word(p, buf); 511241675Suqs term_flushln(p); 512241675Suqs 513241675Suqs p->flags &= ~TERMP_NOBREAK; 514241675Suqs if (p->rmargin + titlen <= p->maxrmargin) { 515241675Suqs p->flags |= TERMP_NOSPACE; 516241675Suqs p->offset = p->rmargin; 517241675Suqs p->rmargin = p->maxrmargin; 518241675Suqs term_word(p, title); 519241675Suqs term_flushln(p); 520241675Suqs } 521241675Suqs 522241675Suqs p->flags &= ~TERMP_NOSPACE; 523241675Suqs p->offset = 0; 524241675Suqs p->rmargin = p->maxrmargin; 525241675Suqs} 526241675Suqs 527241675Suqs 528241675Suqsstatic size_t 529241675Suqsa2height(const struct termp *p, const char *v) 530241675Suqs{ 531241675Suqs struct roffsu su; 532241675Suqs 533241675Suqs 534241675Suqs assert(v); 535241675Suqs if ( ! a2roffsu(v, &su, SCALE_VS)) 536241675Suqs SCALE_VS_INIT(&su, atoi(v)); 537241675Suqs 538241675Suqs return(term_vspan(p, &su)); 539241675Suqs} 540241675Suqs 541241675Suqs 542241675Suqsstatic size_t 543241675Suqsa2width(const struct termp *p, const char *v) 544241675Suqs{ 545241675Suqs struct roffsu su; 546241675Suqs 547241675Suqs assert(v); 548241675Suqs if ( ! a2roffsu(v, &su, SCALE_MAX)) 549241675Suqs SCALE_HS_INIT(&su, term_strlen(p, v)); 550241675Suqs 551241675Suqs return(term_hspan(p, &su)); 552241675Suqs} 553241675Suqs 554241675Suqs 555241675Suqsstatic size_t 556241675Suqsa2offs(const struct termp *p, const char *v) 557241675Suqs{ 558241675Suqs struct roffsu su; 559241675Suqs 560241675Suqs if ('\0' == *v) 561241675Suqs return(0); 562241675Suqs else if (0 == strcmp(v, "left")) 563241675Suqs return(0); 564241675Suqs else if (0 == strcmp(v, "indent")) 565241675Suqs return(term_len(p, p->defindent + 1)); 566241675Suqs else if (0 == strcmp(v, "indent-two")) 567241675Suqs return(term_len(p, (p->defindent + 1) * 2)); 568241675Suqs else if ( ! a2roffsu(v, &su, SCALE_MAX)) 569241675Suqs SCALE_HS_INIT(&su, term_strlen(p, v)); 570241675Suqs 571241675Suqs return(term_hspan(p, &su)); 572241675Suqs} 573241675Suqs 574241675Suqs 575241675Suqs/* 576241675Suqs * Determine how much space to print out before block elements of `It' 577241675Suqs * (and thus `Bl') and `Bd'. And then go ahead and print that space, 578241675Suqs * too. 579241675Suqs */ 580241675Suqsstatic void 581241675Suqsprint_bvspace(struct termp *p, 582241675Suqs const struct mdoc_node *bl, 583241675Suqs const struct mdoc_node *n) 584241675Suqs{ 585241675Suqs const struct mdoc_node *nn; 586241675Suqs 587241675Suqs assert(n); 588241675Suqs 589241675Suqs term_newln(p); 590241675Suqs 591241675Suqs if (MDOC_Bd == bl->tok && bl->norm->Bd.comp) 592241675Suqs return; 593241675Suqs if (MDOC_Bl == bl->tok && bl->norm->Bl.comp) 594241675Suqs return; 595241675Suqs 596241675Suqs /* Do not vspace directly after Ss/Sh. */ 597241675Suqs 598241675Suqs for (nn = n; nn; nn = nn->parent) { 599241675Suqs if (MDOC_BLOCK != nn->type) 600241675Suqs continue; 601241675Suqs if (MDOC_Ss == nn->tok) 602241675Suqs return; 603241675Suqs if (MDOC_Sh == nn->tok) 604241675Suqs return; 605241675Suqs if (NULL == nn->prev) 606241675Suqs continue; 607241675Suqs break; 608241675Suqs } 609241675Suqs 610241675Suqs /* A `-column' does not assert vspace within the list. */ 611241675Suqs 612241675Suqs if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type) 613241675Suqs if (n->prev && MDOC_It == n->prev->tok) 614241675Suqs return; 615241675Suqs 616241675Suqs /* A `-diag' without body does not vspace. */ 617241675Suqs 618241675Suqs if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type) 619241675Suqs if (n->prev && MDOC_It == n->prev->tok) { 620241675Suqs assert(n->prev->body); 621241675Suqs if (NULL == n->prev->body->child) 622241675Suqs return; 623241675Suqs } 624241675Suqs 625241675Suqs term_vspace(p); 626241675Suqs} 627241675Suqs 628241675Suqs 629241675Suqs/* ARGSUSED */ 630241675Suqsstatic int 631241675Suqstermp_it_pre(DECL_ARGS) 632241675Suqs{ 633241675Suqs const struct mdoc_node *bl, *nn; 634241675Suqs char buf[7]; 635241675Suqs int i; 636241675Suqs size_t width, offset, ncols, dcol; 637241675Suqs enum mdoc_list type; 638241675Suqs 639241675Suqs if (MDOC_BLOCK == n->type) { 640241675Suqs print_bvspace(p, n->parent->parent, n); 641241675Suqs return(1); 642241675Suqs } 643241675Suqs 644241675Suqs bl = n->parent->parent->parent; 645241675Suqs type = bl->norm->Bl.type; 646241675Suqs 647241675Suqs /* 648241675Suqs * First calculate width and offset. This is pretty easy unless 649241675Suqs * we're a -column list, in which case all prior columns must 650241675Suqs * be accounted for. 651241675Suqs */ 652241675Suqs 653241675Suqs width = offset = 0; 654241675Suqs 655241675Suqs if (bl->norm->Bl.offs) 656241675Suqs offset = a2offs(p, bl->norm->Bl.offs); 657241675Suqs 658241675Suqs switch (type) { 659241675Suqs case (LIST_column): 660241675Suqs if (MDOC_HEAD == n->type) 661241675Suqs break; 662241675Suqs 663241675Suqs /* 664241675Suqs * Imitate groff's column handling: 665241675Suqs * - For each earlier column, add its width. 666241675Suqs * - For less than 5 columns, add four more blanks per 667241675Suqs * column. 668241675Suqs * - For exactly 5 columns, add three more blank per 669241675Suqs * column. 670241675Suqs * - For more than 5 columns, add only one column. 671241675Suqs */ 672241675Suqs ncols = bl->norm->Bl.ncols; 673241675Suqs 674241675Suqs /* LINTED */ 675241675Suqs dcol = ncols < 5 ? term_len(p, 4) : 676241675Suqs ncols == 5 ? term_len(p, 3) : term_len(p, 1); 677241675Suqs 678241675Suqs /* 679241675Suqs * Calculate the offset by applying all prior MDOC_BODY, 680241675Suqs * so we stop at the MDOC_HEAD (NULL == nn->prev). 681241675Suqs */ 682241675Suqs 683241675Suqs for (i = 0, nn = n->prev; 684241675Suqs nn->prev && i < (int)ncols; 685241675Suqs nn = nn->prev, i++) 686241675Suqs offset += dcol + a2width 687241675Suqs (p, bl->norm->Bl.cols[i]); 688241675Suqs 689241675Suqs /* 690241675Suqs * When exceeding the declared number of columns, leave 691241675Suqs * the remaining widths at 0. This will later be 692241675Suqs * adjusted to the default width of 10, or, for the last 693241675Suqs * column, stretched to the right margin. 694241675Suqs */ 695241675Suqs if (i >= (int)ncols) 696241675Suqs break; 697241675Suqs 698241675Suqs /* 699241675Suqs * Use the declared column widths, extended as explained 700241675Suqs * in the preceding paragraph. 701241675Suqs */ 702241675Suqs width = a2width(p, bl->norm->Bl.cols[i]) + dcol; 703241675Suqs break; 704241675Suqs default: 705241675Suqs if (NULL == bl->norm->Bl.width) 706241675Suqs break; 707241675Suqs 708241675Suqs /* 709241675Suqs * Note: buffer the width by 2, which is groff's magic 710241675Suqs * number for buffering single arguments. See the above 711241675Suqs * handling for column for how this changes. 712241675Suqs */ 713241675Suqs assert(bl->norm->Bl.width); 714241675Suqs width = a2width(p, bl->norm->Bl.width) + term_len(p, 2); 715241675Suqs break; 716241675Suqs } 717241675Suqs 718241675Suqs /* 719241675Suqs * List-type can override the width in the case of fixed-head 720241675Suqs * values (bullet, dash/hyphen, enum). Tags need a non-zero 721241675Suqs * offset. 722241675Suqs */ 723241675Suqs 724241675Suqs switch (type) { 725241675Suqs case (LIST_bullet): 726241675Suqs /* FALLTHROUGH */ 727241675Suqs case (LIST_dash): 728241675Suqs /* FALLTHROUGH */ 729241675Suqs case (LIST_hyphen): 730241675Suqs if (width < term_len(p, 4)) 731241675Suqs width = term_len(p, 4); 732241675Suqs break; 733241675Suqs case (LIST_enum): 734241675Suqs if (width < term_len(p, 5)) 735241675Suqs width = term_len(p, 5); 736241675Suqs break; 737241675Suqs case (LIST_hang): 738241675Suqs if (0 == width) 739241675Suqs width = term_len(p, 8); 740241675Suqs break; 741241675Suqs case (LIST_column): 742241675Suqs /* FALLTHROUGH */ 743241675Suqs case (LIST_tag): 744241675Suqs if (0 == width) 745241675Suqs width = term_len(p, 10); 746241675Suqs break; 747241675Suqs default: 748241675Suqs break; 749241675Suqs } 750241675Suqs 751241675Suqs /* 752241675Suqs * Whitespace control. Inset bodies need an initial space, 753241675Suqs * while diagonal bodies need two. 754241675Suqs */ 755241675Suqs 756241675Suqs p->flags |= TERMP_NOSPACE; 757241675Suqs 758241675Suqs switch (type) { 759241675Suqs case (LIST_diag): 760241675Suqs if (MDOC_BODY == n->type) 761241675Suqs term_word(p, "\\ \\ "); 762241675Suqs break; 763241675Suqs case (LIST_inset): 764241675Suqs if (MDOC_BODY == n->type) 765241675Suqs term_word(p, "\\ "); 766241675Suqs break; 767241675Suqs default: 768241675Suqs break; 769241675Suqs } 770241675Suqs 771241675Suqs p->flags |= TERMP_NOSPACE; 772241675Suqs 773241675Suqs switch (type) { 774241675Suqs case (LIST_diag): 775241675Suqs if (MDOC_HEAD == n->type) 776241675Suqs term_fontpush(p, TERMFONT_BOLD); 777241675Suqs break; 778241675Suqs default: 779241675Suqs break; 780241675Suqs } 781241675Suqs 782241675Suqs /* 783241675Suqs * Pad and break control. This is the tricky part. These flags 784241675Suqs * are documented in term_flushln() in term.c. Note that we're 785241675Suqs * going to unset all of these flags in termp_it_post() when we 786241675Suqs * exit. 787241675Suqs */ 788241675Suqs 789241675Suqs switch (type) { 790241675Suqs case (LIST_bullet): 791241675Suqs /* FALLTHROUGH */ 792241675Suqs case (LIST_dash): 793241675Suqs /* FALLTHROUGH */ 794241675Suqs case (LIST_enum): 795241675Suqs /* FALLTHROUGH */ 796241675Suqs case (LIST_hyphen): 797241675Suqs if (MDOC_HEAD == n->type) 798241675Suqs p->flags |= TERMP_NOBREAK; 799241675Suqs break; 800241675Suqs case (LIST_hang): 801241675Suqs if (MDOC_HEAD == n->type) 802241675Suqs p->flags |= TERMP_NOBREAK; 803241675Suqs else 804241675Suqs break; 805241675Suqs 806241675Suqs /* 807241675Suqs * This is ugly. If `-hang' is specified and the body 808241675Suqs * is a `Bl' or `Bd', then we want basically to nullify 809241675Suqs * the "overstep" effect in term_flushln() and treat 810241675Suqs * this as a `-ohang' list instead. 811241675Suqs */ 812241675Suqs if (n->next->child && 813241675Suqs (MDOC_Bl == n->next->child->tok || 814241675Suqs MDOC_Bd == n->next->child->tok)) 815241675Suqs p->flags &= ~TERMP_NOBREAK; 816241675Suqs else 817241675Suqs p->flags |= TERMP_HANG; 818241675Suqs break; 819241675Suqs case (LIST_tag): 820241675Suqs if (MDOC_HEAD == n->type) 821241675Suqs p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE; 822241675Suqs 823241675Suqs if (MDOC_HEAD != n->type) 824241675Suqs break; 825241675Suqs if (NULL == n->next || NULL == n->next->child) 826241675Suqs p->flags |= TERMP_DANGLE; 827241675Suqs break; 828241675Suqs case (LIST_column): 829241675Suqs if (MDOC_HEAD == n->type) 830241675Suqs break; 831241675Suqs 832241675Suqs if (NULL == n->next) 833241675Suqs p->flags &= ~TERMP_NOBREAK; 834241675Suqs else 835241675Suqs p->flags |= TERMP_NOBREAK; 836241675Suqs 837241675Suqs break; 838241675Suqs case (LIST_diag): 839241675Suqs if (MDOC_HEAD == n->type) 840241675Suqs p->flags |= TERMP_NOBREAK; 841241675Suqs break; 842241675Suqs default: 843241675Suqs break; 844241675Suqs } 845241675Suqs 846241675Suqs /* 847241675Suqs * Margin control. Set-head-width lists have their right 848241675Suqs * margins shortened. The body for these lists has the offset 849241675Suqs * necessarily lengthened. Everybody gets the offset. 850241675Suqs */ 851241675Suqs 852241675Suqs p->offset += offset; 853241675Suqs 854241675Suqs switch (type) { 855241675Suqs case (LIST_hang): 856241675Suqs /* 857241675Suqs * Same stipulation as above, regarding `-hang'. We 858241675Suqs * don't want to recalculate rmargin and offsets when 859241675Suqs * using `Bd' or `Bl' within `-hang' overstep lists. 860241675Suqs */ 861241675Suqs if (MDOC_HEAD == n->type && n->next->child && 862241675Suqs (MDOC_Bl == n->next->child->tok || 863241675Suqs MDOC_Bd == n->next->child->tok)) 864241675Suqs break; 865241675Suqs /* FALLTHROUGH */ 866241675Suqs case (LIST_bullet): 867241675Suqs /* FALLTHROUGH */ 868241675Suqs case (LIST_dash): 869241675Suqs /* FALLTHROUGH */ 870241675Suqs case (LIST_enum): 871241675Suqs /* FALLTHROUGH */ 872241675Suqs case (LIST_hyphen): 873241675Suqs /* FALLTHROUGH */ 874241675Suqs case (LIST_tag): 875241675Suqs assert(width); 876241675Suqs if (MDOC_HEAD == n->type) 877241675Suqs p->rmargin = p->offset + width; 878241675Suqs else 879241675Suqs p->offset += width; 880241675Suqs break; 881241675Suqs case (LIST_column): 882241675Suqs assert(width); 883241675Suqs p->rmargin = p->offset + width; 884241675Suqs /* 885241675Suqs * XXX - this behaviour is not documented: the 886241675Suqs * right-most column is filled to the right margin. 887241675Suqs */ 888241675Suqs if (MDOC_HEAD == n->type) 889241675Suqs break; 890241675Suqs if (NULL == n->next && p->rmargin < p->maxrmargin) 891241675Suqs p->rmargin = p->maxrmargin; 892241675Suqs break; 893241675Suqs default: 894241675Suqs break; 895241675Suqs } 896241675Suqs 897241675Suqs /* 898241675Suqs * The dash, hyphen, bullet and enum lists all have a special 899241675Suqs * HEAD character (temporarily bold, in some cases). 900241675Suqs */ 901241675Suqs 902241675Suqs if (MDOC_HEAD == n->type) 903241675Suqs switch (type) { 904241675Suqs case (LIST_bullet): 905241675Suqs term_fontpush(p, TERMFONT_BOLD); 906241675Suqs term_word(p, "\\[bu]"); 907241675Suqs term_fontpop(p); 908241675Suqs break; 909241675Suqs case (LIST_dash): 910241675Suqs /* FALLTHROUGH */ 911241675Suqs case (LIST_hyphen): 912241675Suqs term_fontpush(p, TERMFONT_BOLD); 913241675Suqs term_word(p, "\\(hy"); 914241675Suqs term_fontpop(p); 915241675Suqs break; 916241675Suqs case (LIST_enum): 917241675Suqs (pair->ppair->ppair->count)++; 918241675Suqs snprintf(buf, sizeof(buf), "%d.", 919241675Suqs pair->ppair->ppair->count); 920241675Suqs term_word(p, buf); 921241675Suqs break; 922241675Suqs default: 923241675Suqs break; 924241675Suqs } 925241675Suqs 926241675Suqs /* 927241675Suqs * If we're not going to process our children, indicate so here. 928241675Suqs */ 929241675Suqs 930241675Suqs switch (type) { 931241675Suqs case (LIST_bullet): 932241675Suqs /* FALLTHROUGH */ 933241675Suqs case (LIST_item): 934241675Suqs /* FALLTHROUGH */ 935241675Suqs case (LIST_dash): 936241675Suqs /* FALLTHROUGH */ 937241675Suqs case (LIST_hyphen): 938241675Suqs /* FALLTHROUGH */ 939241675Suqs case (LIST_enum): 940241675Suqs if (MDOC_HEAD == n->type) 941241675Suqs return(0); 942241675Suqs break; 943241675Suqs case (LIST_column): 944241675Suqs if (MDOC_HEAD == n->type) 945241675Suqs return(0); 946241675Suqs break; 947241675Suqs default: 948241675Suqs break; 949241675Suqs } 950241675Suqs 951241675Suqs return(1); 952241675Suqs} 953241675Suqs 954241675Suqs 955241675Suqs/* ARGSUSED */ 956241675Suqsstatic void 957241675Suqstermp_it_post(DECL_ARGS) 958241675Suqs{ 959241675Suqs enum mdoc_list type; 960241675Suqs 961241675Suqs if (MDOC_BLOCK == n->type) 962241675Suqs return; 963241675Suqs 964241675Suqs type = n->parent->parent->parent->norm->Bl.type; 965241675Suqs 966241675Suqs switch (type) { 967241675Suqs case (LIST_item): 968241675Suqs /* FALLTHROUGH */ 969241675Suqs case (LIST_diag): 970241675Suqs /* FALLTHROUGH */ 971241675Suqs case (LIST_inset): 972241675Suqs if (MDOC_BODY == n->type) 973241675Suqs term_newln(p); 974241675Suqs break; 975241675Suqs case (LIST_column): 976241675Suqs if (MDOC_BODY == n->type) 977241675Suqs term_flushln(p); 978241675Suqs break; 979241675Suqs default: 980241675Suqs term_newln(p); 981241675Suqs break; 982241675Suqs } 983241675Suqs 984241675Suqs /* 985241675Suqs * Now that our output is flushed, we can reset our tags. Since 986241675Suqs * only `It' sets these flags, we're free to assume that nobody 987241675Suqs * has munged them in the meanwhile. 988241675Suqs */ 989241675Suqs 990241675Suqs p->flags &= ~TERMP_DANGLE; 991241675Suqs p->flags &= ~TERMP_NOBREAK; 992241675Suqs p->flags &= ~TERMP_TWOSPACE; 993241675Suqs p->flags &= ~TERMP_HANG; 994241675Suqs} 995241675Suqs 996241675Suqs 997241675Suqs/* ARGSUSED */ 998241675Suqsstatic int 999241675Suqstermp_nm_pre(DECL_ARGS) 1000241675Suqs{ 1001241675Suqs 1002241675Suqs if (MDOC_BLOCK == n->type) 1003241675Suqs return(1); 1004241675Suqs 1005241675Suqs if (MDOC_BODY == n->type) { 1006241675Suqs if (NULL == n->child) 1007241675Suqs return(0); 1008241675Suqs p->flags |= TERMP_NOSPACE; 1009241675Suqs p->offset += term_len(p, 1) + 1010241675Suqs (NULL == n->prev->child ? term_strlen(p, m->name) : 1011241675Suqs MDOC_TEXT == n->prev->child->type ? 1012241675Suqs term_strlen(p, n->prev->child->string) : 1013241675Suqs term_len(p, 5)); 1014241675Suqs return(1); 1015241675Suqs } 1016241675Suqs 1017241675Suqs if (NULL == n->child && NULL == m->name) 1018241675Suqs return(0); 1019241675Suqs 1020241675Suqs if (MDOC_HEAD == n->type) 1021241675Suqs synopsis_pre(p, n->parent); 1022241675Suqs 1023241675Suqs if (MDOC_HEAD == n->type && n->next->child) { 1024241675Suqs p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; 1025241675Suqs p->rmargin = p->offset + term_len(p, 1); 1026241675Suqs if (NULL == n->child) { 1027241675Suqs p->rmargin += term_strlen(p, m->name); 1028241675Suqs } else if (MDOC_TEXT == n->child->type) { 1029241675Suqs p->rmargin += term_strlen(p, n->child->string); 1030241675Suqs if (n->child->next) 1031241675Suqs p->flags |= TERMP_HANG; 1032241675Suqs } else { 1033241675Suqs p->rmargin += term_len(p, 5); 1034241675Suqs p->flags |= TERMP_HANG; 1035241675Suqs } 1036241675Suqs } 1037241675Suqs 1038241675Suqs term_fontpush(p, TERMFONT_BOLD); 1039241675Suqs if (NULL == n->child) 1040241675Suqs term_word(p, m->name); 1041241675Suqs return(1); 1042241675Suqs} 1043241675Suqs 1044241675Suqs 1045241675Suqs/* ARGSUSED */ 1046241675Suqsstatic void 1047241675Suqstermp_nm_post(DECL_ARGS) 1048241675Suqs{ 1049241675Suqs 1050241675Suqs if (MDOC_HEAD == n->type && n->next->child) { 1051241675Suqs term_flushln(p); 1052241675Suqs p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); 1053241675Suqs } else if (MDOC_BODY == n->type && n->child) 1054241675Suqs term_flushln(p); 1055241675Suqs} 1056241675Suqs 1057241675Suqs 1058241675Suqs/* ARGSUSED */ 1059241675Suqsstatic int 1060241675Suqstermp_fl_pre(DECL_ARGS) 1061241675Suqs{ 1062241675Suqs 1063241675Suqs term_fontpush(p, TERMFONT_BOLD); 1064241675Suqs term_word(p, "\\-"); 1065241675Suqs 1066241675Suqs if (n->child) 1067241675Suqs p->flags |= TERMP_NOSPACE; 1068241675Suqs else if (n->next && n->next->line == n->line) 1069241675Suqs p->flags |= TERMP_NOSPACE; 1070241675Suqs 1071241675Suqs return(1); 1072241675Suqs} 1073241675Suqs 1074241675Suqs 1075241675Suqs/* ARGSUSED */ 1076241675Suqsstatic int 1077241675Suqstermp__a_pre(DECL_ARGS) 1078241675Suqs{ 1079241675Suqs 1080241675Suqs if (n->prev && MDOC__A == n->prev->tok) 1081241675Suqs if (NULL == n->next || MDOC__A != n->next->tok) 1082241675Suqs term_word(p, "and"); 1083241675Suqs 1084241675Suqs return(1); 1085241675Suqs} 1086241675Suqs 1087241675Suqs 1088241675Suqs/* ARGSUSED */ 1089241675Suqsstatic int 1090241675Suqstermp_an_pre(DECL_ARGS) 1091241675Suqs{ 1092241675Suqs 1093241675Suqs if (NULL == n->child) 1094241675Suqs return(1); 1095241675Suqs 1096241675Suqs /* 1097241675Suqs * If not in the AUTHORS section, `An -split' will cause 1098241675Suqs * newlines to occur before the author name. If in the AUTHORS 1099241675Suqs * section, by default, the first `An' invocation is nosplit, 1100241675Suqs * then all subsequent ones, regardless of whether interspersed 1101241675Suqs * with other macros/text, are split. -split, in this case, 1102241675Suqs * will override the condition of the implied first -nosplit. 1103241675Suqs */ 1104241675Suqs 1105241675Suqs if (n->sec == SEC_AUTHORS) { 1106241675Suqs if ( ! (TERMP_ANPREC & p->flags)) { 1107241675Suqs if (TERMP_SPLIT & p->flags) 1108241675Suqs term_newln(p); 1109241675Suqs return(1); 1110241675Suqs } 1111241675Suqs if (TERMP_NOSPLIT & p->flags) 1112241675Suqs return(1); 1113241675Suqs term_newln(p); 1114241675Suqs return(1); 1115241675Suqs } 1116241675Suqs 1117241675Suqs if (TERMP_SPLIT & p->flags) 1118241675Suqs term_newln(p); 1119241675Suqs 1120241675Suqs return(1); 1121241675Suqs} 1122241675Suqs 1123241675Suqs 1124241675Suqs/* ARGSUSED */ 1125241675Suqsstatic void 1126241675Suqstermp_an_post(DECL_ARGS) 1127241675Suqs{ 1128241675Suqs 1129241675Suqs if (n->child) { 1130241675Suqs if (SEC_AUTHORS == n->sec) 1131241675Suqs p->flags |= TERMP_ANPREC; 1132241675Suqs return; 1133241675Suqs } 1134241675Suqs 1135241675Suqs if (AUTH_split == n->norm->An.auth) { 1136241675Suqs p->flags &= ~TERMP_NOSPLIT; 1137241675Suqs p->flags |= TERMP_SPLIT; 1138241675Suqs } else if (AUTH_nosplit == n->norm->An.auth) { 1139241675Suqs p->flags &= ~TERMP_SPLIT; 1140241675Suqs p->flags |= TERMP_NOSPLIT; 1141241675Suqs } 1142241675Suqs 1143241675Suqs} 1144241675Suqs 1145241675Suqs 1146241675Suqs/* ARGSUSED */ 1147241675Suqsstatic int 1148241675Suqstermp_ns_pre(DECL_ARGS) 1149241675Suqs{ 1150241675Suqs 1151241675Suqs if ( ! (MDOC_LINE & n->flags)) 1152241675Suqs p->flags |= TERMP_NOSPACE; 1153241675Suqs return(1); 1154241675Suqs} 1155241675Suqs 1156241675Suqs 1157241675Suqs/* ARGSUSED */ 1158241675Suqsstatic int 1159241675Suqstermp_rs_pre(DECL_ARGS) 1160241675Suqs{ 1161241675Suqs 1162241675Suqs if (SEC_SEE_ALSO != n->sec) 1163241675Suqs return(1); 1164241675Suqs if (MDOC_BLOCK == n->type && n->prev) 1165241675Suqs term_vspace(p); 1166241675Suqs return(1); 1167241675Suqs} 1168241675Suqs 1169241675Suqs 1170241675Suqs/* ARGSUSED */ 1171241675Suqsstatic int 1172241675Suqstermp_rv_pre(DECL_ARGS) 1173241675Suqs{ 1174241675Suqs int nchild; 1175241675Suqs 1176241675Suqs term_newln(p); 1177241675Suqs term_word(p, "The"); 1178241675Suqs 1179241675Suqs nchild = n->nchild; 1180241675Suqs for (n = n->child; n; n = n->next) { 1181241675Suqs term_fontpush(p, TERMFONT_BOLD); 1182241675Suqs term_word(p, n->string); 1183241675Suqs term_fontpop(p); 1184241675Suqs 1185241675Suqs p->flags |= TERMP_NOSPACE; 1186241675Suqs term_word(p, "()"); 1187241675Suqs 1188241675Suqs if (nchild > 2 && n->next) { 1189241675Suqs p->flags |= TERMP_NOSPACE; 1190241675Suqs term_word(p, ","); 1191241675Suqs } 1192241675Suqs 1193241675Suqs if (n->next && NULL == n->next->next) 1194241675Suqs term_word(p, "and"); 1195241675Suqs } 1196241675Suqs 1197241675Suqs if (nchild > 1) 1198241675Suqs term_word(p, "functions return"); 1199241675Suqs else 1200241675Suqs term_word(p, "function returns"); 1201241675Suqs 1202241675Suqs term_word(p, "the value 0 if successful; otherwise the value " 1203241675Suqs "-1 is returned and the global variable"); 1204241675Suqs 1205241675Suqs term_fontpush(p, TERMFONT_UNDER); 1206241675Suqs term_word(p, "errno"); 1207241675Suqs term_fontpop(p); 1208241675Suqs 1209241675Suqs term_word(p, "is set to indicate the error."); 1210241675Suqs p->flags |= TERMP_SENTENCE; 1211241675Suqs 1212241675Suqs return(0); 1213241675Suqs} 1214241675Suqs 1215241675Suqs 1216241675Suqs/* ARGSUSED */ 1217241675Suqsstatic int 1218241675Suqstermp_ex_pre(DECL_ARGS) 1219241675Suqs{ 1220241675Suqs int nchild; 1221241675Suqs 1222241675Suqs term_newln(p); 1223241675Suqs term_word(p, "The"); 1224241675Suqs 1225241675Suqs nchild = n->nchild; 1226241675Suqs for (n = n->child; n; n = n->next) { 1227241675Suqs term_fontpush(p, TERMFONT_BOLD); 1228241675Suqs term_word(p, n->string); 1229241675Suqs term_fontpop(p); 1230241675Suqs 1231241675Suqs if (nchild > 2 && n->next) { 1232241675Suqs p->flags |= TERMP_NOSPACE; 1233241675Suqs term_word(p, ","); 1234241675Suqs } 1235241675Suqs 1236241675Suqs if (n->next && NULL == n->next->next) 1237241675Suqs term_word(p, "and"); 1238241675Suqs } 1239241675Suqs 1240241675Suqs if (nchild > 1) 1241241675Suqs term_word(p, "utilities exit"); 1242241675Suqs else 1243241675Suqs term_word(p, "utility exits"); 1244241675Suqs 1245241675Suqs term_word(p, "0 on success, and >0 if an error occurs."); 1246241675Suqs 1247241675Suqs p->flags |= TERMP_SENTENCE; 1248241675Suqs return(0); 1249241675Suqs} 1250241675Suqs 1251241675Suqs 1252241675Suqs/* ARGSUSED */ 1253241675Suqsstatic int 1254241675Suqstermp_nd_pre(DECL_ARGS) 1255241675Suqs{ 1256241675Suqs 1257241675Suqs if (MDOC_BODY != n->type) 1258241675Suqs return(1); 1259241675Suqs 1260241675Suqs#if defined(__OpenBSD__) || defined(__linux__) 1261241675Suqs term_word(p, "\\(en"); 1262241675Suqs#else 1263241675Suqs term_word(p, "\\(em"); 1264241675Suqs#endif 1265241675Suqs return(1); 1266241675Suqs} 1267241675Suqs 1268241675Suqs 1269241675Suqs/* ARGSUSED */ 1270241675Suqsstatic int 1271241675Suqstermp_bl_pre(DECL_ARGS) 1272241675Suqs{ 1273241675Suqs 1274241675Suqs return(MDOC_HEAD != n->type); 1275241675Suqs} 1276241675Suqs 1277241675Suqs 1278241675Suqs/* ARGSUSED */ 1279241675Suqsstatic void 1280241675Suqstermp_bl_post(DECL_ARGS) 1281241675Suqs{ 1282241675Suqs 1283241675Suqs if (MDOC_BLOCK == n->type) 1284241675Suqs term_newln(p); 1285241675Suqs} 1286241675Suqs 1287241675Suqs/* ARGSUSED */ 1288241675Suqsstatic int 1289241675Suqstermp_xr_pre(DECL_ARGS) 1290241675Suqs{ 1291241675Suqs 1292241675Suqs if (NULL == (n = n->child)) 1293241675Suqs return(0); 1294241675Suqs 1295241675Suqs assert(MDOC_TEXT == n->type); 1296241675Suqs term_word(p, n->string); 1297241675Suqs 1298241675Suqs if (NULL == (n = n->next)) 1299241675Suqs return(0); 1300241675Suqs 1301241675Suqs p->flags |= TERMP_NOSPACE; 1302241675Suqs term_word(p, "("); 1303241675Suqs p->flags |= TERMP_NOSPACE; 1304241675Suqs 1305241675Suqs assert(MDOC_TEXT == n->type); 1306241675Suqs term_word(p, n->string); 1307241675Suqs 1308241675Suqs p->flags |= TERMP_NOSPACE; 1309241675Suqs term_word(p, ")"); 1310241675Suqs 1311241675Suqs return(0); 1312241675Suqs} 1313241675Suqs 1314241675Suqs/* 1315241675Suqs * This decides how to assert whitespace before any of the SYNOPSIS set 1316241675Suqs * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain 1317241675Suqs * macro combos). 1318241675Suqs */ 1319241675Suqsstatic void 1320241675Suqssynopsis_pre(struct termp *p, const struct mdoc_node *n) 1321241675Suqs{ 1322241675Suqs /* 1323241675Suqs * Obviously, if we're not in a SYNOPSIS or no prior macros 1324241675Suqs * exist, do nothing. 1325241675Suqs */ 1326241675Suqs if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags)) 1327241675Suqs return; 1328241675Suqs 1329241675Suqs /* 1330241675Suqs * If we're the second in a pair of like elements, emit our 1331241675Suqs * newline and return. UNLESS we're `Fo', `Fn', `Fn', in which 1332241675Suqs * case we soldier on. 1333241675Suqs */ 1334241675Suqs if (n->prev->tok == n->tok && 1335241675Suqs MDOC_Ft != n->tok && 1336241675Suqs MDOC_Fo != n->tok && 1337241675Suqs MDOC_Fn != n->tok) { 1338241675Suqs term_newln(p); 1339241675Suqs return; 1340241675Suqs } 1341241675Suqs 1342241675Suqs /* 1343241675Suqs * If we're one of the SYNOPSIS set and non-like pair-wise after 1344241675Suqs * another (or Fn/Fo, which we've let slip through) then assert 1345241675Suqs * vertical space, else only newline and move on. 1346241675Suqs */ 1347241675Suqs switch (n->prev->tok) { 1348241675Suqs case (MDOC_Fd): 1349241675Suqs /* FALLTHROUGH */ 1350241675Suqs case (MDOC_Fn): 1351241675Suqs /* FALLTHROUGH */ 1352241675Suqs case (MDOC_Fo): 1353241675Suqs /* FALLTHROUGH */ 1354241675Suqs case (MDOC_In): 1355241675Suqs /* FALLTHROUGH */ 1356241675Suqs case (MDOC_Vt): 1357241675Suqs term_vspace(p); 1358241675Suqs break; 1359241675Suqs case (MDOC_Ft): 1360241675Suqs if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { 1361241675Suqs term_vspace(p); 1362241675Suqs break; 1363241675Suqs } 1364241675Suqs /* FALLTHROUGH */ 1365241675Suqs default: 1366241675Suqs term_newln(p); 1367241675Suqs break; 1368241675Suqs } 1369241675Suqs} 1370241675Suqs 1371241675Suqs 1372241675Suqsstatic int 1373241675Suqstermp_vt_pre(DECL_ARGS) 1374241675Suqs{ 1375241675Suqs 1376241675Suqs if (MDOC_ELEM == n->type) { 1377241675Suqs synopsis_pre(p, n); 1378241675Suqs return(termp_under_pre(p, pair, m, n)); 1379241675Suqs } else if (MDOC_BLOCK == n->type) { 1380241675Suqs synopsis_pre(p, n); 1381241675Suqs return(1); 1382241675Suqs } else if (MDOC_HEAD == n->type) 1383241675Suqs return(0); 1384241675Suqs 1385241675Suqs return(termp_under_pre(p, pair, m, n)); 1386241675Suqs} 1387241675Suqs 1388241675Suqs 1389241675Suqs/* ARGSUSED */ 1390241675Suqsstatic int 1391241675Suqstermp_bold_pre(DECL_ARGS) 1392241675Suqs{ 1393241675Suqs 1394241675Suqs term_fontpush(p, TERMFONT_BOLD); 1395241675Suqs return(1); 1396241675Suqs} 1397241675Suqs 1398241675Suqs 1399241675Suqs/* ARGSUSED */ 1400241675Suqsstatic int 1401241675Suqstermp_fd_pre(DECL_ARGS) 1402241675Suqs{ 1403241675Suqs 1404241675Suqs synopsis_pre(p, n); 1405241675Suqs return(termp_bold_pre(p, pair, m, n)); 1406241675Suqs} 1407241675Suqs 1408241675Suqs 1409241675Suqs/* ARGSUSED */ 1410241675Suqsstatic int 1411241675Suqstermp_sh_pre(DECL_ARGS) 1412241675Suqs{ 1413241675Suqs 1414241675Suqs /* No vspace between consecutive `Sh' calls. */ 1415241675Suqs 1416241675Suqs switch (n->type) { 1417241675Suqs case (MDOC_BLOCK): 1418241675Suqs if (n->prev && MDOC_Sh == n->prev->tok) 1419241675Suqs if (NULL == n->prev->body->child) 1420241675Suqs break; 1421241675Suqs term_vspace(p); 1422241675Suqs break; 1423241675Suqs case (MDOC_HEAD): 1424241675Suqs term_fontpush(p, TERMFONT_BOLD); 1425241675Suqs break; 1426241675Suqs case (MDOC_BODY): 1427241675Suqs p->offset = term_len(p, p->defindent); 1428241675Suqs break; 1429241675Suqs default: 1430241675Suqs break; 1431241675Suqs } 1432241675Suqs return(1); 1433241675Suqs} 1434241675Suqs 1435241675Suqs 1436241675Suqs/* ARGSUSED */ 1437241675Suqsstatic void 1438241675Suqstermp_sh_post(DECL_ARGS) 1439241675Suqs{ 1440241675Suqs 1441241675Suqs switch (n->type) { 1442241675Suqs case (MDOC_HEAD): 1443241675Suqs term_newln(p); 1444241675Suqs break; 1445241675Suqs case (MDOC_BODY): 1446241675Suqs term_newln(p); 1447241675Suqs p->offset = 0; 1448241675Suqs break; 1449241675Suqs default: 1450241675Suqs break; 1451241675Suqs } 1452241675Suqs} 1453241675Suqs 1454241675Suqs 1455241675Suqs/* ARGSUSED */ 1456241675Suqsstatic int 1457241675Suqstermp_bt_pre(DECL_ARGS) 1458241675Suqs{ 1459241675Suqs 1460241675Suqs term_word(p, "is currently in beta test."); 1461241675Suqs p->flags |= TERMP_SENTENCE; 1462241675Suqs return(0); 1463241675Suqs} 1464241675Suqs 1465241675Suqs 1466241675Suqs/* ARGSUSED */ 1467241675Suqsstatic void 1468241675Suqstermp_lb_post(DECL_ARGS) 1469241675Suqs{ 1470241675Suqs 1471241675Suqs if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags) 1472241675Suqs term_newln(p); 1473241675Suqs} 1474241675Suqs 1475241675Suqs 1476241675Suqs/* ARGSUSED */ 1477241675Suqsstatic int 1478241675Suqstermp_ud_pre(DECL_ARGS) 1479241675Suqs{ 1480241675Suqs 1481241675Suqs term_word(p, "currently under development."); 1482241675Suqs p->flags |= TERMP_SENTENCE; 1483241675Suqs return(0); 1484241675Suqs} 1485241675Suqs 1486241675Suqs 1487241675Suqs/* ARGSUSED */ 1488241675Suqsstatic int 1489241675Suqstermp_d1_pre(DECL_ARGS) 1490241675Suqs{ 1491241675Suqs 1492241675Suqs if (MDOC_BLOCK != n->type) 1493241675Suqs return(1); 1494241675Suqs term_newln(p); 1495241675Suqs p->offset += term_len(p, p->defindent + 1); 1496241675Suqs return(1); 1497241675Suqs} 1498241675Suqs 1499241675Suqs 1500241675Suqs/* ARGSUSED */ 1501241675Suqsstatic void 1502241675Suqstermp_d1_post(DECL_ARGS) 1503241675Suqs{ 1504241675Suqs 1505241675Suqs if (MDOC_BLOCK != n->type) 1506241675Suqs return; 1507241675Suqs term_newln(p); 1508241675Suqs} 1509241675Suqs 1510241675Suqs 1511241675Suqs/* ARGSUSED */ 1512241675Suqsstatic int 1513241675Suqstermp_ft_pre(DECL_ARGS) 1514241675Suqs{ 1515241675Suqs 1516241675Suqs /* NB: MDOC_LINE does not effect this! */ 1517241675Suqs synopsis_pre(p, n); 1518241675Suqs term_fontpush(p, TERMFONT_UNDER); 1519241675Suqs return(1); 1520241675Suqs} 1521241675Suqs 1522241675Suqs 1523241675Suqs/* ARGSUSED */ 1524241675Suqsstatic int 1525241675Suqstermp_fn_pre(DECL_ARGS) 1526241675Suqs{ 1527241675Suqs int pretty; 1528241675Suqs 1529241675Suqs pretty = MDOC_SYNPRETTY & n->flags; 1530241675Suqs 1531241675Suqs synopsis_pre(p, n); 1532241675Suqs 1533241675Suqs if (NULL == (n = n->child)) 1534241675Suqs return(0); 1535241675Suqs 1536241675Suqs assert(MDOC_TEXT == n->type); 1537241675Suqs term_fontpush(p, TERMFONT_BOLD); 1538241675Suqs term_word(p, n->string); 1539241675Suqs term_fontpop(p); 1540241675Suqs 1541241675Suqs p->flags |= TERMP_NOSPACE; 1542241675Suqs term_word(p, "("); 1543241675Suqs p->flags |= TERMP_NOSPACE; 1544241675Suqs 1545241675Suqs for (n = n->next; n; n = n->next) { 1546241675Suqs assert(MDOC_TEXT == n->type); 1547241675Suqs term_fontpush(p, TERMFONT_UNDER); 1548241675Suqs term_word(p, n->string); 1549241675Suqs term_fontpop(p); 1550241675Suqs 1551241675Suqs if (n->next) { 1552241675Suqs p->flags |= TERMP_NOSPACE; 1553241675Suqs term_word(p, ","); 1554241675Suqs } 1555241675Suqs } 1556241675Suqs 1557241675Suqs p->flags |= TERMP_NOSPACE; 1558241675Suqs term_word(p, ")"); 1559241675Suqs 1560241675Suqs if (pretty) { 1561241675Suqs p->flags |= TERMP_NOSPACE; 1562241675Suqs term_word(p, ";"); 1563241675Suqs } 1564241675Suqs 1565241675Suqs return(0); 1566241675Suqs} 1567241675Suqs 1568241675Suqs 1569241675Suqs/* ARGSUSED */ 1570241675Suqsstatic int 1571241675Suqstermp_fa_pre(DECL_ARGS) 1572241675Suqs{ 1573241675Suqs const struct mdoc_node *nn; 1574241675Suqs 1575241675Suqs if (n->parent->tok != MDOC_Fo) { 1576241675Suqs term_fontpush(p, TERMFONT_UNDER); 1577241675Suqs return(1); 1578241675Suqs } 1579241675Suqs 1580241675Suqs for (nn = n->child; nn; nn = nn->next) { 1581241675Suqs term_fontpush(p, TERMFONT_UNDER); 1582241675Suqs term_word(p, nn->string); 1583241675Suqs term_fontpop(p); 1584241675Suqs 1585241675Suqs if (nn->next) { 1586241675Suqs p->flags |= TERMP_NOSPACE; 1587241675Suqs term_word(p, ","); 1588241675Suqs } 1589241675Suqs } 1590241675Suqs 1591241675Suqs if (n->child && n->next && n->next->tok == MDOC_Fa) { 1592241675Suqs p->flags |= TERMP_NOSPACE; 1593241675Suqs term_word(p, ","); 1594241675Suqs } 1595241675Suqs 1596241675Suqs return(0); 1597241675Suqs} 1598241675Suqs 1599241675Suqs 1600241675Suqs/* ARGSUSED */ 1601241675Suqsstatic int 1602241675Suqstermp_bd_pre(DECL_ARGS) 1603241675Suqs{ 1604241675Suqs size_t tabwidth, rm, rmax; 1605241675Suqs const struct mdoc_node *nn; 1606241675Suqs 1607241675Suqs if (MDOC_BLOCK == n->type) { 1608241675Suqs print_bvspace(p, n, n); 1609241675Suqs return(1); 1610241675Suqs } else if (MDOC_HEAD == n->type) 1611241675Suqs return(0); 1612241675Suqs 1613241675Suqs if (n->norm->Bd.offs) 1614241675Suqs p->offset += a2offs(p, n->norm->Bd.offs); 1615241675Suqs 1616241675Suqs /* 1617241675Suqs * If -ragged or -filled are specified, the block does nothing 1618241675Suqs * but change the indentation. If -unfilled or -literal are 1619241675Suqs * specified, text is printed exactly as entered in the display: 1620241675Suqs * for macro lines, a newline is appended to the line. Blank 1621241675Suqs * lines are allowed. 1622241675Suqs */ 1623241675Suqs 1624241675Suqs if (DISP_literal != n->norm->Bd.type && 1625241675Suqs DISP_unfilled != n->norm->Bd.type) 1626241675Suqs return(1); 1627241675Suqs 1628241675Suqs tabwidth = p->tabwidth; 1629241675Suqs if (DISP_literal == n->norm->Bd.type) 1630241675Suqs p->tabwidth = term_len(p, 8); 1631241675Suqs 1632241675Suqs rm = p->rmargin; 1633241675Suqs rmax = p->maxrmargin; 1634241675Suqs p->rmargin = p->maxrmargin = TERM_MAXMARGIN; 1635241675Suqs 1636241675Suqs for (nn = n->child; nn; nn = nn->next) { 1637241675Suqs print_mdoc_node(p, pair, m, nn); 1638241675Suqs /* 1639241675Suqs * If the printed node flushes its own line, then we 1640241675Suqs * needn't do it here as well. This is hacky, but the 1641241675Suqs * notion of selective eoln whitespace is pretty dumb 1642241675Suqs * anyway, so don't sweat it. 1643241675Suqs */ 1644241675Suqs switch (nn->tok) { 1645241675Suqs case (MDOC_Sm): 1646241675Suqs /* FALLTHROUGH */ 1647241675Suqs case (MDOC_br): 1648241675Suqs /* FALLTHROUGH */ 1649241675Suqs case (MDOC_sp): 1650241675Suqs /* FALLTHROUGH */ 1651241675Suqs case (MDOC_Bl): 1652241675Suqs /* FALLTHROUGH */ 1653241675Suqs case (MDOC_D1): 1654241675Suqs /* FALLTHROUGH */ 1655241675Suqs case (MDOC_Dl): 1656241675Suqs /* FALLTHROUGH */ 1657241675Suqs case (MDOC_Lp): 1658241675Suqs /* FALLTHROUGH */ 1659241675Suqs case (MDOC_Pp): 1660241675Suqs continue; 1661241675Suqs default: 1662241675Suqs break; 1663241675Suqs } 1664241675Suqs if (nn->next && nn->next->line == nn->line) 1665241675Suqs continue; 1666241675Suqs term_flushln(p); 1667241675Suqs p->flags |= TERMP_NOSPACE; 1668241675Suqs } 1669241675Suqs 1670241675Suqs p->tabwidth = tabwidth; 1671241675Suqs p->rmargin = rm; 1672241675Suqs p->maxrmargin = rmax; 1673241675Suqs return(0); 1674241675Suqs} 1675241675Suqs 1676241675Suqs 1677241675Suqs/* ARGSUSED */ 1678241675Suqsstatic void 1679241675Suqstermp_bd_post(DECL_ARGS) 1680241675Suqs{ 1681241675Suqs size_t rm, rmax; 1682241675Suqs 1683241675Suqs if (MDOC_BODY != n->type) 1684241675Suqs return; 1685241675Suqs 1686241675Suqs rm = p->rmargin; 1687241675Suqs rmax = p->maxrmargin; 1688241675Suqs 1689241675Suqs if (DISP_literal == n->norm->Bd.type || 1690241675Suqs DISP_unfilled == n->norm->Bd.type) 1691241675Suqs p->rmargin = p->maxrmargin = TERM_MAXMARGIN; 1692241675Suqs 1693241675Suqs p->flags |= TERMP_NOSPACE; 1694241675Suqs term_newln(p); 1695241675Suqs 1696241675Suqs p->rmargin = rm; 1697241675Suqs p->maxrmargin = rmax; 1698241675Suqs} 1699241675Suqs 1700241675Suqs 1701241675Suqs/* ARGSUSED */ 1702241675Suqsstatic int 1703241675Suqstermp_bx_pre(DECL_ARGS) 1704241675Suqs{ 1705241675Suqs 1706241675Suqs if (NULL != (n = n->child)) { 1707241675Suqs term_word(p, n->string); 1708241675Suqs p->flags |= TERMP_NOSPACE; 1709241675Suqs term_word(p, "BSD"); 1710241675Suqs } else { 1711241675Suqs term_word(p, "BSD"); 1712241675Suqs return(0); 1713241675Suqs } 1714241675Suqs 1715241675Suqs if (NULL != (n = n->next)) { 1716241675Suqs p->flags |= TERMP_NOSPACE; 1717241675Suqs term_word(p, "-"); 1718241675Suqs p->flags |= TERMP_NOSPACE; 1719241675Suqs term_word(p, n->string); 1720241675Suqs } 1721241675Suqs 1722241675Suqs return(0); 1723241675Suqs} 1724241675Suqs 1725241675Suqs 1726241675Suqs/* ARGSUSED */ 1727241675Suqsstatic int 1728241675Suqstermp_xx_pre(DECL_ARGS) 1729241675Suqs{ 1730241675Suqs const char *pp; 1731241675Suqs int flags; 1732241675Suqs 1733241675Suqs pp = NULL; 1734241675Suqs switch (n->tok) { 1735241675Suqs case (MDOC_Bsx): 1736241675Suqs pp = "BSD/OS"; 1737241675Suqs break; 1738241675Suqs case (MDOC_Dx): 1739241675Suqs pp = "DragonFly"; 1740241675Suqs break; 1741241675Suqs case (MDOC_Fx): 1742241675Suqs pp = "FreeBSD"; 1743241675Suqs break; 1744241675Suqs case (MDOC_Nx): 1745241675Suqs pp = "NetBSD"; 1746241675Suqs break; 1747241675Suqs case (MDOC_Ox): 1748241675Suqs pp = "OpenBSD"; 1749241675Suqs break; 1750241675Suqs case (MDOC_Ux): 1751241675Suqs pp = "UNIX"; 1752241675Suqs break; 1753241675Suqs default: 1754241675Suqs break; 1755241675Suqs } 1756241675Suqs 1757241675Suqs term_word(p, pp); 1758241675Suqs if (n->child) { 1759241675Suqs flags = p->flags; 1760241675Suqs p->flags |= TERMP_KEEP; 1761241675Suqs term_word(p, n->child->string); 1762241675Suqs p->flags = flags; 1763241675Suqs } 1764241675Suqs return(0); 1765241675Suqs} 1766241675Suqs 1767241675Suqs 1768241675Suqs/* ARGSUSED */ 1769241675Suqsstatic int 1770241675Suqstermp_igndelim_pre(DECL_ARGS) 1771241675Suqs{ 1772241675Suqs 1773241675Suqs p->flags |= TERMP_IGNDELIM; 1774241675Suqs return(1); 1775241675Suqs} 1776241675Suqs 1777241675Suqs 1778241675Suqs/* ARGSUSED */ 1779241675Suqsstatic void 1780241675Suqstermp_pf_post(DECL_ARGS) 1781241675Suqs{ 1782241675Suqs 1783241675Suqs p->flags |= TERMP_NOSPACE; 1784241675Suqs} 1785241675Suqs 1786241675Suqs 1787241675Suqs/* ARGSUSED */ 1788241675Suqsstatic int 1789241675Suqstermp_ss_pre(DECL_ARGS) 1790241675Suqs{ 1791241675Suqs 1792241675Suqs switch (n->type) { 1793241675Suqs case (MDOC_BLOCK): 1794241675Suqs term_newln(p); 1795241675Suqs if (n->prev) 1796241675Suqs term_vspace(p); 1797241675Suqs break; 1798241675Suqs case (MDOC_HEAD): 1799241675Suqs term_fontpush(p, TERMFONT_BOLD); 1800241675Suqs p->offset = term_len(p, (p->defindent+1)/2); 1801241675Suqs break; 1802241675Suqs default: 1803241675Suqs break; 1804241675Suqs } 1805241675Suqs 1806241675Suqs return(1); 1807241675Suqs} 1808241675Suqs 1809241675Suqs 1810241675Suqs/* ARGSUSED */ 1811241675Suqsstatic void 1812241675Suqstermp_ss_post(DECL_ARGS) 1813241675Suqs{ 1814241675Suqs 1815241675Suqs if (MDOC_HEAD == n->type) 1816241675Suqs term_newln(p); 1817241675Suqs} 1818241675Suqs 1819241675Suqs 1820241675Suqs/* ARGSUSED */ 1821241675Suqsstatic int 1822241675Suqstermp_cd_pre(DECL_ARGS) 1823241675Suqs{ 1824241675Suqs 1825241675Suqs synopsis_pre(p, n); 1826241675Suqs term_fontpush(p, TERMFONT_BOLD); 1827241675Suqs return(1); 1828241675Suqs} 1829241675Suqs 1830241675Suqs 1831241675Suqs/* ARGSUSED */ 1832241675Suqsstatic int 1833241675Suqstermp_in_pre(DECL_ARGS) 1834241675Suqs{ 1835241675Suqs 1836241675Suqs synopsis_pre(p, n); 1837241675Suqs 1838241675Suqs if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) { 1839241675Suqs term_fontpush(p, TERMFONT_BOLD); 1840241675Suqs term_word(p, "#include"); 1841241675Suqs term_word(p, "<"); 1842241675Suqs } else { 1843241675Suqs term_word(p, "<"); 1844241675Suqs term_fontpush(p, TERMFONT_UNDER); 1845241675Suqs } 1846241675Suqs 1847241675Suqs p->flags |= TERMP_NOSPACE; 1848241675Suqs return(1); 1849241675Suqs} 1850241675Suqs 1851241675Suqs 1852241675Suqs/* ARGSUSED */ 1853241675Suqsstatic void 1854241675Suqstermp_in_post(DECL_ARGS) 1855241675Suqs{ 1856241675Suqs 1857241675Suqs if (MDOC_SYNPRETTY & n->flags) 1858241675Suqs term_fontpush(p, TERMFONT_BOLD); 1859241675Suqs 1860241675Suqs p->flags |= TERMP_NOSPACE; 1861241675Suqs term_word(p, ">"); 1862241675Suqs 1863241675Suqs if (MDOC_SYNPRETTY & n->flags) 1864241675Suqs term_fontpop(p); 1865241675Suqs} 1866241675Suqs 1867241675Suqs 1868241675Suqs/* ARGSUSED */ 1869241675Suqsstatic int 1870241675Suqstermp_sp_pre(DECL_ARGS) 1871241675Suqs{ 1872241675Suqs size_t i, len; 1873241675Suqs 1874241675Suqs switch (n->tok) { 1875241675Suqs case (MDOC_sp): 1876241675Suqs len = n->child ? a2height(p, n->child->string) : 1; 1877241675Suqs break; 1878241675Suqs case (MDOC_br): 1879241675Suqs len = 0; 1880241675Suqs break; 1881241675Suqs default: 1882241675Suqs len = 1; 1883241675Suqs break; 1884241675Suqs } 1885241675Suqs 1886241675Suqs if (0 == len) 1887241675Suqs term_newln(p); 1888241675Suqs for (i = 0; i < len; i++) 1889241675Suqs term_vspace(p); 1890241675Suqs 1891241675Suqs return(0); 1892241675Suqs} 1893241675Suqs 1894241675Suqs 1895241675Suqs/* ARGSUSED */ 1896241675Suqsstatic int 1897241675Suqstermp_quote_pre(DECL_ARGS) 1898241675Suqs{ 1899241675Suqs 1900241675Suqs if (MDOC_BODY != n->type && MDOC_ELEM != n->type) 1901241675Suqs return(1); 1902241675Suqs 1903241675Suqs switch (n->tok) { 1904241675Suqs case (MDOC_Ao): 1905241675Suqs /* FALLTHROUGH */ 1906241675Suqs case (MDOC_Aq): 1907241675Suqs term_word(p, "<"); 1908241675Suqs break; 1909241675Suqs case (MDOC_Bro): 1910241675Suqs /* FALLTHROUGH */ 1911241675Suqs case (MDOC_Brq): 1912241675Suqs term_word(p, "{"); 1913241675Suqs break; 1914241675Suqs case (MDOC_Oo): 1915241675Suqs /* FALLTHROUGH */ 1916241675Suqs case (MDOC_Op): 1917241675Suqs /* FALLTHROUGH */ 1918241675Suqs case (MDOC_Bo): 1919241675Suqs /* FALLTHROUGH */ 1920241675Suqs case (MDOC_Bq): 1921241675Suqs term_word(p, "["); 1922241675Suqs break; 1923241675Suqs case (MDOC_Do): 1924241675Suqs /* FALLTHROUGH */ 1925241675Suqs case (MDOC_Dq): 1926241675Suqs term_word(p, "``"); 1927241675Suqs break; 1928241675Suqs case (MDOC_Eo): 1929241675Suqs break; 1930241675Suqs case (MDOC_Po): 1931241675Suqs /* FALLTHROUGH */ 1932241675Suqs case (MDOC_Pq): 1933241675Suqs term_word(p, "("); 1934241675Suqs break; 1935241675Suqs case (MDOC__T): 1936241675Suqs /* FALLTHROUGH */ 1937241675Suqs case (MDOC_Qo): 1938241675Suqs /* FALLTHROUGH */ 1939241675Suqs case (MDOC_Qq): 1940241675Suqs term_word(p, "\""); 1941241675Suqs break; 1942241675Suqs case (MDOC_Ql): 1943241675Suqs /* FALLTHROUGH */ 1944241675Suqs case (MDOC_So): 1945241675Suqs /* FALLTHROUGH */ 1946241675Suqs case (MDOC_Sq): 1947241675Suqs term_word(p, "`"); 1948241675Suqs break; 1949241675Suqs default: 1950241675Suqs abort(); 1951241675Suqs /* NOTREACHED */ 1952241675Suqs } 1953241675Suqs 1954241675Suqs p->flags |= TERMP_NOSPACE; 1955241675Suqs return(1); 1956241675Suqs} 1957241675Suqs 1958241675Suqs 1959241675Suqs/* ARGSUSED */ 1960241675Suqsstatic void 1961241675Suqstermp_quote_post(DECL_ARGS) 1962241675Suqs{ 1963241675Suqs 1964241675Suqs if (MDOC_BODY != n->type && MDOC_ELEM != n->type) 1965241675Suqs return; 1966241675Suqs 1967241675Suqs p->flags |= TERMP_NOSPACE; 1968241675Suqs 1969241675Suqs switch (n->tok) { 1970241675Suqs case (MDOC_Ao): 1971241675Suqs /* FALLTHROUGH */ 1972241675Suqs case (MDOC_Aq): 1973241675Suqs term_word(p, ">"); 1974241675Suqs break; 1975241675Suqs case (MDOC_Bro): 1976241675Suqs /* FALLTHROUGH */ 1977241675Suqs case (MDOC_Brq): 1978241675Suqs term_word(p, "}"); 1979241675Suqs break; 1980241675Suqs case (MDOC_Oo): 1981241675Suqs /* FALLTHROUGH */ 1982241675Suqs case (MDOC_Op): 1983241675Suqs /* FALLTHROUGH */ 1984241675Suqs case (MDOC_Bo): 1985241675Suqs /* FALLTHROUGH */ 1986241675Suqs case (MDOC_Bq): 1987241675Suqs term_word(p, "]"); 1988241675Suqs break; 1989241675Suqs case (MDOC_Do): 1990241675Suqs /* FALLTHROUGH */ 1991241675Suqs case (MDOC_Dq): 1992241675Suqs term_word(p, "''"); 1993241675Suqs break; 1994241675Suqs case (MDOC_Eo): 1995241675Suqs break; 1996241675Suqs case (MDOC_Po): 1997241675Suqs /* FALLTHROUGH */ 1998241675Suqs case (MDOC_Pq): 1999241675Suqs term_word(p, ")"); 2000241675Suqs break; 2001241675Suqs case (MDOC__T): 2002241675Suqs /* FALLTHROUGH */ 2003241675Suqs case (MDOC_Qo): 2004241675Suqs /* FALLTHROUGH */ 2005241675Suqs case (MDOC_Qq): 2006241675Suqs term_word(p, "\""); 2007241675Suqs break; 2008241675Suqs case (MDOC_Ql): 2009241675Suqs /* FALLTHROUGH */ 2010241675Suqs case (MDOC_So): 2011241675Suqs /* FALLTHROUGH */ 2012241675Suqs case (MDOC_Sq): 2013241675Suqs term_word(p, "'"); 2014241675Suqs break; 2015241675Suqs default: 2016241675Suqs abort(); 2017241675Suqs /* NOTREACHED */ 2018241675Suqs } 2019241675Suqs} 2020241675Suqs 2021241675Suqs 2022241675Suqs/* ARGSUSED */ 2023241675Suqsstatic int 2024241675Suqstermp_fo_pre(DECL_ARGS) 2025241675Suqs{ 2026241675Suqs 2027241675Suqs if (MDOC_BLOCK == n->type) { 2028241675Suqs synopsis_pre(p, n); 2029241675Suqs return(1); 2030241675Suqs } else if (MDOC_BODY == n->type) { 2031241675Suqs p->flags |= TERMP_NOSPACE; 2032241675Suqs term_word(p, "("); 2033241675Suqs p->flags |= TERMP_NOSPACE; 2034241675Suqs return(1); 2035241675Suqs } 2036241675Suqs 2037241675Suqs if (NULL == n->child) 2038241675Suqs return(0); 2039241675Suqs 2040241675Suqs /* XXX: we drop non-initial arguments as per groff. */ 2041241675Suqs 2042241675Suqs assert(n->child->string); 2043241675Suqs term_fontpush(p, TERMFONT_BOLD); 2044241675Suqs term_word(p, n->child->string); 2045241675Suqs return(0); 2046241675Suqs} 2047241675Suqs 2048241675Suqs 2049241675Suqs/* ARGSUSED */ 2050241675Suqsstatic void 2051241675Suqstermp_fo_post(DECL_ARGS) 2052241675Suqs{ 2053241675Suqs 2054241675Suqs if (MDOC_BODY != n->type) 2055241675Suqs return; 2056241675Suqs 2057241675Suqs p->flags |= TERMP_NOSPACE; 2058241675Suqs term_word(p, ")"); 2059241675Suqs 2060241675Suqs if (MDOC_SYNPRETTY & n->flags) { 2061241675Suqs p->flags |= TERMP_NOSPACE; 2062241675Suqs term_word(p, ";"); 2063241675Suqs } 2064241675Suqs} 2065241675Suqs 2066241675Suqs 2067241675Suqs/* ARGSUSED */ 2068241675Suqsstatic int 2069241675Suqstermp_bf_pre(DECL_ARGS) 2070241675Suqs{ 2071241675Suqs 2072241675Suqs if (MDOC_HEAD == n->type) 2073241675Suqs return(0); 2074241675Suqs else if (MDOC_BLOCK != n->type) 2075241675Suqs return(1); 2076241675Suqs 2077241675Suqs if (FONT_Em == n->norm->Bf.font) 2078241675Suqs term_fontpush(p, TERMFONT_UNDER); 2079241675Suqs else if (FONT_Sy == n->norm->Bf.font) 2080241675Suqs term_fontpush(p, TERMFONT_BOLD); 2081241675Suqs else 2082241675Suqs term_fontpush(p, TERMFONT_NONE); 2083241675Suqs 2084241675Suqs return(1); 2085241675Suqs} 2086241675Suqs 2087241675Suqs 2088241675Suqs/* ARGSUSED */ 2089241675Suqsstatic int 2090241675Suqstermp_sm_pre(DECL_ARGS) 2091241675Suqs{ 2092241675Suqs 2093241675Suqs assert(n->child && MDOC_TEXT == n->child->type); 2094241675Suqs if (0 == strcmp("on", n->child->string)) { 2095241675Suqs if (p->col) 2096241675Suqs p->flags &= ~TERMP_NOSPACE; 2097241675Suqs p->flags &= ~TERMP_NONOSPACE; 2098241675Suqs } else 2099241675Suqs p->flags |= TERMP_NONOSPACE; 2100241675Suqs 2101241675Suqs return(0); 2102241675Suqs} 2103241675Suqs 2104241675Suqs 2105241675Suqs/* ARGSUSED */ 2106241675Suqsstatic int 2107241675Suqstermp_ap_pre(DECL_ARGS) 2108241675Suqs{ 2109241675Suqs 2110241675Suqs p->flags |= TERMP_NOSPACE; 2111241675Suqs term_word(p, "'"); 2112241675Suqs p->flags |= TERMP_NOSPACE; 2113241675Suqs return(1); 2114241675Suqs} 2115241675Suqs 2116241675Suqs 2117241675Suqs/* ARGSUSED */ 2118241675Suqsstatic void 2119241675Suqstermp____post(DECL_ARGS) 2120241675Suqs{ 2121241675Suqs 2122241675Suqs /* 2123241675Suqs * Handle lists of authors. In general, print each followed by 2124241675Suqs * a comma. Don't print the comma if there are only two 2125241675Suqs * authors. 2126241675Suqs */ 2127241675Suqs if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok) 2128241675Suqs if (NULL == n->next->next || MDOC__A != n->next->next->tok) 2129241675Suqs if (NULL == n->prev || MDOC__A != n->prev->tok) 2130241675Suqs return; 2131241675Suqs 2132241675Suqs /* TODO: %U. */ 2133241675Suqs 2134241675Suqs if (NULL == n->parent || MDOC_Rs != n->parent->tok) 2135241675Suqs return; 2136241675Suqs 2137241675Suqs p->flags |= TERMP_NOSPACE; 2138241675Suqs if (NULL == n->next) { 2139241675Suqs term_word(p, "."); 2140241675Suqs p->flags |= TERMP_SENTENCE; 2141241675Suqs } else 2142241675Suqs term_word(p, ","); 2143241675Suqs} 2144241675Suqs 2145241675Suqs 2146241675Suqs/* ARGSUSED */ 2147241675Suqsstatic int 2148241675Suqstermp_li_pre(DECL_ARGS) 2149241675Suqs{ 2150241675Suqs 2151241675Suqs term_fontpush(p, TERMFONT_NONE); 2152241675Suqs return(1); 2153241675Suqs} 2154241675Suqs 2155241675Suqs 2156241675Suqs/* ARGSUSED */ 2157241675Suqsstatic int 2158241675Suqstermp_lk_pre(DECL_ARGS) 2159241675Suqs{ 2160241675Suqs const struct mdoc_node *nn, *sv; 2161241675Suqs 2162241675Suqs term_fontpush(p, TERMFONT_UNDER); 2163241675Suqs 2164241675Suqs nn = sv = n->child; 2165241675Suqs 2166241675Suqs if (NULL == nn || NULL == nn->next) 2167241675Suqs return(1); 2168241675Suqs 2169241675Suqs for (nn = nn->next; nn; nn = nn->next) 2170241675Suqs term_word(p, nn->string); 2171241675Suqs 2172241675Suqs term_fontpop(p); 2173241675Suqs 2174241675Suqs p->flags |= TERMP_NOSPACE; 2175241675Suqs term_word(p, ":"); 2176241675Suqs 2177241675Suqs term_fontpush(p, TERMFONT_BOLD); 2178241675Suqs term_word(p, sv->string); 2179241675Suqs term_fontpop(p); 2180241675Suqs 2181241675Suqs return(0); 2182241675Suqs} 2183241675Suqs 2184241675Suqs 2185241675Suqs/* ARGSUSED */ 2186241675Suqsstatic int 2187241675Suqstermp_bk_pre(DECL_ARGS) 2188241675Suqs{ 2189241675Suqs 2190241675Suqs switch (n->type) { 2191241675Suqs case (MDOC_BLOCK): 2192241675Suqs break; 2193241675Suqs case (MDOC_HEAD): 2194241675Suqs return(0); 2195241675Suqs case (MDOC_BODY): 2196241675Suqs if (n->parent->args || 0 == n->prev->nchild) 2197241675Suqs p->flags |= TERMP_PREKEEP; 2198241675Suqs break; 2199241675Suqs default: 2200241675Suqs abort(); 2201241675Suqs /* NOTREACHED */ 2202241675Suqs } 2203241675Suqs 2204241675Suqs return(1); 2205241675Suqs} 2206241675Suqs 2207241675Suqs 2208241675Suqs/* ARGSUSED */ 2209241675Suqsstatic void 2210241675Suqstermp_bk_post(DECL_ARGS) 2211241675Suqs{ 2212241675Suqs 2213241675Suqs if (MDOC_BODY == n->type) 2214241675Suqs p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); 2215241675Suqs} 2216241675Suqs 2217241675Suqs/* ARGSUSED */ 2218241675Suqsstatic void 2219241675Suqstermp__t_post(DECL_ARGS) 2220241675Suqs{ 2221241675Suqs 2222241675Suqs /* 2223241675Suqs * If we're in an `Rs' and there's a journal present, then quote 2224241675Suqs * us instead of underlining us (for disambiguation). 2225241675Suqs */ 2226241675Suqs if (n->parent && MDOC_Rs == n->parent->tok && 2227241675Suqs n->parent->norm->Rs.quote_T) 2228241675Suqs termp_quote_post(p, pair, m, n); 2229241675Suqs 2230241675Suqs termp____post(p, pair, m, n); 2231241675Suqs} 2232241675Suqs 2233241675Suqs/* ARGSUSED */ 2234241675Suqsstatic int 2235241675Suqstermp__t_pre(DECL_ARGS) 2236241675Suqs{ 2237241675Suqs 2238241675Suqs /* 2239241675Suqs * If we're in an `Rs' and there's a journal present, then quote 2240241675Suqs * us instead of underlining us (for disambiguation). 2241241675Suqs */ 2242241675Suqs if (n->parent && MDOC_Rs == n->parent->tok && 2243241675Suqs n->parent->norm->Rs.quote_T) 2244241675Suqs return(termp_quote_pre(p, pair, m, n)); 2245241675Suqs 2246241675Suqs term_fontpush(p, TERMFONT_UNDER); 2247241675Suqs return(1); 2248241675Suqs} 2249241675Suqs 2250241675Suqs/* ARGSUSED */ 2251241675Suqsstatic int 2252241675Suqstermp_under_pre(DECL_ARGS) 2253241675Suqs{ 2254241675Suqs 2255241675Suqs term_fontpush(p, TERMFONT_UNDER); 2256241675Suqs return(1); 2257241675Suqs} 2258