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