Annotation of mandoc/term.c, Revision 1.64
1.64 ! kristaps 1: /* $Id: term.c,v 1.63 2009/03/20 16:43:28 kristaps Exp $ */
1.1 kristaps 2: /*
1.61 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
1.50 kristaps 19: #include <sys/types.h>
20:
1.1 kristaps 21: #include <assert.h>
1.25 kristaps 22: #include <ctype.h>
1.23 kristaps 23: #include <err.h>
1.22 kristaps 24: #include <stdio.h>
1.1 kristaps 25: #include <stdlib.h>
26: #include <string.h>
27:
1.10 kristaps 28: #include "term.h"
29:
30: /*
31: * Performs actions on nodes of the abstract syntax tree. Both pre- and
32: * post-fix operations are defined here.
33: */
34:
1.21 kristaps 35: /* FIXME: macro arguments can be escaped. */
1.10 kristaps 36:
37: #define TTYPE_PROG 0
38: #define TTYPE_CMD_FLAG 1
39: #define TTYPE_CMD_ARG 2
40: #define TTYPE_SECTION 3
41: #define TTYPE_FUNC_DECL 4
42: #define TTYPE_VAR_DECL 5
43: #define TTYPE_FUNC_TYPE 6
44: #define TTYPE_FUNC_NAME 7
45: #define TTYPE_FUNC_ARG 8
46: #define TTYPE_LINK 9
47: #define TTYPE_SSECTION 10
48: #define TTYPE_FILE 11
1.11 kristaps 49: #define TTYPE_EMPH 12
1.14 kristaps 50: #define TTYPE_CONFIG 13
51: #define TTYPE_CMD 14
52: #define TTYPE_INCLUDE 15
1.17 kristaps 53: #define TTYPE_SYMB 16
54: #define TTYPE_SYMBOL 17
1.37 kristaps 55: #define TTYPE_DIAG 18
1.51 kristaps 56: #define TTYPE_LINK_ANCHOR 19
57: #define TTYPE_LINK_TEXT 20
1.54 kristaps 58: #define TTYPE_REF_TITLE 21
59: #define TTYPE_NMAX 22
1.10 kristaps 60:
61: /*
62: * These define "styles" for element types, like command arguments or
63: * executable names. This is useful when multiple macros must decorate
64: * the same thing (like .Ex -std cmd and .Nm cmd).
65: */
66:
1.36 kristaps 67: /* TODO: abstract this into mdocterm.c. */
68:
1.10 kristaps 69: const int ttypes[TTYPE_NMAX] = {
1.59 kristaps 70: TERMP_BOLD, /* TTYPE_PROG */
1.10 kristaps 71: TERMP_BOLD, /* TTYPE_CMD_FLAG */
1.59 kristaps 72: TERMP_UNDER, /* TTYPE_CMD_ARG */
1.10 kristaps 73: TERMP_BOLD, /* TTYPE_SECTION */
74: TERMP_BOLD, /* TTYPE_FUNC_DECL */
1.59 kristaps 75: TERMP_UNDER, /* TTYPE_VAR_DECL */
76: TERMP_UNDER, /* TTYPE_FUNC_TYPE */
1.10 kristaps 77: TERMP_BOLD, /* TTYPE_FUNC_NAME */
1.59 kristaps 78: TERMP_UNDER, /* TTYPE_FUNC_ARG */
79: TERMP_UNDER, /* TTYPE_LINK */
1.10 kristaps 80: TERMP_BOLD, /* TTYPE_SSECTION */
1.59 kristaps 81: TERMP_UNDER, /* TTYPE_FILE */
82: TERMP_UNDER, /* TTYPE_EMPH */
1.14 kristaps 83: TERMP_BOLD, /* TTYPE_CONFIG */
84: TERMP_BOLD, /* TTYPE_CMD */
1.17 kristaps 85: TERMP_BOLD, /* TTYPE_INCLUDE */
86: TERMP_BOLD, /* TTYPE_SYMB */
1.37 kristaps 87: TERMP_BOLD, /* TTYPE_SYMBOL */
1.51 kristaps 88: TERMP_BOLD, /* TTYPE_DIAG */
1.59 kristaps 89: TERMP_UNDER, /* TTYPE_LINK_ANCHOR */
1.54 kristaps 90: TERMP_BOLD, /* TTYPE_LINK_TEXT */
1.59 kristaps 91: TERMP_UNDER /* TTYPE_REF_TITLE */
1.10 kristaps 92: };
1.7 kristaps 93:
1.44 kristaps 94: static int arg_hasattr(int, const struct mdoc_node *);
1.54 kristaps 95: static int arg_getattrs(const int *, int *, size_t,
96: const struct mdoc_node *);
1.44 kristaps 97: static int arg_getattr(int, const struct mdoc_node *);
98: static size_t arg_offset(const struct mdoc_argv *);
1.54 kristaps 99: static size_t arg_width(const struct mdoc_argv *, int);
1.39 kristaps 100: static int arg_listtype(const struct mdoc_node *);
1.10 kristaps 101:
102: /*
103: * What follows describes prefix and postfix operations for the abstract
104: * syntax tree descent.
105: */
1.1 kristaps 106:
1.10 kristaps 107: #define DECL_ARGS \
108: struct termp *p, \
1.18 kristaps 109: struct termpair *pair, \
1.10 kristaps 110: const struct mdoc_meta *meta, \
111: const struct mdoc_node *node
112:
113: #define DECL_PRE(name) \
114: static int name##_pre(DECL_ARGS)
115: #define DECL_POST(name) \
116: static void name##_post(DECL_ARGS)
117: #define DECL_PREPOST(name) \
118: DECL_PRE(name); \
119: DECL_POST(name);
120:
121: DECL_PREPOST(termp_aq);
1.12 kristaps 122: DECL_PREPOST(termp_bd);
1.15 kristaps 123: DECL_PREPOST(termp_bq);
1.53 kristaps 124: DECL_PREPOST(termp_brq);
1.10 kristaps 125: DECL_PREPOST(termp_d1);
126: DECL_PREPOST(termp_dq);
127: DECL_PREPOST(termp_fd);
128: DECL_PREPOST(termp_fn);
1.16 kristaps 129: DECL_PREPOST(termp_fo);
1.10 kristaps 130: DECL_PREPOST(termp_ft);
1.30 kristaps 131: DECL_PREPOST(termp_in);
1.10 kristaps 132: DECL_PREPOST(termp_it);
1.47 kristaps 133: DECL_PREPOST(termp_lb);
1.10 kristaps 134: DECL_PREPOST(termp_op);
135: DECL_PREPOST(termp_pf);
1.15 kristaps 136: DECL_PREPOST(termp_pq);
1.10 kristaps 137: DECL_PREPOST(termp_qq);
138: DECL_PREPOST(termp_sh);
139: DECL_PREPOST(termp_ss);
140: DECL_PREPOST(termp_sq);
141: DECL_PREPOST(termp_vt);
142:
1.54 kristaps 143: DECL_PRE(termp__t);
1.48 kristaps 144: DECL_PRE(termp_ap);
1.18 kristaps 145: DECL_PRE(termp_ar);
1.14 kristaps 146: DECL_PRE(termp_at);
1.18 kristaps 147: DECL_PRE(termp_bf);
1.15 kristaps 148: DECL_PRE(termp_bsx);
1.17 kristaps 149: DECL_PRE(termp_bt);
1.18 kristaps 150: DECL_PRE(termp_cd);
151: DECL_PRE(termp_cm);
1.61 kristaps 152: DECL_PRE(termp_dx);
1.18 kristaps 153: DECL_PRE(termp_em);
1.10 kristaps 154: DECL_PRE(termp_ex);
1.18 kristaps 155: DECL_PRE(termp_fa);
156: DECL_PRE(termp_fl);
1.16 kristaps 157: DECL_PRE(termp_fx);
1.18 kristaps 158: DECL_PRE(termp_ic);
1.51 kristaps 159: DECL_PRE(termp_lk);
1.18 kristaps 160: DECL_PRE(termp_ms);
1.51 kristaps 161: DECL_PRE(termp_mt);
1.10 kristaps 162: DECL_PRE(termp_nd);
1.18 kristaps 163: DECL_PRE(termp_nm);
1.10 kristaps 164: DECL_PRE(termp_ns);
165: DECL_PRE(termp_nx);
166: DECL_PRE(termp_ox);
1.18 kristaps 167: DECL_PRE(termp_pa);
1.10 kristaps 168: DECL_PRE(termp_pp);
1.28 kristaps 169: DECL_PRE(termp_rs);
1.14 kristaps 170: DECL_PRE(termp_rv);
1.22 kristaps 171: DECL_PRE(termp_sm);
1.14 kristaps 172: DECL_PRE(termp_st);
1.18 kristaps 173: DECL_PRE(termp_sx);
174: DECL_PRE(termp_sy);
1.10 kristaps 175: DECL_PRE(termp_ud);
1.16 kristaps 176: DECL_PRE(termp_ux);
1.18 kristaps 177: DECL_PRE(termp_va);
1.10 kristaps 178: DECL_PRE(termp_xr);
179:
1.28 kristaps 180: DECL_POST(termp___);
1.10 kristaps 181: DECL_POST(termp_bl);
1.31 kristaps 182: DECL_POST(termp_bx);
1.10 kristaps 183:
184: const struct termact __termacts[MDOC_MAX] = {
185: { NULL, NULL }, /* \" */
186: { NULL, NULL }, /* Dd */
187: { NULL, NULL }, /* Dt */
188: { NULL, NULL }, /* Os */
189: { termp_sh_pre, termp_sh_post }, /* Sh */
190: { termp_ss_pre, termp_ss_post }, /* Ss */
191: { termp_pp_pre, NULL }, /* Pp */
192: { termp_d1_pre, termp_d1_post }, /* D1 */
1.29 kristaps 193: { termp_d1_pre, termp_d1_post }, /* Dl */
1.12 kristaps 194: { termp_bd_pre, termp_bd_post }, /* Bd */
1.10 kristaps 195: { NULL, NULL }, /* Ed */
196: { NULL, termp_bl_post }, /* Bl */
197: { NULL, NULL }, /* El */
198: { termp_it_pre, termp_it_post }, /* It */
199: { NULL, NULL }, /* Ad */
200: { NULL, NULL }, /* An */
1.18 kristaps 201: { termp_ar_pre, NULL }, /* Ar */
202: { termp_cd_pre, NULL }, /* Cd */
203: { termp_cm_pre, NULL }, /* Cm */
1.10 kristaps 204: { NULL, NULL }, /* Dv */
205: { NULL, NULL }, /* Er */
206: { NULL, NULL }, /* Ev */
207: { termp_ex_pre, NULL }, /* Ex */
1.18 kristaps 208: { termp_fa_pre, NULL }, /* Fa */
1.10 kristaps 209: { termp_fd_pre, termp_fd_post }, /* Fd */
1.18 kristaps 210: { termp_fl_pre, NULL }, /* Fl */
1.10 kristaps 211: { termp_fn_pre, termp_fn_post }, /* Fn */
212: { termp_ft_pre, termp_ft_post }, /* Ft */
1.18 kristaps 213: { termp_ic_pre, NULL }, /* Ic */
1.30 kristaps 214: { termp_in_pre, termp_in_post }, /* In */
1.10 kristaps 215: { NULL, NULL }, /* Li */
216: { termp_nd_pre, NULL }, /* Nd */
1.18 kristaps 217: { termp_nm_pre, NULL }, /* Nm */
1.10 kristaps 218: { termp_op_pre, termp_op_post }, /* Op */
219: { NULL, NULL }, /* Ot */
1.18 kristaps 220: { termp_pa_pre, NULL }, /* Pa */
1.14 kristaps 221: { termp_rv_pre, NULL }, /* Rv */
222: { termp_st_pre, NULL }, /* St */
1.18 kristaps 223: { termp_va_pre, NULL }, /* Va */
1.10 kristaps 224: { termp_vt_pre, termp_vt_post }, /* Vt */
225: { termp_xr_pre, NULL }, /* Xr */
1.28 kristaps 226: { NULL, termp____post }, /* %A */
1.29 kristaps 227: { NULL, termp____post }, /* %B */
1.28 kristaps 228: { NULL, termp____post }, /* %D */
1.29 kristaps 229: { NULL, termp____post }, /* %I */
1.28 kristaps 230: { NULL, termp____post }, /* %J */
1.29 kristaps 231: { NULL, termp____post }, /* %N */
232: { NULL, termp____post }, /* %O */
233: { NULL, termp____post }, /* %P */
234: { NULL, termp____post }, /* %R */
1.54 kristaps 235: { termp__t_pre, termp____post }, /* %T */
1.29 kristaps 236: { NULL, termp____post }, /* %V */
1.10 kristaps 237: { NULL, NULL }, /* Ac */
1.14 kristaps 238: { termp_aq_pre, termp_aq_post }, /* Ao */
1.10 kristaps 239: { termp_aq_pre, termp_aq_post }, /* Aq */
1.14 kristaps 240: { termp_at_pre, NULL }, /* At */
1.10 kristaps 241: { NULL, NULL }, /* Bc */
1.18 kristaps 242: { termp_bf_pre, NULL }, /* Bf */
1.15 kristaps 243: { termp_bq_pre, termp_bq_post }, /* Bo */
244: { termp_bq_pre, termp_bq_post }, /* Bq */
245: { termp_bsx_pre, NULL }, /* Bsx */
1.31 kristaps 246: { NULL, termp_bx_post }, /* Bx */
1.10 kristaps 247: { NULL, NULL }, /* Db */
248: { NULL, NULL }, /* Dc */
1.15 kristaps 249: { termp_dq_pre, termp_dq_post }, /* Do */
1.10 kristaps 250: { termp_dq_pre, termp_dq_post }, /* Dq */
251: { NULL, NULL }, /* Ec */
252: { NULL, NULL }, /* Ef */
1.18 kristaps 253: { termp_em_pre, NULL }, /* Em */
1.10 kristaps 254: { NULL, NULL }, /* Eo */
1.16 kristaps 255: { termp_fx_pre, NULL }, /* Fx */
1.18 kristaps 256: { termp_ms_pre, NULL }, /* Ms */
1.10 kristaps 257: { NULL, NULL }, /* No */
258: { termp_ns_pre, NULL }, /* Ns */
259: { termp_nx_pre, NULL }, /* Nx */
260: { termp_ox_pre, NULL }, /* Ox */
261: { NULL, NULL }, /* Pc */
262: { termp_pf_pre, termp_pf_post }, /* Pf */
1.15 kristaps 263: { termp_pq_pre, termp_pq_post }, /* Po */
264: { termp_pq_pre, termp_pq_post }, /* Pq */
1.10 kristaps 265: { NULL, NULL }, /* Qc */
1.16 kristaps 266: { termp_sq_pre, termp_sq_post }, /* Ql */
1.15 kristaps 267: { termp_qq_pre, termp_qq_post }, /* Qo */
1.10 kristaps 268: { termp_qq_pre, termp_qq_post }, /* Qq */
269: { NULL, NULL }, /* Re */
1.28 kristaps 270: { termp_rs_pre, NULL }, /* Rs */
1.10 kristaps 271: { NULL, NULL }, /* Sc */
1.15 kristaps 272: { termp_sq_pre, termp_sq_post }, /* So */
1.10 kristaps 273: { termp_sq_pre, termp_sq_post }, /* Sq */
1.22 kristaps 274: { termp_sm_pre, NULL }, /* Sm */
1.18 kristaps 275: { termp_sx_pre, NULL }, /* Sx */
276: { termp_sy_pre, NULL }, /* Sy */
1.10 kristaps 277: { NULL, NULL }, /* Tn */
1.16 kristaps 278: { termp_ux_pre, NULL }, /* Ux */
1.10 kristaps 279: { NULL, NULL }, /* Xc */
280: { NULL, NULL }, /* Xo */
1.16 kristaps 281: { termp_fo_pre, termp_fo_post }, /* Fo */
1.10 kristaps 282: { NULL, NULL }, /* Fc */
1.16 kristaps 283: { termp_op_pre, termp_op_post }, /* Oo */
1.10 kristaps 284: { NULL, NULL }, /* Oc */
285: { NULL, NULL }, /* Bk */
286: { NULL, NULL }, /* Ek */
1.17 kristaps 287: { termp_bt_pre, NULL }, /* Bt */
1.10 kristaps 288: { NULL, NULL }, /* Hf */
289: { NULL, NULL }, /* Fr */
290: { termp_ud_pre, NULL }, /* Ud */
1.47 kristaps 291: { termp_lb_pre, termp_lb_post }, /* Lb */
1.48 kristaps 292: { termp_ap_pre, NULL }, /* Lb */
1.49 kristaps 293: { termp_pp_pre, NULL }, /* Pp */
1.51 kristaps 294: { termp_lk_pre, NULL }, /* Lk */
295: { termp_mt_pre, NULL }, /* Mt */
1.53 kristaps 296: { termp_brq_pre, termp_brq_post }, /* Brq */
297: { termp_brq_pre, termp_brq_post }, /* Bro */
298: { NULL, NULL }, /* Brc */
1.57 kristaps 299: { NULL, NULL }, /* %C */
1.60 kristaps 300: { NULL, NULL }, /* Es */
301: { NULL, NULL }, /* En */
1.61 kristaps 302: { termp_dx_pre, NULL }, /* Dx */
1.64 ! kristaps 303: { NULL, NULL }, /* %Q */
1.2 kristaps 304: };
305:
1.10 kristaps 306: const struct termact *termacts = __termacts;
307:
308:
309: static size_t
1.54 kristaps 310: arg_width(const struct mdoc_argv *arg, int pos)
1.10 kristaps 311: {
1.27 kristaps 312: size_t v;
313: int i, len;
1.12 kristaps 314:
1.54 kristaps 315: assert(pos < (int)arg->sz && pos >= 0);
316: assert(arg->value[pos]);
317: if (0 == strcmp(arg->value[pos], "indent"))
1.25 kristaps 318: return(INDENT);
1.54 kristaps 319: if (0 == strcmp(arg->value[pos], "indent-two"))
1.25 kristaps 320: return(INDENT * 2);
321:
1.54 kristaps 322: len = (int)strlen(arg->value[pos]);
1.25 kristaps 323: assert(len > 0);
324:
325: for (i = 0; i < len - 1; i++)
1.54 kristaps 326: if ( ! isdigit((u_char)arg->value[pos][i]))
1.25 kristaps 327: break;
328:
329: if (i == len - 1) {
1.54 kristaps 330: if ('n' == arg->value[pos][len - 1]) {
331: v = (size_t)atoi(arg->value[pos]);
1.25 kristaps 332: return(v);
333: }
334:
335: }
1.54 kristaps 336: return(strlen(arg->value[pos]) + 1);
1.12 kristaps 337: }
338:
339:
1.39 kristaps 340: static int
341: arg_listtype(const struct mdoc_node *n)
342: {
343: int i, len;
344:
1.44 kristaps 345: assert(MDOC_BLOCK == n->type);
346:
1.46 kristaps 347: len = (int)(n->args ? n->args->argc : 0);
1.39 kristaps 348:
349: for (i = 0; i < len; i++)
1.44 kristaps 350: switch (n->args->argv[i].arg) {
1.39 kristaps 351: case (MDOC_Bullet):
352: /* FALLTHROUGH */
353: case (MDOC_Dash):
354: /* FALLTHROUGH */
355: case (MDOC_Enum):
356: /* FALLTHROUGH */
357: case (MDOC_Hyphen):
358: /* FALLTHROUGH */
359: case (MDOC_Tag):
360: /* FALLTHROUGH */
361: case (MDOC_Inset):
362: /* FALLTHROUGH */
363: case (MDOC_Diag):
364: /* FALLTHROUGH */
365: case (MDOC_Item):
366: /* FALLTHROUGH */
1.54 kristaps 367: case (MDOC_Column):
368: /* FALLTHROUGH */
1.39 kristaps 369: case (MDOC_Ohang):
1.44 kristaps 370: return(n->args->argv[i].arg);
1.39 kristaps 371: default:
372: break;
373: }
374:
375: errx(1, "list type not supported");
376: /* NOTREACHED */
377: }
378:
379:
1.12 kristaps 380: static size_t
1.44 kristaps 381: arg_offset(const struct mdoc_argv *arg)
1.12 kristaps 382: {
383:
384: /* TODO */
385: assert(*arg->value);
386: if (0 == strcmp(*arg->value, "indent"))
1.10 kristaps 387: return(INDENT);
1.12 kristaps 388: if (0 == strcmp(*arg->value, "indent-two"))
1.10 kristaps 389: return(INDENT * 2);
1.12 kristaps 390: return(strlen(*arg->value));
1.10 kristaps 391: }
392:
1.3 kristaps 393:
1.10 kristaps 394: static int
1.44 kristaps 395: arg_hasattr(int arg, const struct mdoc_node *n)
1.2 kristaps 396: {
397:
1.44 kristaps 398: return(-1 != arg_getattr(arg, n));
1.10 kristaps 399: }
400:
401:
402: static int
1.54 kristaps 403: arg_getattr(int v, const struct mdoc_node *n)
404: {
405: int val;
406:
407: return(arg_getattrs(&v, &val, 1, n) ? val : -1);
408: }
409:
410:
411: static int
412: arg_getattrs(const int *keys, int *vals,
413: size_t sz, const struct mdoc_node *n)
1.10 kristaps 414: {
1.54 kristaps 415: int i, j, k;
1.10 kristaps 416:
1.44 kristaps 417: if (NULL == n->args)
1.54 kristaps 418: return(0);
419:
420: for (k = i = 0; i < (int)n->args->argc; i++)
421: for (j = 0; j < (int)sz; j++)
422: if (n->args->argv[i].arg == keys[j]) {
423: vals[j] = i;
424: k++;
425: }
426: return(k);
1.10 kristaps 427: }
428:
429:
430: /* ARGSUSED */
431: static int
432: termp_dq_pre(DECL_ARGS)
433: {
434:
435: if (MDOC_BODY != node->type)
436: return(1);
437:
1.62 kristaps 438: term_word(p, "\\(lq");
1.10 kristaps 439: p->flags |= TERMP_NOSPACE;
440: return(1);
441: }
442:
443:
444: /* ARGSUSED */
445: static void
446: termp_dq_post(DECL_ARGS)
447: {
448:
449: if (MDOC_BODY != node->type)
450: return;
1.3 kristaps 451:
1.10 kristaps 452: p->flags |= TERMP_NOSPACE;
1.62 kristaps 453: term_word(p, "\\(rq");
1.10 kristaps 454: }
1.2 kristaps 455:
1.3 kristaps 456:
1.10 kristaps 457: /* ARGSUSED */
1.20 kristaps 458: static int
1.39 kristaps 459: termp_it_pre_block(DECL_ARGS)
460: {
461:
1.62 kristaps 462: term_newln(p);
1.44 kristaps 463: if ( ! arg_hasattr(MDOC_Compact, node->parent->parent))
1.62 kristaps 464: term_vspace(p);
1.39 kristaps 465:
466: return(1);
467: }
468:
469:
470: /* ARGSUSED */
471: static int
1.20 kristaps 472: termp_it_pre(DECL_ARGS)
1.10 kristaps 473: {
1.54 kristaps 474: const struct mdoc_node *bl, *n;
475: char buf[7];
476: int i, type, keys[3], vals[3];
477: size_t width, offset;
1.2 kristaps 478:
1.39 kristaps 479: if (MDOC_BLOCK == node->type)
480: return(termp_it_pre_block(p, pair, meta, node));
1.8 kristaps 481:
1.44 kristaps 482: bl = node->parent->parent->parent;
1.23 kristaps 483:
1.39 kristaps 484: /* Save parent attributes. */
1.23 kristaps 485:
1.20 kristaps 486: pair->offset = p->offset;
487: pair->rmargin = p->rmargin;
1.39 kristaps 488: pair->flag = p->flags;
1.20 kristaps 489:
1.23 kristaps 490: /* Get list width and offset. */
491:
1.54 kristaps 492: keys[0] = MDOC_Width;
493: keys[1] = MDOC_Offset;
494: keys[2] = MDOC_Column;
495:
496: vals[0] = vals[1] = vals[2] = -1;
497:
498: width = offset = 0;
499:
500: (void)arg_getattrs(keys, vals, 3, bl);
501:
502: type = arg_listtype(bl);
503:
504: /* Calculate real width and offset. */
1.20 kristaps 505:
1.54 kristaps 506: switch (type) {
507: case (MDOC_Column):
508: if (MDOC_BODY == node->type)
509: break;
510: for (i = 0, n = node->prev; n; n = n->prev, i++)
511: offset += arg_width
512: (&bl->args->argv[vals[2]], i);
513: assert(i < (int)bl->args->argv[vals[2]].sz);
514: width = arg_width(&bl->args->argv[vals[2]], i);
1.56 kristaps 515: if (vals[1] >= 0)
516: offset += arg_offset(&bl->args->argv[vals[1]]);
1.54 kristaps 517: break;
518: default:
519: if (vals[0] >= 0)
520: width = arg_width(&bl->args->argv[vals[0]], 0);
521: if (vals[1] >= 0)
522: offset = arg_offset(&bl->args->argv[vals[1]]);
523: break;
524: }
1.20 kristaps 525:
1.39 kristaps 526: /*
527: * List-type can override the width in the case of fixed-head
528: * values (bullet, dash/hyphen, enum). Tags need a non-zero
529: * offset.
530: */
1.10 kristaps 531:
1.23 kristaps 532: switch (type) {
533: case (MDOC_Bullet):
534: /* FALLTHROUGH */
535: case (MDOC_Dash):
536: /* FALLTHROUGH */
537: case (MDOC_Enum):
538: /* FALLTHROUGH */
539: case (MDOC_Hyphen):
1.55 kristaps 540: if (width < 4)
1.54 kristaps 541: width = 4;
1.23 kristaps 542: break;
543: case (MDOC_Tag):
1.54 kristaps 544: if (0 == width)
545: width = 10;
546: break;
1.23 kristaps 547: default:
548: break;
549: }
1.10 kristaps 550:
1.39 kristaps 551: /*
552: * Whitespace control. Inset bodies need an initial space.
553: */
1.21 kristaps 554:
1.23 kristaps 555: switch (type) {
1.37 kristaps 556: case (MDOC_Diag):
557: /* FALLTHROUGH */
558: case (MDOC_Inset):
1.39 kristaps 559: if (MDOC_BODY == node->type)
560: p->flags &= ~TERMP_NOSPACE;
561: else
562: p->flags |= TERMP_NOSPACE;
563: break;
564: default:
565: p->flags |= TERMP_NOSPACE;
566: break;
567: }
568:
569: /*
570: * Style flags. Diagnostic heads need TTYPE_DIAG.
571: */
572:
573: switch (type) {
574: case (MDOC_Diag):
1.37 kristaps 575: if (MDOC_HEAD == node->type)
1.39 kristaps 576: p->flags |= ttypes[TTYPE_DIAG];
577: break;
578: default:
1.37 kristaps 579: break;
1.39 kristaps 580: }
581:
582: /*
583: * Pad and break control. This is the tricker part. Lists with
584: * set right-margins for the head get TERMP_NOBREAK because, if
585: * they overrun the margin, they wrap to the new margin.
586: * Correspondingly, the body for these types don't left-pad, as
587: * the head will pad out to to the right.
588: */
589:
590: switch (type) {
1.23 kristaps 591: case (MDOC_Bullet):
592: /* FALLTHROUGH */
593: case (MDOC_Dash):
594: /* FALLTHROUGH */
595: case (MDOC_Enum):
596: /* FALLTHROUGH */
597: case (MDOC_Hyphen):
598: /* FALLTHROUGH */
599: case (MDOC_Tag):
600: if (MDOC_HEAD == node->type)
601: p->flags |= TERMP_NOBREAK;
1.39 kristaps 602: else
1.23 kristaps 603: p->flags |= TERMP_NOLPAD;
1.41 kristaps 604: if (MDOC_HEAD == node->type && MDOC_Tag == type)
605: if (NULL == node->next ||
606: NULL == node->next->child)
607: p->flags |= TERMP_NONOBREAK;
1.23 kristaps 608: break;
1.54 kristaps 609: case (MDOC_Column):
610: if (MDOC_HEAD == node->type) {
611: assert(node->next);
612: if (MDOC_BODY == node->next->type)
613: p->flags &= ~TERMP_NOBREAK;
614: else
615: p->flags |= TERMP_NOBREAK;
616: if (node->prev)
617: p->flags |= TERMP_NOLPAD;
618: }
619: break;
1.39 kristaps 620: case (MDOC_Diag):
621: if (MDOC_HEAD == node->type)
622: p->flags |= TERMP_NOBREAK;
623: break;
1.24 kristaps 624: default:
1.23 kristaps 625: break;
626: }
1.21 kristaps 627:
1.23 kristaps 628: /*
1.39 kristaps 629: * Margin control. Set-head-width lists have their right
630: * margins shortened. The body for these lists has the offset
631: * necessarily lengthened. Everybody gets the offset.
1.23 kristaps 632: */
1.21 kristaps 633:
634: p->offset += offset;
1.23 kristaps 635:
636: switch (type) {
637: case (MDOC_Bullet):
638: /* FALLTHROUGH */
639: case (MDOC_Dash):
640: /* FALLTHROUGH */
641: case (MDOC_Enum):
642: /* FALLTHROUGH */
643: case (MDOC_Hyphen):
644: /* FALLTHROUGH */
645: case (MDOC_Tag):
646: if (MDOC_HEAD == node->type)
647: p->rmargin = p->offset + width;
1.39 kristaps 648: else
1.23 kristaps 649: p->offset += width;
1.54 kristaps 650: break;
651: case (MDOC_Column):
652: p->rmargin = p->offset + width;
653: break;
1.24 kristaps 654: default:
1.23 kristaps 655: break;
656: }
657:
1.39 kristaps 658: /*
659: * The dash, hyphen, bullet and enum lists all have a special
660: * HEAD character. Print it now.
661: */
662:
663: if (MDOC_HEAD == node->type)
664: switch (type) {
665: case (MDOC_Bullet):
1.62 kristaps 666: term_word(p, "\\[bu]");
1.39 kristaps 667: break;
668: case (MDOC_Dash):
669: /* FALLTHROUGH */
670: case (MDOC_Hyphen):
1.62 kristaps 671: term_word(p, "\\-");
1.39 kristaps 672: break;
673: case (MDOC_Enum):
674: (pair->ppair->ppair->count)++;
675: (void)snprintf(buf, sizeof(buf), "%d.",
676: pair->ppair->ppair->count);
1.62 kristaps 677: term_word(p, buf);
1.39 kristaps 678: break;
679: default:
680: break;
681: }
682:
683: /*
1.54 kristaps 684: * If we're not going to process our children, indicate so here.
1.39 kristaps 685: */
686:
1.54 kristaps 687: switch (type) {
688: case (MDOC_Bullet):
689: /* FALLTHROUGH */
690: case (MDOC_Item):
691: /* FALLTHROUGH */
692: case (MDOC_Dash):
693: /* FALLTHROUGH */
694: case (MDOC_Hyphen):
695: /* FALLTHROUGH */
696: case (MDOC_Enum):
697: if (MDOC_HEAD == node->type)
698: return(0);
699: break;
700: case (MDOC_Column):
701: if (MDOC_BODY == node->type)
1.39 kristaps 702: return(0);
1.54 kristaps 703: break;
704: default:
705: break;
1.39 kristaps 706: }
1.23 kristaps 707:
1.39 kristaps 708: return(1);
1.10 kristaps 709: }
710:
711:
712: /* ARGSUSED */
1.20 kristaps 713: static void
714: termp_it_post(DECL_ARGS)
1.10 kristaps 715: {
1.39 kristaps 716: int type;
1.3 kristaps 717:
1.21 kristaps 718: if (MDOC_BODY != node->type && MDOC_HEAD != node->type)
1.20 kristaps 719: return;
1.10 kristaps 720:
1.39 kristaps 721: type = arg_listtype(node->parent->parent->parent);
1.37 kristaps 722:
723: switch (type) {
724: case (MDOC_Diag):
725: /* FALLTHROUGH */
1.39 kristaps 726: case (MDOC_Item):
727: /* FALLTHROUGH */
1.37 kristaps 728: case (MDOC_Inset):
1.54 kristaps 729: if (MDOC_BODY == node->type)
1.62 kristaps 730: term_flushln(p);
1.54 kristaps 731: break;
732: case (MDOC_Column):
733: if (MDOC_HEAD == node->type)
1.62 kristaps 734: term_flushln(p);
1.37 kristaps 735: break;
736: default:
1.62 kristaps 737: term_flushln(p);
1.37 kristaps 738: break;
739: }
1.10 kristaps 740:
1.23 kristaps 741: p->offset = pair->offset;
742: p->rmargin = pair->rmargin;
1.39 kristaps 743: p->flags = pair->flag;
1.2 kristaps 744: }
745:
746:
1.10 kristaps 747: /* ARGSUSED */
1.18 kristaps 748: static int
749: termp_nm_pre(DECL_ARGS)
1.10 kristaps 750: {
751:
1.29 kristaps 752: if (SEC_SYNOPSIS == node->sec)
1.62 kristaps 753: term_newln(p);
1.29 kristaps 754:
1.31 kristaps 755: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_PROG]);
1.18 kristaps 756: if (NULL == node->child)
1.62 kristaps 757: term_word(p, meta->name);
1.31 kristaps 758:
1.18 kristaps 759: return(1);
1.10 kristaps 760: }
761:
762:
763: /* ARGSUSED */
1.18 kristaps 764: static int
765: termp_fl_pre(DECL_ARGS)
1.10 kristaps 766: {
767:
1.31 kristaps 768: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
1.62 kristaps 769: term_word(p, "\\-");
1.18 kristaps 770: p->flags |= TERMP_NOSPACE;
771: return(1);
1.10 kristaps 772: }
773:
774:
775: /* ARGSUSED */
776: static int
777: termp_ar_pre(DECL_ARGS)
778: {
779:
1.31 kristaps 780: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_ARG]);
1.10 kristaps 781: return(1);
782: }
783:
784:
785: /* ARGSUSED */
786: static int
787: termp_ns_pre(DECL_ARGS)
1.2 kristaps 788: {
789:
790: p->flags |= TERMP_NOSPACE;
1.10 kristaps 791: return(1);
792: }
793:
794:
795: /* ARGSUSED */
796: static int
797: termp_pp_pre(DECL_ARGS)
798: {
799:
1.62 kristaps 800: term_vspace(p);
1.10 kristaps 801: return(1);
802: }
803:
804:
805: /* ARGSUSED */
806: static int
1.14 kristaps 807: termp_st_pre(DECL_ARGS)
808: {
1.43 kristaps 809: const char *cp;
1.14 kristaps 810:
1.52 kristaps 811: if (node->child && (cp = mdoc_a2st(node->child->string)))
1.62 kristaps 812: term_word(p, cp);
1.43 kristaps 813: return(0);
1.14 kristaps 814: }
815:
816:
817: /* ARGSUSED */
818: static int
1.28 kristaps 819: termp_rs_pre(DECL_ARGS)
820: {
821:
1.30 kristaps 822: if (MDOC_BLOCK == node->type && node->prev)
1.62 kristaps 823: term_vspace(p);
1.28 kristaps 824: return(1);
825: }
826:
827:
828: /* ARGSUSED */
829: static int
1.14 kristaps 830: termp_rv_pre(DECL_ARGS)
831: {
832: int i;
833:
1.44 kristaps 834: if (-1 == (i = arg_getattr(MDOC_Std, node)))
835: errx(1, "expected -std argument");
836: if (1 != node->args->argv[i].sz)
837: errx(1, "expected -std argument");
1.14 kristaps 838:
1.62 kristaps 839: term_newln(p);
840: term_word(p, "The");
1.14 kristaps 841:
842: p->flags |= ttypes[TTYPE_FUNC_NAME];
1.62 kristaps 843: term_word(p, *node->args->argv[i].value);
1.14 kristaps 844: p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1.57 kristaps 845: p->flags |= TERMP_NOSPACE;
1.14 kristaps 846:
1.62 kristaps 847: term_word(p, "() function returns the value 0 if successful;");
848: term_word(p, "otherwise the value -1 is returned and the");
849: term_word(p, "global variable");
1.14 kristaps 850:
851: p->flags |= ttypes[TTYPE_VAR_DECL];
1.62 kristaps 852: term_word(p, "errno");
1.14 kristaps 853: p->flags &= ~ttypes[TTYPE_VAR_DECL];
854:
1.62 kristaps 855: term_word(p, "is set to indicate the error.");
1.14 kristaps 856:
857: return(1);
858: }
859:
860:
861: /* ARGSUSED */
862: static int
1.10 kristaps 863: termp_ex_pre(DECL_ARGS)
864: {
865: int i;
866:
1.44 kristaps 867: if (-1 == (i = arg_getattr(MDOC_Std, node)))
868: errx(1, "expected -std argument");
869: if (1 != node->args->argv[i].sz)
870: errx(1, "expected -std argument");
1.10 kristaps 871:
1.62 kristaps 872: term_word(p, "The");
1.10 kristaps 873: p->flags |= ttypes[TTYPE_PROG];
1.62 kristaps 874: term_word(p, *node->args->argv[i].value);
1.10 kristaps 875: p->flags &= ~ttypes[TTYPE_PROG];
1.62 kristaps 876: term_word(p, "utility exits 0 on success, and >0 if an error occurs.");
1.10 kristaps 877:
878: return(1);
879: }
880:
881:
882: /* ARGSUSED */
883: static int
884: termp_nd_pre(DECL_ARGS)
885: {
886:
1.62 kristaps 887: term_word(p, "\\-");
1.10 kristaps 888: return(1);
889: }
890:
891:
892: /* ARGSUSED */
893: static void
894: termp_bl_post(DECL_ARGS)
895: {
896:
897: if (MDOC_BLOCK == node->type)
1.62 kristaps 898: term_newln(p);
1.10 kristaps 899: }
900:
901:
902: /* ARGSUSED */
903: static void
904: termp_op_post(DECL_ARGS)
905: {
906:
907: if (MDOC_BODY != node->type)
1.2 kristaps 908: return;
1.10 kristaps 909: p->flags |= TERMP_NOSPACE;
1.62 kristaps 910: term_word(p, "\\(rB");
1.10 kristaps 911: }
912:
913:
914: /* ARGSUSED */
915: static int
916: termp_xr_pre(DECL_ARGS)
917: {
918: const struct mdoc_node *n;
919:
1.44 kristaps 920: if (NULL == (n = node->child))
921: errx(1, "expected text line argument");
1.62 kristaps 922: term_word(p, n->string);
1.10 kristaps 923: if (NULL == (n = n->next))
924: return(0);
925: p->flags |= TERMP_NOSPACE;
1.62 kristaps 926: term_word(p, "(");
1.10 kristaps 927: p->flags |= TERMP_NOSPACE;
1.62 kristaps 928: term_word(p, n->string);
1.10 kristaps 929: p->flags |= TERMP_NOSPACE;
1.62 kristaps 930: term_word(p, ")");
1.10 kristaps 931: return(0);
1.2 kristaps 932: }
933:
934:
1.10 kristaps 935: /* ARGSUSED */
936: static int
937: termp_vt_pre(DECL_ARGS)
1.2 kristaps 938: {
939:
1.10 kristaps 940: /* FIXME: this can be "type name". */
1.31 kristaps 941: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
1.10 kristaps 942: return(1);
1.2 kristaps 943: }
944:
945:
1.10 kristaps 946: /* ARGSUSED */
1.2 kristaps 947: static void
1.10 kristaps 948: termp_vt_post(DECL_ARGS)
949: {
950:
951: if (node->sec == SEC_SYNOPSIS)
1.62 kristaps 952: term_vspace(p);
1.10 kristaps 953: }
954:
955:
956: /* ARGSUSED */
957: static int
958: termp_fd_pre(DECL_ARGS)
1.2 kristaps 959: {
960:
1.10 kristaps 961: /*
962: * FIXME: this naming is bad. This value is used, in general,
963: * for the #include header or other preprocessor statement.
964: */
1.31 kristaps 965: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_DECL]);
1.10 kristaps 966: return(1);
1.2 kristaps 967: }
968:
969:
1.10 kristaps 970: /* ARGSUSED */
1.2 kristaps 971: static void
1.10 kristaps 972: termp_fd_post(DECL_ARGS)
1.2 kristaps 973: {
974:
1.30 kristaps 975: if (node->sec != SEC_SYNOPSIS)
976: return;
1.62 kristaps 977: term_newln(p);
1.30 kristaps 978: if (node->next && MDOC_Fd != node->next->tok)
1.62 kristaps 979: term_vspace(p);
1.10 kristaps 980: }
981:
982:
983: /* ARGSUSED */
984: static int
985: termp_sh_pre(DECL_ARGS)
986: {
1.2 kristaps 987:
1.10 kristaps 988: switch (node->type) {
989: case (MDOC_HEAD):
1.62 kristaps 990: term_vspace(p);
1.31 kristaps 991: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SECTION]);
1.2 kristaps 992: break;
1.10 kristaps 993: case (MDOC_BODY):
994: p->offset = INDENT;
1.2 kristaps 995: break;
1.10 kristaps 996: default:
997: break;
998: }
999: return(1);
1000: }
1001:
1002:
1003: /* ARGSUSED */
1.19 kristaps 1004: static void
1005: termp_sh_post(DECL_ARGS)
1006: {
1007:
1008: switch (node->type) {
1009: case (MDOC_HEAD):
1.62 kristaps 1010: term_newln(p);
1.19 kristaps 1011: break;
1012: case (MDOC_BODY):
1.62 kristaps 1013: term_newln(p);
1.19 kristaps 1014: p->offset = 0;
1015: break;
1016: default:
1017: break;
1018: }
1019: }
1020:
1021:
1022: /* ARGSUSED */
1.10 kristaps 1023: static int
1024: termp_op_pre(DECL_ARGS)
1025: {
1026:
1027: switch (node->type) {
1028: case (MDOC_BODY):
1.62 kristaps 1029: term_word(p, "\\(lB");
1.10 kristaps 1030: p->flags |= TERMP_NOSPACE;
1.2 kristaps 1031: break;
1032: default:
1.10 kristaps 1033: break;
1.2 kristaps 1034: }
1.10 kristaps 1035: return(1);
1036: }
1037:
1038:
1039: /* ARGSUSED */
1040: static int
1.17 kristaps 1041: termp_bt_pre(DECL_ARGS)
1042: {
1043:
1.62 kristaps 1044: term_word(p, "is currently in beta test.");
1.17 kristaps 1045: return(1);
1046: }
1047:
1048:
1049: /* ARGSUSED */
1.47 kristaps 1050: static int
1051: termp_lb_pre(DECL_ARGS)
1052: {
1053: const char *lb;
1054:
1055: if (NULL == node->child)
1056: errx(1, "expected text line argument");
1057: if ((lb = mdoc_a2lib(node->child->string))) {
1.62 kristaps 1058: term_word(p, lb);
1.47 kristaps 1059: return(0);
1060: }
1.62 kristaps 1061: term_word(p, "library");
1.47 kristaps 1062: return(1);
1063: }
1064:
1065:
1066: /* ARGSUSED */
1.43 kristaps 1067: static void
1068: termp_lb_post(DECL_ARGS)
1069: {
1070:
1.62 kristaps 1071: term_newln(p);
1.43 kristaps 1072: }
1073:
1074:
1075: /* ARGSUSED */
1.17 kristaps 1076: static int
1.10 kristaps 1077: termp_ud_pre(DECL_ARGS)
1078: {
1079:
1.62 kristaps 1080: term_word(p, "currently under development.");
1.10 kristaps 1081: return(1);
1082: }
1083:
1084:
1085: /* ARGSUSED */
1086: static int
1087: termp_d1_pre(DECL_ARGS)
1088: {
1089:
1090: if (MDOC_BODY != node->type)
1091: return(1);
1.62 kristaps 1092: term_newln(p);
1.19 kristaps 1093: p->offset += (pair->offset = INDENT);
1.10 kristaps 1094: return(1);
1.2 kristaps 1095: }
1096:
1097:
1.10 kristaps 1098: /* ARGSUSED */
1.2 kristaps 1099: static void
1.10 kristaps 1100: termp_d1_post(DECL_ARGS)
1101: {
1102:
1103: if (MDOC_BODY != node->type)
1104: return;
1.62 kristaps 1105: term_newln(p);
1.19 kristaps 1106: p->offset -= pair->offset;
1.10 kristaps 1107: }
1108:
1109:
1110: /* ARGSUSED */
1111: static int
1112: termp_aq_pre(DECL_ARGS)
1.6 kristaps 1113: {
1114:
1.10 kristaps 1115: if (MDOC_BODY != node->type)
1116: return(1);
1.62 kristaps 1117: term_word(p, "\\(la");
1.10 kristaps 1118: p->flags |= TERMP_NOSPACE;
1119: return(1);
1120: }
1.6 kristaps 1121:
1122:
1.10 kristaps 1123: /* ARGSUSED */
1124: static void
1125: termp_aq_post(DECL_ARGS)
1126: {
1.6 kristaps 1127:
1.10 kristaps 1128: if (MDOC_BODY != node->type)
1.6 kristaps 1129: return;
1.10 kristaps 1130: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1131: term_word(p, "\\(ra");
1.10 kristaps 1132: }
1.6 kristaps 1133:
1.10 kristaps 1134:
1135: /* ARGSUSED */
1136: static int
1137: termp_ft_pre(DECL_ARGS)
1138: {
1139:
1.34 kristaps 1140: if (SEC_SYNOPSIS == node->sec)
1141: if (node->prev && MDOC_Fo == node->prev->tok)
1.62 kristaps 1142: term_vspace(p);
1.31 kristaps 1143: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_TYPE]);
1.10 kristaps 1144: return(1);
1.6 kristaps 1145: }
1146:
1147:
1.10 kristaps 1148: /* ARGSUSED */
1.6 kristaps 1149: static void
1.10 kristaps 1150: termp_ft_post(DECL_ARGS)
1.2 kristaps 1151: {
1152:
1.34 kristaps 1153: if (SEC_SYNOPSIS == node->sec)
1.62 kristaps 1154: term_newln(p);
1.10 kristaps 1155: }
1.2 kristaps 1156:
1157:
1.10 kristaps 1158: /* ARGSUSED */
1159: static int
1160: termp_fn_pre(DECL_ARGS)
1161: {
1162: const struct mdoc_node *n;
1163:
1.44 kristaps 1164: if (NULL == node->child)
1165: errx(1, "expected text line arguments");
1.2 kristaps 1166:
1.10 kristaps 1167: /* FIXME: can be "type funcname" "type varname"... */
1.2 kristaps 1168:
1.10 kristaps 1169: p->flags |= ttypes[TTYPE_FUNC_NAME];
1.62 kristaps 1170: term_word(p, node->child->string);
1.10 kristaps 1171: p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1172:
1.62 kristaps 1173: term_word(p, "(");
1.10 kristaps 1174:
1175: p->flags |= TERMP_NOSPACE;
1176: for (n = node->child->next; n; n = n->next) {
1177: p->flags |= ttypes[TTYPE_FUNC_ARG];
1.62 kristaps 1178: term_word(p, n->string);
1.10 kristaps 1179: p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1.16 kristaps 1180: if (n->next)
1.62 kristaps 1181: term_word(p, ",");
1.6 kristaps 1182: }
1.2 kristaps 1183:
1.62 kristaps 1184: term_word(p, ")");
1.10 kristaps 1185:
1186: if (SEC_SYNOPSIS == node->sec)
1.62 kristaps 1187: term_word(p, ";");
1.10 kristaps 1188:
1189: return(0);
1.2 kristaps 1190: }
1191:
1192:
1.10 kristaps 1193: /* ARGSUSED */
1194: static void
1195: termp_fn_post(DECL_ARGS)
1.2 kristaps 1196: {
1197:
1.30 kristaps 1198: if (node->sec == SEC_SYNOPSIS && node->next)
1.62 kristaps 1199: term_vspace(p);
1.10 kristaps 1200:
1201: }
1.2 kristaps 1202:
1203:
1.10 kristaps 1204: /* ARGSUSED */
1205: static int
1206: termp_sx_pre(DECL_ARGS)
1207: {
1.8 kristaps 1208:
1.31 kristaps 1209: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK]);
1.10 kristaps 1210: return(1);
1.2 kristaps 1211: }
1212:
1213:
1.10 kristaps 1214: /* ARGSUSED */
1215: static int
1216: termp_fa_pre(DECL_ARGS)
1217: {
1.16 kristaps 1218: struct mdoc_node *n;
1219:
1220: if (node->parent->tok != MDOC_Fo) {
1.31 kristaps 1221: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_ARG]);
1.16 kristaps 1222: return(1);
1223: }
1224:
1225: for (n = node->child; n; n = n->next) {
1226: p->flags |= ttypes[TTYPE_FUNC_ARG];
1.62 kristaps 1227: term_word(p, n->string);
1.16 kristaps 1228: p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1229: if (n->next)
1.62 kristaps 1230: term_word(p, ",");
1.16 kristaps 1231: }
1232:
1233: if (node->next && node->next->tok == MDOC_Fa)
1.62 kristaps 1234: term_word(p, ",");
1.2 kristaps 1235:
1.16 kristaps 1236: return(0);
1.10 kristaps 1237: }
1.2 kristaps 1238:
1239:
1.10 kristaps 1240: /* ARGSUSED */
1241: static int
1242: termp_va_pre(DECL_ARGS)
1243: {
1.2 kristaps 1244:
1.31 kristaps 1245: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
1.10 kristaps 1246: return(1);
1.2 kristaps 1247: }
1248:
1249:
1.10 kristaps 1250: /* ARGSUSED */
1251: static int
1252: termp_bd_pre(DECL_ARGS)
1253: {
1.62 kristaps 1254: int i, type, ln;
1255:
1256: /*
1257: * This is fairly tricky due primarily to crappy documentation.
1258: * If -ragged or -filled are specified, the block does nothing
1259: * but change the indentation.
1260: *
1261: * If, on the other hand, -unfilled or -literal are specified,
1262: * then the game changes. Text is printed exactly as entered in
1263: * the display: if a macro line, a newline is appended to the
1264: * line. Blank lines are allowed.
1265: */
1.1 kristaps 1266:
1.10 kristaps 1267: if (MDOC_BLOCK == node->type) {
1.54 kristaps 1268: /* FIXME: parent prev? */
1.30 kristaps 1269: if (node->prev)
1.62 kristaps 1270: term_vspace(p);
1.10 kristaps 1271: return(1);
1272: } else if (MDOC_BODY != node->type)
1273: return(1);
1274:
1.44 kristaps 1275: if (NULL == node->parent->args)
1276: errx(1, "missing display type");
1277:
1.20 kristaps 1278: pair->offset = p->offset;
1.10 kristaps 1279:
1.44 kristaps 1280: for (type = -1, i = 0;
1281: i < (int)node->parent->args->argc; i++) {
1282: switch (node->parent->args->argv[i].arg) {
1.35 kristaps 1283: case (MDOC_Ragged):
1284: /* FALLTHROUGH */
1285: case (MDOC_Filled):
1286: /* FALLTHROUGH */
1287: case (MDOC_Unfilled):
1288: /* FALLTHROUGH */
1289: case (MDOC_Literal):
1.44 kristaps 1290: type = node->parent->args->argv[i].arg;
1291: i = (int)node->parent->args->argc;
1.35 kristaps 1292: break;
1293: default:
1.44 kristaps 1294: break;
1.35 kristaps 1295: }
1296: }
1297:
1.44 kristaps 1298: if (NULL == node->parent->args)
1299: errx(1, "missing display type");
1.12 kristaps 1300:
1.44 kristaps 1301: i = arg_getattr(MDOC_Offset, node->parent);
1.12 kristaps 1302: if (-1 != i) {
1.45 kristaps 1303: if (1 != node->parent->args->argv[i].sz)
1.44 kristaps 1304: errx(1, "expected single value");
1.45 kristaps 1305: p->offset += arg_offset(&node->parent->args->argv[i]);
1.12 kristaps 1306: }
1307:
1.35 kristaps 1308: switch (type) {
1309: case (MDOC_Literal):
1310: /* FALLTHROUGH */
1311: case (MDOC_Unfilled):
1312: break;
1313: default:
1314: return(1);
1315: }
1316:
1.62 kristaps 1317: /*
1318: * Tricky. Iterate through all children. If we're on a
1319: * different parse line, append a newline and then the contents.
1320: * Ew.
1321: */
1322:
1.10 kristaps 1323: p->flags |= TERMP_LITERAL;
1.62 kristaps 1324: ln = node->child ? node->child->line : 0;
1.10 kristaps 1325:
1.62 kristaps 1326: for (node = node->child; node; node = node->next) {
1327: if (ln < node->line) {
1328: term_flushln(p);
1329: p->flags |= TERMP_NOSPACE;
1.35 kristaps 1330: }
1.62 kristaps 1331: ln = node->line;
1332: term_node(p, pair, meta, node);
1.10 kristaps 1333: }
1.1 kristaps 1334:
1.10 kristaps 1335: return(0);
1336: }
1.1 kristaps 1337:
1338:
1.10 kristaps 1339: /* ARGSUSED */
1.12 kristaps 1340: static void
1341: termp_bd_post(DECL_ARGS)
1342: {
1343:
1.20 kristaps 1344: if (MDOC_BODY != node->type)
1345: return;
1.35 kristaps 1346:
1.63 kristaps 1347: term_flushln(p);
1.35 kristaps 1348: p->flags &= ~TERMP_LITERAL;
1.20 kristaps 1349: p->offset = pair->offset;
1.62 kristaps 1350: p->flags |= TERMP_NOSPACE;
1.12 kristaps 1351: }
1352:
1353:
1354: /* ARGSUSED */
1.10 kristaps 1355: static int
1356: termp_qq_pre(DECL_ARGS)
1357: {
1.1 kristaps 1358:
1.10 kristaps 1359: if (MDOC_BODY != node->type)
1360: return(1);
1.62 kristaps 1361: term_word(p, "\"");
1.10 kristaps 1362: p->flags |= TERMP_NOSPACE;
1363: return(1);
1.1 kristaps 1364: }
1365:
1366:
1.10 kristaps 1367: /* ARGSUSED */
1.1 kristaps 1368: static void
1.10 kristaps 1369: termp_qq_post(DECL_ARGS)
1.1 kristaps 1370: {
1371:
1.10 kristaps 1372: if (MDOC_BODY != node->type)
1373: return;
1374: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1375: term_word(p, "\"");
1.10 kristaps 1376: }
1377:
1378:
1379: /* ARGSUSED */
1380: static int
1.15 kristaps 1381: termp_bsx_pre(DECL_ARGS)
1382: {
1383:
1.62 kristaps 1384: term_word(p, "BSDI BSD/OS");
1.15 kristaps 1385: return(1);
1386: }
1387:
1388:
1389: /* ARGSUSED */
1.31 kristaps 1390: static void
1391: termp_bx_post(DECL_ARGS)
1.10 kristaps 1392: {
1.1 kristaps 1393:
1.34 kristaps 1394: if (node->child)
1395: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1396: term_word(p, "BSD");
1.10 kristaps 1397: }
1398:
1399:
1400: /* ARGSUSED */
1401: static int
1402: termp_ox_pre(DECL_ARGS)
1403: {
1404:
1.62 kristaps 1405: term_word(p, "OpenBSD");
1.10 kristaps 1406: return(1);
1407: }
1408:
1409:
1410: /* ARGSUSED */
1411: static int
1.61 kristaps 1412: termp_dx_pre(DECL_ARGS)
1413: {
1414:
1.62 kristaps 1415: term_word(p, "DragonFly");
1.61 kristaps 1416: return(1);
1417: }
1418:
1419:
1420: /* ARGSUSED */
1421: static int
1.16 kristaps 1422: termp_ux_pre(DECL_ARGS)
1423: {
1424:
1.62 kristaps 1425: term_word(p, "UNIX");
1.16 kristaps 1426: return(1);
1427: }
1428:
1429:
1430: /* ARGSUSED */
1431: static int
1432: termp_fx_pre(DECL_ARGS)
1433: {
1434:
1.62 kristaps 1435: term_word(p, "FreeBSD");
1.16 kristaps 1436: return(1);
1437: }
1438:
1439:
1440: /* ARGSUSED */
1441: static int
1.10 kristaps 1442: termp_nx_pre(DECL_ARGS)
1443: {
1444:
1.62 kristaps 1445: term_word(p, "NetBSD");
1.10 kristaps 1446: return(1);
1447: }
1448:
1449:
1450: /* ARGSUSED */
1451: static int
1452: termp_sq_pre(DECL_ARGS)
1453: {
1454:
1455: if (MDOC_BODY != node->type)
1456: return(1);
1.62 kristaps 1457: term_word(p, "\\(oq");
1.10 kristaps 1458: p->flags |= TERMP_NOSPACE;
1459: return(1);
1460: }
1.1 kristaps 1461:
1462:
1.10 kristaps 1463: /* ARGSUSED */
1464: static void
1465: termp_sq_post(DECL_ARGS)
1466: {
1467:
1468: if (MDOC_BODY != node->type)
1469: return;
1470: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1471: term_word(p, "\\(aq");
1.10 kristaps 1472: }
1.2 kristaps 1473:
1474:
1.10 kristaps 1475: /* ARGSUSED */
1476: static int
1477: termp_pf_pre(DECL_ARGS)
1478: {
1.1 kristaps 1479:
1.10 kristaps 1480: p->flags |= TERMP_IGNDELIM;
1481: return(1);
1482: }
1.1 kristaps 1483:
1484:
1.10 kristaps 1485: /* ARGSUSED */
1486: static void
1487: termp_pf_post(DECL_ARGS)
1488: {
1.1 kristaps 1489:
1.10 kristaps 1490: p->flags &= ~TERMP_IGNDELIM;
1491: p->flags |= TERMP_NOSPACE;
1492: }
1.1 kristaps 1493:
1494:
1.10 kristaps 1495: /* ARGSUSED */
1496: static int
1497: termp_ss_pre(DECL_ARGS)
1498: {
1.1 kristaps 1499:
1.10 kristaps 1500: switch (node->type) {
1.58 kristaps 1501: case (MDOC_BLOCK):
1.62 kristaps 1502: term_newln(p);
1.58 kristaps 1503: if (node->prev)
1.62 kristaps 1504: term_vspace(p);
1.58 kristaps 1505: break;
1.10 kristaps 1506: case (MDOC_HEAD):
1.31 kristaps 1507: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SSECTION]);
1.10 kristaps 1508: p->offset = INDENT / 2;
1509: break;
1510: default:
1511: break;
1512: }
1.1 kristaps 1513:
1.10 kristaps 1514: return(1);
1.1 kristaps 1515: }
1516:
1517:
1.10 kristaps 1518: /* ARGSUSED */
1519: static void
1520: termp_ss_post(DECL_ARGS)
1.1 kristaps 1521: {
1522:
1.10 kristaps 1523: switch (node->type) {
1524: case (MDOC_HEAD):
1.62 kristaps 1525: term_newln(p);
1.10 kristaps 1526: p->offset = INDENT;
1527: break;
1528: default:
1529: break;
1530: }
1531: }
1.2 kristaps 1532:
1533:
1.10 kristaps 1534: /* ARGSUSED */
1535: static int
1536: termp_pa_pre(DECL_ARGS)
1537: {
1.2 kristaps 1538:
1.31 kristaps 1539: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FILE]);
1.10 kristaps 1540: return(1);
1.1 kristaps 1541: }
1542:
1543:
1.10 kristaps 1544: /* ARGSUSED */
1.11 kristaps 1545: static int
1546: termp_em_pre(DECL_ARGS)
1547: {
1548:
1.31 kristaps 1549: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.11 kristaps 1550: return(1);
1551: }
1552:
1553:
1554: /* ARGSUSED */
1.14 kristaps 1555: static int
1556: termp_cd_pre(DECL_ARGS)
1557: {
1558:
1.31 kristaps 1559: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CONFIG]);
1.62 kristaps 1560: term_newln(p);
1.14 kristaps 1561: return(1);
1562: }
1563:
1564:
1565: /* ARGSUSED */
1566: static int
1567: termp_cm_pre(DECL_ARGS)
1568: {
1569:
1.31 kristaps 1570: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
1.14 kristaps 1571: return(1);
1572: }
1573:
1574:
1575: /* ARGSUSED */
1576: static int
1577: termp_ic_pre(DECL_ARGS)
1578: {
1579:
1.31 kristaps 1580: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD]);
1.14 kristaps 1581: return(1);
1582: }
1583:
1584:
1585: /* ARGSUSED */
1586: static int
1587: termp_in_pre(DECL_ARGS)
1588: {
1589:
1.31 kristaps 1590: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_INCLUDE]);
1.62 kristaps 1591: term_word(p, "#include");
1592: term_word(p, "<");
1.30 kristaps 1593: p->flags |= TERMP_NOSPACE;
1.14 kristaps 1594: return(1);
1595: }
1596:
1597:
1598: /* ARGSUSED */
1.30 kristaps 1599: static void
1600: termp_in_post(DECL_ARGS)
1601: {
1602:
1603: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1604: term_word(p, ">");
1.30 kristaps 1605:
1.62 kristaps 1606: term_newln(p);
1.30 kristaps 1607: if (SEC_SYNOPSIS != node->sec)
1608: return;
1609: if (node->next && MDOC_In != node->next->tok)
1.62 kristaps 1610: term_vspace(p);
1.30 kristaps 1611: }
1612:
1613:
1614: /* ARGSUSED */
1.14 kristaps 1615: static int
1616: termp_at_pre(DECL_ARGS)
1617: {
1.43 kristaps 1618: const char *att;
1619:
1620: att = NULL;
1.14 kristaps 1621:
1.52 kristaps 1622: if (node->child)
1.44 kristaps 1623: att = mdoc_a2att(node->child->string);
1.43 kristaps 1624: if (NULL == att)
1625: att = "AT&T UNIX";
1626:
1.62 kristaps 1627: term_word(p, att);
1.14 kristaps 1628: return(0);
1629: }
1.15 kristaps 1630:
1631:
1632: /* ARGSUSED */
1633: static int
1.53 kristaps 1634: termp_brq_pre(DECL_ARGS)
1635: {
1636:
1637: if (MDOC_BODY != node->type)
1638: return(1);
1.62 kristaps 1639: term_word(p, "\\(lC");
1.53 kristaps 1640: p->flags |= TERMP_NOSPACE;
1641: return(1);
1642: }
1643:
1644:
1645: /* ARGSUSED */
1646: static void
1647: termp_brq_post(DECL_ARGS)
1648: {
1649:
1650: if (MDOC_BODY != node->type)
1651: return;
1652: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1653: term_word(p, "\\(rC");
1.53 kristaps 1654: }
1655:
1656:
1657: /* ARGSUSED */
1658: static int
1.15 kristaps 1659: termp_bq_pre(DECL_ARGS)
1660: {
1661:
1662: if (MDOC_BODY != node->type)
1663: return(1);
1.62 kristaps 1664: term_word(p, "\\(lB");
1.15 kristaps 1665: p->flags |= TERMP_NOSPACE;
1666: return(1);
1667: }
1668:
1669:
1670: /* ARGSUSED */
1671: static void
1672: termp_bq_post(DECL_ARGS)
1673: {
1674:
1675: if (MDOC_BODY != node->type)
1676: return;
1.53 kristaps 1677: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1678: term_word(p, "\\(rB");
1.15 kristaps 1679: }
1680:
1681:
1682: /* ARGSUSED */
1683: static int
1684: termp_pq_pre(DECL_ARGS)
1685: {
1686:
1687: if (MDOC_BODY != node->type)
1688: return(1);
1.62 kristaps 1689: term_word(p, "\\&(");
1.15 kristaps 1690: p->flags |= TERMP_NOSPACE;
1691: return(1);
1692: }
1693:
1694:
1695: /* ARGSUSED */
1696: static void
1697: termp_pq_post(DECL_ARGS)
1698: {
1699:
1700: if (MDOC_BODY != node->type)
1701: return;
1.62 kristaps 1702: term_word(p, ")");
1.15 kristaps 1703: }
1704:
1705:
1.16 kristaps 1706: /* ARGSUSED */
1707: static int
1708: termp_fo_pre(DECL_ARGS)
1709: {
1710: const struct mdoc_node *n;
1711:
1712: if (MDOC_BODY == node->type) {
1.62 kristaps 1713: term_word(p, "(");
1.16 kristaps 1714: p->flags |= TERMP_NOSPACE;
1715: return(1);
1716: } else if (MDOC_HEAD != node->type)
1717: return(1);
1718:
1.17 kristaps 1719: /* XXX - groff shows only first parameter */
1720:
1.16 kristaps 1721: p->flags |= ttypes[TTYPE_FUNC_NAME];
1722: for (n = node->child; n; n = n->next) {
1.44 kristaps 1723: if (MDOC_TEXT != n->type)
1724: errx(1, "expected text line argument");
1.62 kristaps 1725: term_word(p, n->string);
1.16 kristaps 1726: }
1727: p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1728:
1729: return(0);
1730: }
1731:
1732:
1733: /* ARGSUSED */
1734: static void
1735: termp_fo_post(DECL_ARGS)
1736: {
1737:
1738: if (MDOC_BODY != node->type)
1739: return;
1.53 kristaps 1740: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1741: term_word(p, ")");
1.53 kristaps 1742: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1743: term_word(p, ";");
1744: term_newln(p);
1.16 kristaps 1745: }
1746:
1747:
1.17 kristaps 1748: /* ARGSUSED */
1749: static int
1750: termp_bf_pre(DECL_ARGS)
1751: {
1752: const struct mdoc_node *n;
1753:
1.44 kristaps 1754: if (MDOC_HEAD == node->type) {
1.17 kristaps 1755: return(0);
1.44 kristaps 1756: } else if (MDOC_BLOCK != node->type)
1.17 kristaps 1757: return(1);
1758:
1.44 kristaps 1759: if (NULL == (n = node->head->child)) {
1760: if (arg_hasattr(MDOC_Emphasis, node))
1.31 kristaps 1761: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.44 kristaps 1762: else if (arg_hasattr(MDOC_Symbolic, node))
1.31 kristaps 1763: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1.17 kristaps 1764:
1765: return(1);
1766: }
1767:
1.44 kristaps 1768: if (MDOC_TEXT != n->type)
1769: errx(1, "expected text line arguments");
1.17 kristaps 1770:
1.44 kristaps 1771: if (0 == strcmp("Em", n->string))
1.31 kristaps 1772: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.44 kristaps 1773: else if (0 == strcmp("Sy", n->string))
1.31 kristaps 1774: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.17 kristaps 1775:
1776: return(1);
1777: }
1778:
1779:
1780: /* ARGSUSED */
1781: static int
1782: termp_sy_pre(DECL_ARGS)
1783: {
1784:
1.31 kristaps 1785: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1.17 kristaps 1786: return(1);
1787: }
1788:
1789:
1790: /* ARGSUSED */
1791: static int
1792: termp_ms_pre(DECL_ARGS)
1793: {
1794:
1.31 kristaps 1795: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMBOL]);
1.17 kristaps 1796: return(1);
1797: }
1798:
1.22 kristaps 1799:
1800:
1801: /* ARGSUSED */
1802: static int
1803: termp_sm_pre(DECL_ARGS)
1804: {
1805:
1806: #if notyet
1807: assert(node->child);
1808: if (0 == strcmp("off", node->child->data.text.string)) {
1809: p->flags &= ~TERMP_NONOSPACE;
1810: p->flags &= ~TERMP_NOSPACE;
1811: } else {
1812: p->flags |= TERMP_NONOSPACE;
1813: p->flags |= TERMP_NOSPACE;
1814: }
1815: #endif
1816:
1817: return(0);
1818: }
1.28 kristaps 1819:
1820:
1821: /* ARGSUSED */
1822: static int
1.48 kristaps 1823: termp_ap_pre(DECL_ARGS)
1824: {
1825:
1826: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1827: term_word(p, "\\(aq");
1.48 kristaps 1828: p->flags |= TERMP_NOSPACE;
1829: return(1);
1830: }
1831:
1832:
1833: /* ARGSUSED */
1834: static int
1.28 kristaps 1835: termp__t_pre(DECL_ARGS)
1836: {
1837:
1.54 kristaps 1838: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_REF_TITLE]);
1.28 kristaps 1839: return(1);
1840: }
1841:
1842:
1843: /* ARGSUSED */
1844: static void
1845: termp____post(DECL_ARGS)
1846: {
1847:
1848: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1849: term_word(p, node->next ? "," : ".");
1.28 kristaps 1850: }
1.51 kristaps 1851:
1852:
1853: /* ARGSUSED */
1854: static int
1855: termp_lk_pre(DECL_ARGS)
1856: {
1857: const struct mdoc_node *n;
1858:
1859: if (NULL == (n = node->child))
1.52 kristaps 1860: errx(1, "expected line argument");
1.51 kristaps 1861:
1862: p->flags |= ttypes[TTYPE_LINK_ANCHOR];
1.62 kristaps 1863: term_word(p, n->string);
1.51 kristaps 1864: p->flags &= ~ttypes[TTYPE_LINK_ANCHOR];
1865: p->flags |= TERMP_NOSPACE;
1.62 kristaps 1866: term_word(p, ":");
1.51 kristaps 1867:
1868: p->flags |= ttypes[TTYPE_LINK_TEXT];
1869: for ( ; n; n = n->next) {
1.62 kristaps 1870: term_word(p, n->string);
1.51 kristaps 1871: }
1872: p->flags &= ~ttypes[TTYPE_LINK_TEXT];
1873:
1874: return(0);
1875: }
1876:
1877:
1878: /* ARGSUSED */
1879: static int
1880: termp_mt_pre(DECL_ARGS)
1881: {
1882:
1883: TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK_ANCHOR]);
1884: return(1);
1885: }
1886:
CVSweb