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