]> git.cameronkatri.com Git - mandoc.git/blob - term.c
Brq/Bro/Brc fixed up and pretty.
[mandoc.git] / term.c
1 /* $Id: term.c,v 1.54 2009/03/12 02:57:36 kristaps Exp $ */
2 /*
3 * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <sys/types.h>
20
21 #include <assert.h>
22 #include <ctype.h>
23 #include <err.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "term.h"
29
30 /*
31 * Performs actions on nodes of the abstract syntax tree. Both pre- and
32 * post-fix operations are defined here.
33 */
34
35 /* FIXME: macro arguments can be escaped. */
36
37 #define TTYPE_PROG 0
38 #define TTYPE_CMD_FLAG 1
39 #define TTYPE_CMD_ARG 2
40 #define TTYPE_SECTION 3
41 #define TTYPE_FUNC_DECL 4
42 #define TTYPE_VAR_DECL 5
43 #define TTYPE_FUNC_TYPE 6
44 #define TTYPE_FUNC_NAME 7
45 #define TTYPE_FUNC_ARG 8
46 #define TTYPE_LINK 9
47 #define TTYPE_SSECTION 10
48 #define TTYPE_FILE 11
49 #define TTYPE_EMPH 12
50 #define TTYPE_CONFIG 13
51 #define TTYPE_CMD 14
52 #define TTYPE_INCLUDE 15
53 #define TTYPE_SYMB 16
54 #define TTYPE_SYMBOL 17
55 #define TTYPE_DIAG 18
56 #define TTYPE_LINK_ANCHOR 19
57 #define TTYPE_LINK_TEXT 20
58 #define TTYPE_REF_TITLE 21
59 #define TTYPE_NMAX 22
60
61 /*
62 * These define "styles" for element types, like command arguments or
63 * executable names. This is useful when multiple macros must decorate
64 * the same thing (like .Ex -std cmd and .Nm cmd).
65 */
66
67 /* TODO: abstract this into mdocterm.c. */
68
69 const int ttypes[TTYPE_NMAX] = {
70 TERMP_BOLD, /* TTYPE_PROG */
71 TERMP_BOLD, /* TTYPE_CMD_FLAG */
72 TERMP_UNDERLINE, /* TTYPE_CMD_ARG */
73 TERMP_BOLD, /* TTYPE_SECTION */
74 TERMP_BOLD, /* TTYPE_FUNC_DECL */
75 TERMP_UNDERLINE, /* TTYPE_VAR_DECL */
76 TERMP_UNDERLINE, /* TTYPE_FUNC_TYPE */
77 TERMP_BOLD, /* TTYPE_FUNC_NAME */
78 TERMP_UNDERLINE, /* TTYPE_FUNC_ARG */
79 TERMP_UNDERLINE, /* TTYPE_LINK */
80 TERMP_BOLD, /* TTYPE_SSECTION */
81 TERMP_UNDERLINE, /* TTYPE_FILE */
82 TERMP_UNDERLINE, /* TTYPE_EMPH */
83 TERMP_BOLD, /* TTYPE_CONFIG */
84 TERMP_BOLD, /* TTYPE_CMD */
85 TERMP_BOLD, /* TTYPE_INCLUDE */
86 TERMP_BOLD, /* TTYPE_SYMB */
87 TERMP_BOLD, /* TTYPE_SYMBOL */
88 TERMP_BOLD, /* TTYPE_DIAG */
89 TERMP_UNDERLINE, /* TTYPE_LINK_ANCHOR */
90 TERMP_BOLD, /* TTYPE_LINK_TEXT */
91 TERMP_UNDERLINE /* TTYPE_REF_TITLE */
92 };
93
94 static int arg_hasattr(int, const struct mdoc_node *);
95 static int arg_getattrs(const int *, int *, size_t,
96 const struct mdoc_node *);
97 static int arg_getattr(int, const struct mdoc_node *);
98 static size_t arg_offset(const struct mdoc_argv *);
99 static size_t arg_width(const struct mdoc_argv *, int);
100 static int arg_listtype(const struct mdoc_node *);
101
102 /*
103 * What follows describes prefix and postfix operations for the abstract
104 * syntax tree descent.
105 */
106
107 #define DECL_ARGS \
108 struct termp *p, \
109 struct termpair *pair, \
110 const struct mdoc_meta *meta, \
111 const struct mdoc_node *node
112
113 #define DECL_PRE(name) \
114 static int name##_pre(DECL_ARGS)
115 #define DECL_POST(name) \
116 static void name##_post(DECL_ARGS)
117 #define DECL_PREPOST(name) \
118 DECL_PRE(name); \
119 DECL_POST(name);
120
121 DECL_PREPOST(termp_aq);
122 DECL_PREPOST(termp_bd);
123 DECL_PREPOST(termp_bq);
124 DECL_PREPOST(termp_brq);
125 DECL_PREPOST(termp_d1);
126 DECL_PREPOST(termp_dq);
127 DECL_PREPOST(termp_fd);
128 DECL_PREPOST(termp_fn);
129 DECL_PREPOST(termp_fo);
130 DECL_PREPOST(termp_ft);
131 DECL_PREPOST(termp_in);
132 DECL_PREPOST(termp_it);
133 DECL_PREPOST(termp_lb);
134 DECL_PREPOST(termp_op);
135 DECL_PREPOST(termp_pf);
136 DECL_PREPOST(termp_pq);
137 DECL_PREPOST(termp_qq);
138 DECL_PREPOST(termp_sh);
139 DECL_PREPOST(termp_ss);
140 DECL_PREPOST(termp_sq);
141 DECL_PREPOST(termp_vt);
142
143 DECL_PRE(termp__t);
144 DECL_PRE(termp_ap);
145 DECL_PRE(termp_ar);
146 DECL_PRE(termp_at);
147 DECL_PRE(termp_bf);
148 DECL_PRE(termp_bsx);
149 DECL_PRE(termp_bt);
150 DECL_PRE(termp_cd);
151 DECL_PRE(termp_cm);
152 DECL_PRE(termp_em);
153 DECL_PRE(termp_ex);
154 DECL_PRE(termp_fa);
155 DECL_PRE(termp_fl);
156 DECL_PRE(termp_fx);
157 DECL_PRE(termp_ic);
158 DECL_PRE(termp_lk);
159 DECL_PRE(termp_ms);
160 DECL_PRE(termp_mt);
161 DECL_PRE(termp_nd);
162 DECL_PRE(termp_nm);
163 DECL_PRE(termp_ns);
164 DECL_PRE(termp_nx);
165 DECL_PRE(termp_ox);
166 DECL_PRE(termp_pa);
167 DECL_PRE(termp_pp);
168 DECL_PRE(termp_rs);
169 DECL_PRE(termp_rv);
170 DECL_PRE(termp_sm);
171 DECL_PRE(termp_st);
172 DECL_PRE(termp_sx);
173 DECL_PRE(termp_sy);
174 DECL_PRE(termp_ud);
175 DECL_PRE(termp_ux);
176 DECL_PRE(termp_va);
177 DECL_PRE(termp_xr);
178
179 DECL_POST(termp___);
180 DECL_POST(termp_bl);
181 DECL_POST(termp_bx);
182
183 const struct termact __termacts[MDOC_MAX] = {
184 { NULL, NULL }, /* \" */
185 { NULL, NULL }, /* Dd */
186 { NULL, NULL }, /* Dt */
187 { NULL, NULL }, /* Os */
188 { termp_sh_pre, termp_sh_post }, /* Sh */
189 { termp_ss_pre, termp_ss_post }, /* Ss */
190 { termp_pp_pre, NULL }, /* Pp */
191 { termp_d1_pre, termp_d1_post }, /* D1 */
192 { termp_d1_pre, termp_d1_post }, /* Dl */
193 { termp_bd_pre, termp_bd_post }, /* Bd */
194 { NULL, NULL }, /* Ed */
195 { NULL, termp_bl_post }, /* Bl */
196 { NULL, NULL }, /* El */
197 { termp_it_pre, termp_it_post }, /* It */
198 { NULL, NULL }, /* Ad */
199 { NULL, NULL }, /* An */
200 { termp_ar_pre, NULL }, /* Ar */
201 { termp_cd_pre, NULL }, /* Cd */
202 { termp_cm_pre, NULL }, /* Cm */
203 { NULL, NULL }, /* Dv */
204 { NULL, NULL }, /* Er */
205 { NULL, NULL }, /* Ev */
206 { termp_ex_pre, NULL }, /* Ex */
207 { termp_fa_pre, NULL }, /* Fa */
208 { termp_fd_pre, termp_fd_post }, /* Fd */
209 { termp_fl_pre, NULL }, /* Fl */
210 { termp_fn_pre, termp_fn_post }, /* Fn */
211 { termp_ft_pre, termp_ft_post }, /* Ft */
212 { termp_ic_pre, NULL }, /* Ic */
213 { termp_in_pre, termp_in_post }, /* In */
214 { NULL, NULL }, /* Li */
215 { termp_nd_pre, NULL }, /* Nd */
216 { termp_nm_pre, NULL }, /* Nm */
217 { termp_op_pre, termp_op_post }, /* Op */
218 { NULL, NULL }, /* Ot */
219 { termp_pa_pre, NULL }, /* Pa */
220 { termp_rv_pre, NULL }, /* Rv */
221 { termp_st_pre, NULL }, /* St */
222 { termp_va_pre, NULL }, /* Va */
223 { termp_vt_pre, termp_vt_post }, /* Vt */
224 { termp_xr_pre, NULL }, /* Xr */
225 { NULL, termp____post }, /* %A */
226 { NULL, termp____post }, /* %B */
227 { NULL, termp____post }, /* %D */
228 { NULL, termp____post }, /* %I */
229 { NULL, termp____post }, /* %J */
230 { NULL, termp____post }, /* %N */
231 { NULL, termp____post }, /* %O */
232 { NULL, termp____post }, /* %P */
233 { NULL, termp____post }, /* %R */
234 { termp__t_pre, termp____post }, /* %T */
235 { NULL, termp____post }, /* %V */
236 { NULL, NULL }, /* Ac */
237 { termp_aq_pre, termp_aq_post }, /* Ao */
238 { termp_aq_pre, termp_aq_post }, /* Aq */
239 { termp_at_pre, NULL }, /* At */
240 { NULL, NULL }, /* Bc */
241 { termp_bf_pre, NULL }, /* Bf */
242 { termp_bq_pre, termp_bq_post }, /* Bo */
243 { termp_bq_pre, termp_bq_post }, /* Bq */
244 { termp_bsx_pre, NULL }, /* Bsx */
245 { NULL, termp_bx_post }, /* Bx */
246 { NULL, NULL }, /* Db */
247 { NULL, NULL }, /* Dc */
248 { termp_dq_pre, termp_dq_post }, /* Do */
249 { termp_dq_pre, termp_dq_post }, /* Dq */
250 { NULL, NULL }, /* Ec */
251 { NULL, NULL }, /* Ef */
252 { termp_em_pre, NULL }, /* Em */
253 { NULL, NULL }, /* Eo */
254 { termp_fx_pre, NULL }, /* Fx */
255 { termp_ms_pre, NULL }, /* Ms */
256 { NULL, NULL }, /* No */
257 { termp_ns_pre, NULL }, /* Ns */
258 { termp_nx_pre, NULL }, /* Nx */
259 { termp_ox_pre, NULL }, /* Ox */
260 { NULL, NULL }, /* Pc */
261 { termp_pf_pre, termp_pf_post }, /* Pf */
262 { termp_pq_pre, termp_pq_post }, /* Po */
263 { termp_pq_pre, termp_pq_post }, /* Pq */
264 { NULL, NULL }, /* Qc */
265 { termp_sq_pre, termp_sq_post }, /* Ql */
266 { termp_qq_pre, termp_qq_post }, /* Qo */
267 { termp_qq_pre, termp_qq_post }, /* Qq */
268 { NULL, NULL }, /* Re */
269 { termp_rs_pre, NULL }, /* Rs */
270 { NULL, NULL }, /* Sc */
271 { termp_sq_pre, termp_sq_post }, /* So */
272 { termp_sq_pre, termp_sq_post }, /* Sq */
273 { termp_sm_pre, NULL }, /* Sm */
274 { termp_sx_pre, NULL }, /* Sx */
275 { termp_sy_pre, NULL }, /* Sy */
276 { NULL, NULL }, /* Tn */
277 { termp_ux_pre, NULL }, /* Ux */
278 { NULL, NULL }, /* Xc */
279 { NULL, NULL }, /* Xo */
280 { termp_fo_pre, termp_fo_post }, /* Fo */
281 { NULL, NULL }, /* Fc */
282 { termp_op_pre, termp_op_post }, /* Oo */
283 { NULL, NULL }, /* Oc */
284 { NULL, NULL }, /* Bk */
285 { NULL, NULL }, /* Ek */
286 { termp_bt_pre, NULL }, /* Bt */
287 { NULL, NULL }, /* Hf */
288 { NULL, NULL }, /* Fr */
289 { termp_ud_pre, NULL }, /* Ud */
290 { termp_lb_pre, termp_lb_post }, /* Lb */
291 { termp_ap_pre, NULL }, /* Lb */
292 { termp_pp_pre, NULL }, /* Pp */
293 { termp_lk_pre, NULL }, /* Lk */
294 { termp_mt_pre, NULL }, /* Mt */
295 { termp_brq_pre, termp_brq_post }, /* Brq */
296 { termp_brq_pre, termp_brq_post }, /* Bro */
297 { NULL, NULL }, /* Brc */
298 };
299
300 const struct termact *termacts = __termacts;
301
302
303 static size_t
304 arg_width(const struct mdoc_argv *arg, int pos)
305 {
306 size_t v;
307 int i, len;
308
309 assert(pos < (int)arg->sz && pos >= 0);
310 assert(arg->value[pos]);
311 if (0 == strcmp(arg->value[pos], "indent"))
312 return(INDENT);
313 if (0 == strcmp(arg->value[pos], "indent-two"))
314 return(INDENT * 2);
315
316 len = (int)strlen(arg->value[pos]);
317 assert(len > 0);
318
319 for (i = 0; i < len - 1; i++)
320 if ( ! isdigit((u_char)arg->value[pos][i]))
321 break;
322
323 if (i == len - 1) {
324 if ('n' == arg->value[pos][len - 1]) {
325 v = (size_t)atoi(arg->value[pos]);
326 return(v);
327 }
328
329 }
330 return(strlen(arg->value[pos]) + 1);
331 }
332
333
334 static int
335 arg_listtype(const struct mdoc_node *n)
336 {
337 int i, len;
338
339 assert(MDOC_BLOCK == n->type);
340
341 len = (int)(n->args ? n->args->argc : 0);
342
343 for (i = 0; i < len; i++)
344 switch (n->args->argv[i].arg) {
345 case (MDOC_Bullet):
346 /* FALLTHROUGH */
347 case (MDOC_Dash):
348 /* FALLTHROUGH */
349 case (MDOC_Enum):
350 /* FALLTHROUGH */
351 case (MDOC_Hyphen):
352 /* FALLTHROUGH */
353 case (MDOC_Tag):
354 /* FALLTHROUGH */
355 case (MDOC_Inset):
356 /* FALLTHROUGH */
357 case (MDOC_Diag):
358 /* FALLTHROUGH */
359 case (MDOC_Item):
360 /* FALLTHROUGH */
361 case (MDOC_Column):
362 /* FALLTHROUGH */
363 case (MDOC_Ohang):
364 return(n->args->argv[i].arg);
365 default:
366 break;
367 }
368
369 errx(1, "list type not supported");
370 /* NOTREACHED */
371 }
372
373
374 static size_t
375 arg_offset(const struct mdoc_argv *arg)
376 {
377
378 /* TODO */
379 assert(*arg->value);
380 if (0 == strcmp(*arg->value, "indent"))
381 return(INDENT);
382 if (0 == strcmp(*arg->value, "indent-two"))
383 return(INDENT * 2);
384 return(strlen(*arg->value));
385 }
386
387
388 static int
389 arg_hasattr(int arg, const struct mdoc_node *n)
390 {
391
392 return(-1 != arg_getattr(arg, n));
393 }
394
395
396 static int
397 arg_getattr(int v, const struct mdoc_node *n)
398 {
399 int val;
400
401 return(arg_getattrs(&v, &val, 1, n) ? val : -1);
402 }
403
404
405 static int
406 arg_getattrs(const int *keys, int *vals,
407 size_t sz, const struct mdoc_node *n)
408 {
409 int i, j, k;
410
411 if (NULL == n->args)
412 return(0);
413
414 for (k = i = 0; i < (int)n->args->argc; i++)
415 for (j = 0; j < (int)sz; j++)
416 if (n->args->argv[i].arg == keys[j]) {
417 vals[j] = i;
418 k++;
419 }
420 return(k);
421 }
422
423
424 /* ARGSUSED */
425 static int
426 termp_dq_pre(DECL_ARGS)
427 {
428
429 if (MDOC_BODY != node->type)
430 return(1);
431
432 word(p, "\\(lq");
433 p->flags |= TERMP_NOSPACE;
434 return(1);
435 }
436
437
438 /* ARGSUSED */
439 static void
440 termp_dq_post(DECL_ARGS)
441 {
442
443 if (MDOC_BODY != node->type)
444 return;
445
446 p->flags |= TERMP_NOSPACE;
447 word(p, "\\(rq");
448 }
449
450
451 /* ARGSUSED */
452 static int
453 termp_it_pre_block(DECL_ARGS)
454 {
455
456 newln(p);
457 if ( ! arg_hasattr(MDOC_Compact, node->parent->parent))
458 /* FIXME: parent->parent->parent? */
459 if (node->prev || node->parent->parent->prev)
460 vspace(p);
461
462 return(1);
463 }
464
465
466 /* ARGSUSED */
467 static int
468 termp_it_pre(DECL_ARGS)
469 {
470 const struct mdoc_node *bl, *n;
471 char buf[7];
472 int i, type, keys[3], vals[3];
473 size_t width, offset;
474
475 if (MDOC_BLOCK == node->type)
476 return(termp_it_pre_block(p, pair, meta, node));
477
478 bl = node->parent->parent->parent;
479
480 /* Save parent attributes. */
481
482 pair->offset = p->offset;
483 pair->rmargin = p->rmargin;
484 pair->flag = p->flags;
485
486 /* Get list width and offset. */
487
488 keys[0] = MDOC_Width;
489 keys[1] = MDOC_Offset;
490 keys[2] = MDOC_Column;
491
492 vals[0] = vals[1] = vals[2] = -1;
493
494 width = offset = 0;
495
496 (void)arg_getattrs(keys, vals, 3, bl);
497
498 type = arg_listtype(bl);
499
500 /* Calculate real width and offset. */
501
502 switch (type) {
503 case (MDOC_Column):
504 if (MDOC_BODY == node->type)
505 break;
506 for (i = 0, n = node->prev; n; n = n->prev, i++)
507 offset += arg_width
508 (&bl->args->argv[vals[2]], i);
509 assert(i < (int)bl->args->argv[vals[2]].sz);
510 width = arg_width(&bl->args->argv[vals[2]], i);
511 break;
512 default:
513 if (vals[0] >= 0)
514 width = arg_width(&bl->args->argv[vals[0]], 0);
515 if (vals[1] >= 0)
516 offset = arg_offset(&bl->args->argv[vals[1]]);
517 break;
518 }
519
520 /*
521 * List-type can override the width in the case of fixed-head
522 * values (bullet, dash/hyphen, enum). Tags need a non-zero
523 * offset.
524 */
525
526 switch (type) {
527 case (MDOC_Bullet):
528 /* FALLTHROUGH */
529 case (MDOC_Dash):
530 /* FALLTHROUGH */
531 case (MDOC_Enum):
532 /* FALLTHROUGH */
533 case (MDOC_Hyphen):
534 if (width > 4)
535 width = 4;
536 break;
537 case (MDOC_Tag):
538 if (0 == width)
539 width = 10;
540 break;
541 default:
542 break;
543 }
544
545 /*
546 * Whitespace control. Inset bodies need an initial space.
547 */
548
549 switch (type) {
550 case (MDOC_Diag):
551 /* FALLTHROUGH */
552 case (MDOC_Inset):
553 if (MDOC_BODY == node->type)
554 p->flags &= ~TERMP_NOSPACE;
555 else
556 p->flags |= TERMP_NOSPACE;
557 break;
558 default:
559 p->flags |= TERMP_NOSPACE;
560 break;
561 }
562
563 /*
564 * Style flags. Diagnostic heads need TTYPE_DIAG.
565 */
566
567 switch (type) {
568 case (MDOC_Diag):
569 if (MDOC_HEAD == node->type)
570 p->flags |= ttypes[TTYPE_DIAG];
571 break;
572 default:
573 break;
574 }
575
576 /*
577 * Pad and break control. This is the tricker part. Lists with
578 * set right-margins for the head get TERMP_NOBREAK because, if
579 * they overrun the margin, they wrap to the new margin.
580 * Correspondingly, the body for these types don't left-pad, as
581 * the head will pad out to to the right.
582 */
583
584 switch (type) {
585 case (MDOC_Bullet):
586 /* FALLTHROUGH */
587 case (MDOC_Dash):
588 /* FALLTHROUGH */
589 case (MDOC_Enum):
590 /* FALLTHROUGH */
591 case (MDOC_Hyphen):
592 /* FALLTHROUGH */
593 case (MDOC_Tag):
594 if (MDOC_HEAD == node->type)
595 p->flags |= TERMP_NOBREAK;
596 else
597 p->flags |= TERMP_NOLPAD;
598 if (MDOC_HEAD == node->type && MDOC_Tag == type)
599 if (NULL == node->next ||
600 NULL == node->next->child)
601 p->flags |= TERMP_NONOBREAK;
602 break;
603 case (MDOC_Column):
604 if (MDOC_HEAD == node->type) {
605 assert(node->next);
606 if (MDOC_BODY == node->next->type)
607 p->flags &= ~TERMP_NOBREAK;
608 else
609 p->flags |= TERMP_NOBREAK;
610 if (node->prev)
611 p->flags |= TERMP_NOLPAD;
612 }
613 break;
614 case (MDOC_Diag):
615 if (MDOC_HEAD == node->type)
616 p->flags |= TERMP_NOBREAK;
617 break;
618 default:
619 break;
620 }
621
622 /*
623 * Margin control. Set-head-width lists have their right
624 * margins shortened. The body for these lists has the offset
625 * necessarily lengthened. Everybody gets the offset.
626 */
627
628 p->offset += offset;
629
630 switch (type) {
631 case (MDOC_Bullet):
632 /* FALLTHROUGH */
633 case (MDOC_Dash):
634 /* FALLTHROUGH */
635 case (MDOC_Enum):
636 /* FALLTHROUGH */
637 case (MDOC_Hyphen):
638 /* FALLTHROUGH */
639 case (MDOC_Tag):
640 if (MDOC_HEAD == node->type)
641 p->rmargin = p->offset + width;
642 else
643 p->offset += width;
644 break;
645 case (MDOC_Column):
646 p->rmargin = p->offset + width;
647 break;
648 default:
649 break;
650 }
651
652 /*
653 * The dash, hyphen, bullet and enum lists all have a special
654 * HEAD character. Print it now.
655 */
656
657 if (MDOC_HEAD == node->type)
658 switch (type) {
659 case (MDOC_Bullet):
660 word(p, "\\[bu]");
661 break;
662 case (MDOC_Dash):
663 /* FALLTHROUGH */
664 case (MDOC_Hyphen):
665 word(p, "\\-");
666 break;
667 case (MDOC_Enum):
668 (pair->ppair->ppair->count)++;
669 (void)snprintf(buf, sizeof(buf), "%d.",
670 pair->ppair->ppair->count);
671 word(p, buf);
672 break;
673 default:
674 break;
675 }
676
677 /*
678 * If we're not going to process our children, indicate so here.
679 */
680
681 switch (type) {
682 case (MDOC_Bullet):
683 /* FALLTHROUGH */
684 case (MDOC_Item):
685 /* FALLTHROUGH */
686 case (MDOC_Dash):
687 /* FALLTHROUGH */
688 case (MDOC_Hyphen):
689 /* FALLTHROUGH */
690 case (MDOC_Enum):
691 if (MDOC_HEAD == node->type)
692 return(0);
693 break;
694 case (MDOC_Column):
695 if (MDOC_BODY == node->type)
696 return(0);
697 break;
698 default:
699 break;
700 }
701
702 return(1);
703 }
704
705
706 /* ARGSUSED */
707 static void
708 termp_it_post(DECL_ARGS)
709 {
710 int type;
711
712 if (MDOC_BODY != node->type && MDOC_HEAD != node->type)
713 return;
714
715 type = arg_listtype(node->parent->parent->parent);
716
717 switch (type) {
718 case (MDOC_Diag):
719 /* FALLTHROUGH */
720 case (MDOC_Item):
721 /* FALLTHROUGH */
722 case (MDOC_Inset):
723 if (MDOC_BODY == node->type)
724 flushln(p);
725 break;
726 case (MDOC_Column):
727 if (MDOC_HEAD == node->type)
728 flushln(p);
729 break;
730 default:
731 flushln(p);
732 break;
733 }
734
735 p->offset = pair->offset;
736 p->rmargin = pair->rmargin;
737 p->flags = pair->flag;
738 }
739
740
741 /* ARGSUSED */
742 static int
743 termp_nm_pre(DECL_ARGS)
744 {
745
746 if (SEC_SYNOPSIS == node->sec)
747 newln(p);
748
749 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_PROG]);
750 if (NULL == node->child)
751 word(p, meta->name);
752
753 return(1);
754 }
755
756
757 /* ARGSUSED */
758 static int
759 termp_fl_pre(DECL_ARGS)
760 {
761
762 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
763 word(p, "\\-");
764 p->flags |= TERMP_NOSPACE;
765 return(1);
766 }
767
768
769 /* ARGSUSED */
770 static int
771 termp_ar_pre(DECL_ARGS)
772 {
773
774 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_ARG]);
775 return(1);
776 }
777
778
779 /* ARGSUSED */
780 static int
781 termp_ns_pre(DECL_ARGS)
782 {
783
784 p->flags |= TERMP_NOSPACE;
785 return(1);
786 }
787
788
789 /* ARGSUSED */
790 static int
791 termp_pp_pre(DECL_ARGS)
792 {
793
794 vspace(p);
795 return(1);
796 }
797
798
799 /* ARGSUSED */
800 static int
801 termp_st_pre(DECL_ARGS)
802 {
803 const char *cp;
804
805 if (node->child && (cp = mdoc_a2st(node->child->string)))
806 word(p, cp);
807 return(0);
808 }
809
810
811 /* ARGSUSED */
812 static int
813 termp_rs_pre(DECL_ARGS)
814 {
815
816 if (MDOC_BLOCK == node->type && node->prev)
817 vspace(p);
818 return(1);
819 }
820
821
822 /* ARGSUSED */
823 static int
824 termp_rv_pre(DECL_ARGS)
825 {
826 int i;
827
828 if (-1 == (i = arg_getattr(MDOC_Std, node)))
829 errx(1, "expected -std argument");
830 if (1 != node->args->argv[i].sz)
831 errx(1, "expected -std argument");
832
833 newln(p);
834 word(p, "The");
835
836 p->flags |= ttypes[TTYPE_FUNC_NAME];
837 word(p, *node->args->argv[i].value);
838 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
839
840 word(p, "() function returns the value 0 if successful;");
841 word(p, "otherwise the value -1 is returned and the");
842 word(p, "global variable");
843
844 p->flags |= ttypes[TTYPE_VAR_DECL];
845 word(p, "errno");
846 p->flags &= ~ttypes[TTYPE_VAR_DECL];
847
848 word(p, "is set to indicate the error.");
849
850 return(1);
851 }
852
853
854 /* ARGSUSED */
855 static int
856 termp_ex_pre(DECL_ARGS)
857 {
858 int i;
859
860 if (-1 == (i = arg_getattr(MDOC_Std, node)))
861 errx(1, "expected -std argument");
862 if (1 != node->args->argv[i].sz)
863 errx(1, "expected -std argument");
864
865 word(p, "The");
866 p->flags |= ttypes[TTYPE_PROG];
867 word(p, *node->args->argv[i].value);
868 p->flags &= ~ttypes[TTYPE_PROG];
869 word(p, "utility exits 0 on success, and >0 if an error occurs.");
870
871 return(1);
872 }
873
874
875 /* ARGSUSED */
876 static int
877 termp_nd_pre(DECL_ARGS)
878 {
879
880 word(p, "\\-");
881 return(1);
882 }
883
884
885 /* ARGSUSED */
886 static void
887 termp_bl_post(DECL_ARGS)
888 {
889
890 if (MDOC_BLOCK == node->type)
891 newln(p);
892 }
893
894
895 /* ARGSUSED */
896 static void
897 termp_op_post(DECL_ARGS)
898 {
899
900 if (MDOC_BODY != node->type)
901 return;
902 p->flags |= TERMP_NOSPACE;
903 word(p, "\\(rB");
904 }
905
906
907 /* ARGSUSED */
908 static int
909 termp_xr_pre(DECL_ARGS)
910 {
911 const struct mdoc_node *n;
912
913 if (NULL == (n = node->child))
914 errx(1, "expected text line argument");
915 word(p, n->string);
916 if (NULL == (n = n->next))
917 return(0);
918 p->flags |= TERMP_NOSPACE;
919 word(p, "(");
920 p->flags |= TERMP_NOSPACE;
921 word(p, n->string);
922 p->flags |= TERMP_NOSPACE;
923 word(p, ")");
924 return(0);
925 }
926
927
928 /* ARGSUSED */
929 static int
930 termp_vt_pre(DECL_ARGS)
931 {
932
933 /* FIXME: this can be "type name". */
934 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
935 return(1);
936 }
937
938
939 /* ARGSUSED */
940 static void
941 termp_vt_post(DECL_ARGS)
942 {
943
944 if (node->sec == SEC_SYNOPSIS)
945 vspace(p);
946 }
947
948
949 /* ARGSUSED */
950 static int
951 termp_fd_pre(DECL_ARGS)
952 {
953
954 /*
955 * FIXME: this naming is bad. This value is used, in general,
956 * for the #include header or other preprocessor statement.
957 */
958 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_DECL]);
959 return(1);
960 }
961
962
963 /* ARGSUSED */
964 static void
965 termp_fd_post(DECL_ARGS)
966 {
967
968 if (node->sec != SEC_SYNOPSIS)
969 return;
970 newln(p);
971 if (node->next && MDOC_Fd != node->next->tok)
972 vspace(p);
973 }
974
975
976 /* ARGSUSED */
977 static int
978 termp_sh_pre(DECL_ARGS)
979 {
980
981 switch (node->type) {
982 case (MDOC_HEAD):
983 vspace(p);
984 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SECTION]);
985 break;
986 case (MDOC_BODY):
987 p->offset = INDENT;
988 break;
989 default:
990 break;
991 }
992 return(1);
993 }
994
995
996 /* ARGSUSED */
997 static void
998 termp_sh_post(DECL_ARGS)
999 {
1000
1001 switch (node->type) {
1002 case (MDOC_HEAD):
1003 newln(p);
1004 break;
1005 case (MDOC_BODY):
1006 newln(p);
1007 p->offset = 0;
1008 break;
1009 default:
1010 break;
1011 }
1012 }
1013
1014
1015 /* ARGSUSED */
1016 static int
1017 termp_op_pre(DECL_ARGS)
1018 {
1019
1020 switch (node->type) {
1021 case (MDOC_BODY):
1022 word(p, "\\(lB");
1023 p->flags |= TERMP_NOSPACE;
1024 break;
1025 default:
1026 break;
1027 }
1028 return(1);
1029 }
1030
1031
1032 /* ARGSUSED */
1033 static int
1034 termp_bt_pre(DECL_ARGS)
1035 {
1036
1037 word(p, "is currently in beta test.");
1038 return(1);
1039 }
1040
1041
1042 /* ARGSUSED */
1043 static int
1044 termp_lb_pre(DECL_ARGS)
1045 {
1046 const char *lb;
1047
1048 if (NULL == node->child)
1049 errx(1, "expected text line argument");
1050 if ((lb = mdoc_a2lib(node->child->string))) {
1051 word(p, lb);
1052 return(0);
1053 }
1054 word(p, "library");
1055 return(1);
1056 }
1057
1058
1059 /* ARGSUSED */
1060 static void
1061 termp_lb_post(DECL_ARGS)
1062 {
1063
1064 newln(p);
1065 }
1066
1067
1068 /* ARGSUSED */
1069 static int
1070 termp_ud_pre(DECL_ARGS)
1071 {
1072
1073 word(p, "currently under development.");
1074 return(1);
1075 }
1076
1077
1078 /* ARGSUSED */
1079 static int
1080 termp_d1_pre(DECL_ARGS)
1081 {
1082
1083 if (MDOC_BODY != node->type)
1084 return(1);
1085 newln(p);
1086 p->offset += (pair->offset = INDENT);
1087 return(1);
1088 }
1089
1090
1091 /* ARGSUSED */
1092 static void
1093 termp_d1_post(DECL_ARGS)
1094 {
1095
1096 if (MDOC_BODY != node->type)
1097 return;
1098 newln(p);
1099 p->offset -= pair->offset;
1100 }
1101
1102
1103 /* ARGSUSED */
1104 static int
1105 termp_aq_pre(DECL_ARGS)
1106 {
1107
1108 if (MDOC_BODY != node->type)
1109 return(1);
1110 word(p, "\\(la");
1111 p->flags |= TERMP_NOSPACE;
1112 return(1);
1113 }
1114
1115
1116 /* ARGSUSED */
1117 static void
1118 termp_aq_post(DECL_ARGS)
1119 {
1120
1121 if (MDOC_BODY != node->type)
1122 return;
1123 p->flags |= TERMP_NOSPACE;
1124 word(p, "\\(ra");
1125 }
1126
1127
1128 /* ARGSUSED */
1129 static int
1130 termp_ft_pre(DECL_ARGS)
1131 {
1132
1133 if (SEC_SYNOPSIS == node->sec)
1134 if (node->prev && MDOC_Fo == node->prev->tok)
1135 vspace(p);
1136 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_TYPE]);
1137 return(1);
1138 }
1139
1140
1141 /* ARGSUSED */
1142 static void
1143 termp_ft_post(DECL_ARGS)
1144 {
1145
1146 if (SEC_SYNOPSIS == node->sec)
1147 newln(p);
1148 }
1149
1150
1151 /* ARGSUSED */
1152 static int
1153 termp_fn_pre(DECL_ARGS)
1154 {
1155 const struct mdoc_node *n;
1156
1157 if (NULL == node->child)
1158 errx(1, "expected text line arguments");
1159
1160 /* FIXME: can be "type funcname" "type varname"... */
1161
1162 p->flags |= ttypes[TTYPE_FUNC_NAME];
1163 word(p, node->child->string);
1164 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1165
1166 word(p, "(");
1167
1168 p->flags |= TERMP_NOSPACE;
1169 for (n = node->child->next; n; n = n->next) {
1170 p->flags |= ttypes[TTYPE_FUNC_ARG];
1171 word(p, n->string);
1172 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1173 if (n->next)
1174 word(p, ",");
1175 }
1176
1177 word(p, ")");
1178
1179 if (SEC_SYNOPSIS == node->sec)
1180 word(p, ";");
1181
1182 return(0);
1183 }
1184
1185
1186 /* ARGSUSED */
1187 static void
1188 termp_fn_post(DECL_ARGS)
1189 {
1190
1191 if (node->sec == SEC_SYNOPSIS && node->next)
1192 vspace(p);
1193
1194 }
1195
1196
1197 /* ARGSUSED */
1198 static int
1199 termp_sx_pre(DECL_ARGS)
1200 {
1201
1202 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK]);
1203 return(1);
1204 }
1205
1206
1207 /* ARGSUSED */
1208 static int
1209 termp_fa_pre(DECL_ARGS)
1210 {
1211 struct mdoc_node *n;
1212
1213 if (node->parent->tok != MDOC_Fo) {
1214 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_ARG]);
1215 return(1);
1216 }
1217
1218 for (n = node->child; n; n = n->next) {
1219 p->flags |= ttypes[TTYPE_FUNC_ARG];
1220 word(p, n->string);
1221 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1222 if (n->next)
1223 word(p, ",");
1224 }
1225
1226 if (node->next && node->next->tok == MDOC_Fa)
1227 word(p, ",");
1228
1229 return(0);
1230 }
1231
1232
1233 /* ARGSUSED */
1234 static int
1235 termp_va_pre(DECL_ARGS)
1236 {
1237
1238 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
1239 return(1);
1240 }
1241
1242
1243 /* ARGSUSED */
1244 static int
1245 termp_bd_pre(DECL_ARGS)
1246 {
1247 const struct mdoc_node *n;
1248 int i, type;
1249
1250 if (MDOC_BLOCK == node->type) {
1251 /* FIXME: parent prev? */
1252 if (node->prev)
1253 vspace(p);
1254 return(1);
1255 } else if (MDOC_BODY != node->type)
1256 return(1);
1257
1258 if (NULL == node->parent->args)
1259 errx(1, "missing display type");
1260
1261 pair->offset = p->offset;
1262
1263 for (type = -1, i = 0;
1264 i < (int)node->parent->args->argc; i++) {
1265 switch (node->parent->args->argv[i].arg) {
1266 case (MDOC_Ragged):
1267 /* FALLTHROUGH */
1268 case (MDOC_Filled):
1269 /* FALLTHROUGH */
1270 case (MDOC_Unfilled):
1271 /* FALLTHROUGH */
1272 case (MDOC_Literal):
1273 type = node->parent->args->argv[i].arg;
1274 i = (int)node->parent->args->argc;
1275 break;
1276 default:
1277 break;
1278 }
1279 }
1280
1281 if (NULL == node->parent->args)
1282 errx(1, "missing display type");
1283
1284 i = arg_getattr(MDOC_Offset, node->parent);
1285 if (-1 != i) {
1286 if (1 != node->parent->args->argv[i].sz)
1287 errx(1, "expected single value");
1288 p->offset += arg_offset(&node->parent->args->argv[i]);
1289 }
1290
1291 switch (type) {
1292 case (MDOC_Literal):
1293 /* FALLTHROUGH */
1294 case (MDOC_Unfilled):
1295 break;
1296 default:
1297 return(1);
1298 }
1299
1300 p->flags |= TERMP_LITERAL;
1301
1302 for (n = node->child; n; n = n->next) {
1303 if (MDOC_TEXT != n->type) {
1304 warnx("non-text children not yet allowed");
1305 continue;
1306 }
1307 word(p, n->string);
1308 flushln(p);
1309 }
1310
1311 return(0);
1312 }
1313
1314
1315 /* ARGSUSED */
1316 static void
1317 termp_bd_post(DECL_ARGS)
1318 {
1319
1320 if (MDOC_BODY != node->type)
1321 return;
1322
1323 if ( ! (p->flags & TERMP_LITERAL))
1324 flushln(p);
1325
1326 p->flags &= ~TERMP_LITERAL;
1327 p->offset = pair->offset;
1328 }
1329
1330
1331 /* ARGSUSED */
1332 static int
1333 termp_qq_pre(DECL_ARGS)
1334 {
1335
1336 if (MDOC_BODY != node->type)
1337 return(1);
1338 word(p, "\"");
1339 p->flags |= TERMP_NOSPACE;
1340 return(1);
1341 }
1342
1343
1344 /* ARGSUSED */
1345 static void
1346 termp_qq_post(DECL_ARGS)
1347 {
1348
1349 if (MDOC_BODY != node->type)
1350 return;
1351 p->flags |= TERMP_NOSPACE;
1352 word(p, "\"");
1353 }
1354
1355
1356 /* ARGSUSED */
1357 static int
1358 termp_bsx_pre(DECL_ARGS)
1359 {
1360
1361 word(p, "BSDI BSD/OS");
1362 return(1);
1363 }
1364
1365
1366 /* ARGSUSED */
1367 static void
1368 termp_bx_post(DECL_ARGS)
1369 {
1370
1371 if (node->child)
1372 p->flags |= TERMP_NOSPACE;
1373 word(p, "BSD");
1374 }
1375
1376
1377 /* ARGSUSED */
1378 static int
1379 termp_ox_pre(DECL_ARGS)
1380 {
1381
1382 word(p, "OpenBSD");
1383 return(1);
1384 }
1385
1386
1387 /* ARGSUSED */
1388 static int
1389 termp_ux_pre(DECL_ARGS)
1390 {
1391
1392 word(p, "UNIX");
1393 return(1);
1394 }
1395
1396
1397 /* ARGSUSED */
1398 static int
1399 termp_fx_pre(DECL_ARGS)
1400 {
1401
1402 word(p, "FreeBSD");
1403 return(1);
1404 }
1405
1406
1407 /* ARGSUSED */
1408 static int
1409 termp_nx_pre(DECL_ARGS)
1410 {
1411
1412 word(p, "NetBSD");
1413 return(1);
1414 }
1415
1416
1417 /* ARGSUSED */
1418 static int
1419 termp_sq_pre(DECL_ARGS)
1420 {
1421
1422 if (MDOC_BODY != node->type)
1423 return(1);
1424 word(p, "\\(oq");
1425 p->flags |= TERMP_NOSPACE;
1426 return(1);
1427 }
1428
1429
1430 /* ARGSUSED */
1431 static void
1432 termp_sq_post(DECL_ARGS)
1433 {
1434
1435 if (MDOC_BODY != node->type)
1436 return;
1437 p->flags |= TERMP_NOSPACE;
1438 word(p, "\\(aq");
1439 }
1440
1441
1442 /* ARGSUSED */
1443 static int
1444 termp_pf_pre(DECL_ARGS)
1445 {
1446
1447 p->flags |= TERMP_IGNDELIM;
1448 return(1);
1449 }
1450
1451
1452 /* ARGSUSED */
1453 static void
1454 termp_pf_post(DECL_ARGS)
1455 {
1456
1457 p->flags &= ~TERMP_IGNDELIM;
1458 p->flags |= TERMP_NOSPACE;
1459 }
1460
1461
1462 /* ARGSUSED */
1463 static int
1464 termp_ss_pre(DECL_ARGS)
1465 {
1466
1467 switch (node->type) {
1468 case (MDOC_HEAD):
1469 vspace(p);
1470 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SSECTION]);
1471 p->offset = INDENT / 2;
1472 break;
1473 default:
1474 break;
1475 }
1476
1477 return(1);
1478 }
1479
1480
1481 /* ARGSUSED */
1482 static void
1483 termp_ss_post(DECL_ARGS)
1484 {
1485
1486 switch (node->type) {
1487 case (MDOC_HEAD):
1488 newln(p);
1489 p->offset = INDENT;
1490 break;
1491 default:
1492 break;
1493 }
1494 }
1495
1496
1497 /* ARGSUSED */
1498 static int
1499 termp_pa_pre(DECL_ARGS)
1500 {
1501
1502 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FILE]);
1503 return(1);
1504 }
1505
1506
1507 /* ARGSUSED */
1508 static int
1509 termp_em_pre(DECL_ARGS)
1510 {
1511
1512 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1513 return(1);
1514 }
1515
1516
1517 /* ARGSUSED */
1518 static int
1519 termp_cd_pre(DECL_ARGS)
1520 {
1521
1522 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CONFIG]);
1523 newln(p);
1524 return(1);
1525 }
1526
1527
1528 /* ARGSUSED */
1529 static int
1530 termp_cm_pre(DECL_ARGS)
1531 {
1532
1533 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
1534 return(1);
1535 }
1536
1537
1538 /* ARGSUSED */
1539 static int
1540 termp_ic_pre(DECL_ARGS)
1541 {
1542
1543 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD]);
1544 return(1);
1545 }
1546
1547
1548 /* ARGSUSED */
1549 static int
1550 termp_in_pre(DECL_ARGS)
1551 {
1552
1553 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_INCLUDE]);
1554 word(p, "#include");
1555 word(p, "<");
1556 p->flags |= TERMP_NOSPACE;
1557 return(1);
1558 }
1559
1560
1561 /* ARGSUSED */
1562 static void
1563 termp_in_post(DECL_ARGS)
1564 {
1565
1566 p->flags |= TERMP_NOSPACE;
1567 word(p, ">");
1568
1569 newln(p);
1570 if (SEC_SYNOPSIS != node->sec)
1571 return;
1572 if (node->next && MDOC_In != node->next->tok)
1573 vspace(p);
1574 }
1575
1576
1577 /* ARGSUSED */
1578 static int
1579 termp_at_pre(DECL_ARGS)
1580 {
1581 const char *att;
1582
1583 att = NULL;
1584
1585 if (node->child)
1586 att = mdoc_a2att(node->child->string);
1587 if (NULL == att)
1588 att = "AT&T UNIX";
1589
1590 word(p, att);
1591 return(0);
1592 }
1593
1594
1595 /* ARGSUSED */
1596 static int
1597 termp_brq_pre(DECL_ARGS)
1598 {
1599
1600 if (MDOC_BODY != node->type)
1601 return(1);
1602 word(p, "\\(lC");
1603 p->flags |= TERMP_NOSPACE;
1604 return(1);
1605 }
1606
1607
1608 /* ARGSUSED */
1609 static void
1610 termp_brq_post(DECL_ARGS)
1611 {
1612
1613 if (MDOC_BODY != node->type)
1614 return;
1615 p->flags |= TERMP_NOSPACE;
1616 word(p, "\\(rC");
1617 }
1618
1619
1620 /* ARGSUSED */
1621 static int
1622 termp_bq_pre(DECL_ARGS)
1623 {
1624
1625 if (MDOC_BODY != node->type)
1626 return(1);
1627 word(p, "\\(lB");
1628 p->flags |= TERMP_NOSPACE;
1629 return(1);
1630 }
1631
1632
1633 /* ARGSUSED */
1634 static void
1635 termp_bq_post(DECL_ARGS)
1636 {
1637
1638 if (MDOC_BODY != node->type)
1639 return;
1640 p->flags |= TERMP_NOSPACE;
1641 word(p, "\\(rB");
1642 }
1643
1644
1645 /* ARGSUSED */
1646 static int
1647 termp_pq_pre(DECL_ARGS)
1648 {
1649
1650 if (MDOC_BODY != node->type)
1651 return(1);
1652 word(p, "\\&(");
1653 p->flags |= TERMP_NOSPACE;
1654 return(1);
1655 }
1656
1657
1658 /* ARGSUSED */
1659 static void
1660 termp_pq_post(DECL_ARGS)
1661 {
1662
1663 if (MDOC_BODY != node->type)
1664 return;
1665 word(p, ")");
1666 }
1667
1668
1669 /* ARGSUSED */
1670 static int
1671 termp_fo_pre(DECL_ARGS)
1672 {
1673 const struct mdoc_node *n;
1674
1675 if (MDOC_BODY == node->type) {
1676 word(p, "(");
1677 p->flags |= TERMP_NOSPACE;
1678 return(1);
1679 } else if (MDOC_HEAD != node->type)
1680 return(1);
1681
1682 /* XXX - groff shows only first parameter */
1683
1684 p->flags |= ttypes[TTYPE_FUNC_NAME];
1685 for (n = node->child; n; n = n->next) {
1686 if (MDOC_TEXT != n->type)
1687 errx(1, "expected text line argument");
1688 word(p, n->string);
1689 }
1690 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1691
1692 return(0);
1693 }
1694
1695
1696 /* ARGSUSED */
1697 static void
1698 termp_fo_post(DECL_ARGS)
1699 {
1700
1701 if (MDOC_BODY != node->type)
1702 return;
1703 p->flags |= TERMP_NOSPACE;
1704 word(p, ")");
1705 p->flags |= TERMP_NOSPACE;
1706 word(p, ";");
1707 newln(p);
1708 }
1709
1710
1711 /* ARGSUSED */
1712 static int
1713 termp_bf_pre(DECL_ARGS)
1714 {
1715 const struct mdoc_node *n;
1716
1717 if (MDOC_HEAD == node->type) {
1718 return(0);
1719 } else if (MDOC_BLOCK != node->type)
1720 return(1);
1721
1722 if (NULL == (n = node->head->child)) {
1723 if (arg_hasattr(MDOC_Emphasis, node))
1724 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1725 else if (arg_hasattr(MDOC_Symbolic, node))
1726 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1727
1728 return(1);
1729 }
1730
1731 if (MDOC_TEXT != n->type)
1732 errx(1, "expected text line arguments");
1733
1734 if (0 == strcmp("Em", n->string))
1735 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1736 else if (0 == strcmp("Sy", n->string))
1737 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1738
1739 return(1);
1740 }
1741
1742
1743 /* ARGSUSED */
1744 static int
1745 termp_sy_pre(DECL_ARGS)
1746 {
1747
1748 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1749 return(1);
1750 }
1751
1752
1753 /* ARGSUSED */
1754 static int
1755 termp_ms_pre(DECL_ARGS)
1756 {
1757
1758 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMBOL]);
1759 return(1);
1760 }
1761
1762
1763
1764 /* ARGSUSED */
1765 static int
1766 termp_sm_pre(DECL_ARGS)
1767 {
1768
1769 #if notyet
1770 assert(node->child);
1771 if (0 == strcmp("off", node->child->data.text.string)) {
1772 p->flags &= ~TERMP_NONOSPACE;
1773 p->flags &= ~TERMP_NOSPACE;
1774 } else {
1775 p->flags |= TERMP_NONOSPACE;
1776 p->flags |= TERMP_NOSPACE;
1777 }
1778 #endif
1779
1780 return(0);
1781 }
1782
1783
1784 /* ARGSUSED */
1785 static int
1786 termp_ap_pre(DECL_ARGS)
1787 {
1788
1789 p->flags |= TERMP_NOSPACE;
1790 word(p, "\\(aq");
1791 p->flags |= TERMP_NOSPACE;
1792 return(1);
1793 }
1794
1795
1796 /* ARGSUSED */
1797 static int
1798 termp__t_pre(DECL_ARGS)
1799 {
1800
1801 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_REF_TITLE]);
1802 return(1);
1803 }
1804
1805
1806 /* ARGSUSED */
1807 static void
1808 termp____post(DECL_ARGS)
1809 {
1810
1811 p->flags |= TERMP_NOSPACE;
1812 word(p, node->next ? "," : ".");
1813 }
1814
1815
1816 /* ARGSUSED */
1817 static int
1818 termp_lk_pre(DECL_ARGS)
1819 {
1820 const struct mdoc_node *n;
1821
1822 if (NULL == (n = node->child))
1823 errx(1, "expected line argument");
1824
1825 p->flags |= ttypes[TTYPE_LINK_ANCHOR];
1826 word(p, n->string);
1827 p->flags &= ~ttypes[TTYPE_LINK_ANCHOR];
1828 p->flags |= TERMP_NOSPACE;
1829 word(p, ":");
1830
1831 p->flags |= ttypes[TTYPE_LINK_TEXT];
1832 for ( ; n; n = n->next) {
1833 word(p, n->string);
1834 }
1835 p->flags &= ~ttypes[TTYPE_LINK_TEXT];
1836
1837 return(0);
1838 }
1839
1840
1841 /* ARGSUSED */
1842 static int
1843 termp_mt_pre(DECL_ARGS)
1844 {
1845
1846 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK_ANCHOR]);
1847 return(1);
1848 }
1849