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