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