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