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