]> git.cameronkatri.com Git - mandoc.git/blob - term.c
Fixed mdoc_phrase escape handling.
[mandoc.git] / term.c
1 /* $Id: term.c,v 1.60 2009/03/16 22:19:19 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_UNDER, /* TTYPE_CMD_ARG */
73 TERMP_BOLD, /* TTYPE_SECTION */
74 TERMP_BOLD, /* TTYPE_FUNC_DECL */
75 TERMP_UNDER, /* TTYPE_VAR_DECL */
76 TERMP_UNDER, /* TTYPE_FUNC_TYPE */
77 TERMP_BOLD, /* TTYPE_FUNC_NAME */
78 TERMP_UNDER, /* TTYPE_FUNC_ARG */
79 TERMP_UNDER, /* TTYPE_LINK */
80 TERMP_BOLD, /* TTYPE_SSECTION */
81 TERMP_UNDER, /* TTYPE_FILE */
82 TERMP_UNDER, /* 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_UNDER, /* TTYPE_LINK_ANCHOR */
90 TERMP_BOLD, /* TTYPE_LINK_TEXT */
91 TERMP_UNDER /* 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 { NULL, NULL }, /* %C */
299 { NULL, NULL }, /* Es */
300 { NULL, NULL }, /* En */
301 };
302
303 const struct termact *termacts = __termacts;
304
305
306 static size_t
307 arg_width(const struct mdoc_argv *arg, int pos)
308 {
309 size_t v;
310 int i, len;
311
312 assert(pos < (int)arg->sz && pos >= 0);
313 assert(arg->value[pos]);
314 if (0 == strcmp(arg->value[pos], "indent"))
315 return(INDENT);
316 if (0 == strcmp(arg->value[pos], "indent-two"))
317 return(INDENT * 2);
318
319 len = (int)strlen(arg->value[pos]);
320 assert(len > 0);
321
322 for (i = 0; i < len - 1; i++)
323 if ( ! isdigit((u_char)arg->value[pos][i]))
324 break;
325
326 if (i == len - 1) {
327 if ('n' == arg->value[pos][len - 1]) {
328 v = (size_t)atoi(arg->value[pos]);
329 return(v);
330 }
331
332 }
333 return(strlen(arg->value[pos]) + 1);
334 }
335
336
337 static int
338 arg_listtype(const struct mdoc_node *n)
339 {
340 int i, len;
341
342 assert(MDOC_BLOCK == n->type);
343
344 len = (int)(n->args ? n->args->argc : 0);
345
346 for (i = 0; i < len; i++)
347 switch (n->args->argv[i].arg) {
348 case (MDOC_Bullet):
349 /* FALLTHROUGH */
350 case (MDOC_Dash):
351 /* FALLTHROUGH */
352 case (MDOC_Enum):
353 /* FALLTHROUGH */
354 case (MDOC_Hyphen):
355 /* FALLTHROUGH */
356 case (MDOC_Tag):
357 /* FALLTHROUGH */
358 case (MDOC_Inset):
359 /* FALLTHROUGH */
360 case (MDOC_Diag):
361 /* FALLTHROUGH */
362 case (MDOC_Item):
363 /* FALLTHROUGH */
364 case (MDOC_Column):
365 /* FALLTHROUGH */
366 case (MDOC_Ohang):
367 return(n->args->argv[i].arg);
368 default:
369 break;
370 }
371
372 errx(1, "list type not supported");
373 /* NOTREACHED */
374 }
375
376
377 static size_t
378 arg_offset(const struct mdoc_argv *arg)
379 {
380
381 /* TODO */
382 assert(*arg->value);
383 if (0 == strcmp(*arg->value, "indent"))
384 return(INDENT);
385 if (0 == strcmp(*arg->value, "indent-two"))
386 return(INDENT * 2);
387 return(strlen(*arg->value));
388 }
389
390
391 static int
392 arg_hasattr(int arg, const struct mdoc_node *n)
393 {
394
395 return(-1 != arg_getattr(arg, n));
396 }
397
398
399 static int
400 arg_getattr(int v, const struct mdoc_node *n)
401 {
402 int val;
403
404 return(arg_getattrs(&v, &val, 1, n) ? val : -1);
405 }
406
407
408 static int
409 arg_getattrs(const int *keys, int *vals,
410 size_t sz, const struct mdoc_node *n)
411 {
412 int i, j, k;
413
414 if (NULL == n->args)
415 return(0);
416
417 for (k = i = 0; i < (int)n->args->argc; i++)
418 for (j = 0; j < (int)sz; j++)
419 if (n->args->argv[i].arg == keys[j]) {
420 vals[j] = i;
421 k++;
422 }
423 return(k);
424 }
425
426
427 /* ARGSUSED */
428 static int
429 termp_dq_pre(DECL_ARGS)
430 {
431
432 if (MDOC_BODY != node->type)
433 return(1);
434
435 word(p, "\\(lq");
436 p->flags |= TERMP_NOSPACE;
437 return(1);
438 }
439
440
441 /* ARGSUSED */
442 static void
443 termp_dq_post(DECL_ARGS)
444 {
445
446 if (MDOC_BODY != node->type)
447 return;
448
449 p->flags |= TERMP_NOSPACE;
450 word(p, "\\(rq");
451 }
452
453
454 /* ARGSUSED */
455 static int
456 termp_it_pre_block(DECL_ARGS)
457 {
458
459 newln(p);
460 if ( ! arg_hasattr(MDOC_Compact, node->parent->parent))
461 /* FIXME: parent->parent->parent? */
462 if (node->prev || node->parent->parent->prev)
463 vspace(p);
464
465 return(1);
466 }
467
468
469 /* ARGSUSED */
470 static int
471 termp_it_pre(DECL_ARGS)
472 {
473 const struct mdoc_node *bl, *n;
474 char buf[7];
475 int i, type, keys[3], vals[3];
476 size_t width, offset;
477
478 if (MDOC_BLOCK == node->type)
479 return(termp_it_pre_block(p, pair, meta, node));
480
481 bl = node->parent->parent->parent;
482
483 /* Save parent attributes. */
484
485 pair->offset = p->offset;
486 pair->rmargin = p->rmargin;
487 pair->flag = p->flags;
488
489 /* Get list width and offset. */
490
491 keys[0] = MDOC_Width;
492 keys[1] = MDOC_Offset;
493 keys[2] = MDOC_Column;
494
495 vals[0] = vals[1] = vals[2] = -1;
496
497 width = offset = 0;
498
499 (void)arg_getattrs(keys, vals, 3, bl);
500
501 type = arg_listtype(bl);
502
503 /* Calculate real width and offset. */
504
505 switch (type) {
506 case (MDOC_Column):
507 if (MDOC_BODY == node->type)
508 break;
509 for (i = 0, n = node->prev; n; n = n->prev, i++)
510 offset += arg_width
511 (&bl->args->argv[vals[2]], i);
512 assert(i < (int)bl->args->argv[vals[2]].sz);
513 width = arg_width(&bl->args->argv[vals[2]], i);
514 if (vals[1] >= 0)
515 offset += arg_offset(&bl->args->argv[vals[1]]);
516 break;
517 default:
518 if (vals[0] >= 0)
519 width = arg_width(&bl->args->argv[vals[0]], 0);
520 if (vals[1] >= 0)
521 offset = arg_offset(&bl->args->argv[vals[1]]);
522 break;
523 }
524
525 /*
526 * List-type can override the width in the case of fixed-head
527 * values (bullet, dash/hyphen, enum). Tags need a non-zero
528 * offset.
529 */
530
531 switch (type) {
532 case (MDOC_Bullet):
533 /* FALLTHROUGH */
534 case (MDOC_Dash):
535 /* FALLTHROUGH */
536 case (MDOC_Enum):
537 /* FALLTHROUGH */
538 case (MDOC_Hyphen):
539 if (width < 4)
540 width = 4;
541 break;
542 case (MDOC_Tag):
543 if (0 == width)
544 width = 10;
545 break;
546 default:
547 break;
548 }
549
550 /*
551 * Whitespace control. Inset bodies need an initial space.
552 */
553
554 switch (type) {
555 case (MDOC_Diag):
556 /* FALLTHROUGH */
557 case (MDOC_Inset):
558 if (MDOC_BODY == node->type)
559 p->flags &= ~TERMP_NOSPACE;
560 else
561 p->flags |= TERMP_NOSPACE;
562 break;
563 default:
564 p->flags |= TERMP_NOSPACE;
565 break;
566 }
567
568 /*
569 * Style flags. Diagnostic heads need TTYPE_DIAG.
570 */
571
572 switch (type) {
573 case (MDOC_Diag):
574 if (MDOC_HEAD == node->type)
575 p->flags |= ttypes[TTYPE_DIAG];
576 break;
577 default:
578 break;
579 }
580
581 /*
582 * Pad and break control. This is the tricker part. Lists with
583 * set right-margins for the head get TERMP_NOBREAK because, if
584 * they overrun the margin, they wrap to the new margin.
585 * Correspondingly, the body for these types don't left-pad, as
586 * the head will pad out to to the right.
587 */
588
589 switch (type) {
590 case (MDOC_Bullet):
591 /* FALLTHROUGH */
592 case (MDOC_Dash):
593 /* FALLTHROUGH */
594 case (MDOC_Enum):
595 /* FALLTHROUGH */
596 case (MDOC_Hyphen):
597 /* FALLTHROUGH */
598 case (MDOC_Tag):
599 if (MDOC_HEAD == node->type)
600 p->flags |= TERMP_NOBREAK;
601 else
602 p->flags |= TERMP_NOLPAD;
603 if (MDOC_HEAD == node->type && MDOC_Tag == type)
604 if (NULL == node->next ||
605 NULL == node->next->child)
606 p->flags |= TERMP_NONOBREAK;
607 break;
608 case (MDOC_Column):
609 if (MDOC_HEAD == node->type) {
610 assert(node->next);
611 if (MDOC_BODY == node->next->type)
612 p->flags &= ~TERMP_NOBREAK;
613 else
614 p->flags |= TERMP_NOBREAK;
615 if (node->prev)
616 p->flags |= TERMP_NOLPAD;
617 }
618 break;
619 case (MDOC_Diag):
620 if (MDOC_HEAD == node->type)
621 p->flags |= TERMP_NOBREAK;
622 break;
623 default:
624 break;
625 }
626
627 /*
628 * Margin control. Set-head-width lists have their right
629 * margins shortened. The body for these lists has the offset
630 * necessarily lengthened. Everybody gets the offset.
631 */
632
633 p->offset += offset;
634
635 switch (type) {
636 case (MDOC_Bullet):
637 /* FALLTHROUGH */
638 case (MDOC_Dash):
639 /* FALLTHROUGH */
640 case (MDOC_Enum):
641 /* FALLTHROUGH */
642 case (MDOC_Hyphen):
643 /* FALLTHROUGH */
644 case (MDOC_Tag):
645 if (MDOC_HEAD == node->type)
646 p->rmargin = p->offset + width;
647 else
648 p->offset += width;
649 break;
650 case (MDOC_Column):
651 p->rmargin = p->offset + width;
652 break;
653 default:
654 break;
655 }
656
657 /*
658 * The dash, hyphen, bullet and enum lists all have a special
659 * HEAD character. Print it now.
660 */
661
662 if (MDOC_HEAD == node->type)
663 switch (type) {
664 case (MDOC_Bullet):
665 word(p, "\\[bu]");
666 break;
667 case (MDOC_Dash):
668 /* FALLTHROUGH */
669 case (MDOC_Hyphen):
670 word(p, "\\-");
671 break;
672 case (MDOC_Enum):
673 (pair->ppair->ppair->count)++;
674 (void)snprintf(buf, sizeof(buf), "%d.",
675 pair->ppair->ppair->count);
676 word(p, buf);
677 break;
678 default:
679 break;
680 }
681
682 /*
683 * If we're not going to process our children, indicate so here.
684 */
685
686 switch (type) {
687 case (MDOC_Bullet):
688 /* FALLTHROUGH */
689 case (MDOC_Item):
690 /* FALLTHROUGH */
691 case (MDOC_Dash):
692 /* FALLTHROUGH */
693 case (MDOC_Hyphen):
694 /* FALLTHROUGH */
695 case (MDOC_Enum):
696 if (MDOC_HEAD == node->type)
697 return(0);
698 break;
699 case (MDOC_Column):
700 if (MDOC_BODY == node->type)
701 return(0);
702 break;
703 default:
704 break;
705 }
706
707 return(1);
708 }
709
710
711 /* ARGSUSED */
712 static void
713 termp_it_post(DECL_ARGS)
714 {
715 int type;
716
717 if (MDOC_BODY != node->type && MDOC_HEAD != node->type)
718 return;
719
720 type = arg_listtype(node->parent->parent->parent);
721
722 switch (type) {
723 case (MDOC_Diag):
724 /* FALLTHROUGH */
725 case (MDOC_Item):
726 /* FALLTHROUGH */
727 case (MDOC_Inset):
728 if (MDOC_BODY == node->type)
729 flushln(p);
730 break;
731 case (MDOC_Column):
732 if (MDOC_HEAD == node->type)
733 flushln(p);
734 break;
735 default:
736 flushln(p);
737 break;
738 }
739
740 p->offset = pair->offset;
741 p->rmargin = pair->rmargin;
742 p->flags = pair->flag;
743 }
744
745
746 /* ARGSUSED */
747 static int
748 termp_nm_pre(DECL_ARGS)
749 {
750
751 if (SEC_SYNOPSIS == node->sec)
752 newln(p);
753
754 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_PROG]);
755 if (NULL == node->child)
756 word(p, meta->name);
757
758 return(1);
759 }
760
761
762 /* ARGSUSED */
763 static int
764 termp_fl_pre(DECL_ARGS)
765 {
766
767 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
768 word(p, "\\-");
769 p->flags |= TERMP_NOSPACE;
770 return(1);
771 }
772
773
774 /* ARGSUSED */
775 static int
776 termp_ar_pre(DECL_ARGS)
777 {
778
779 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_ARG]);
780 return(1);
781 }
782
783
784 /* ARGSUSED */
785 static int
786 termp_ns_pre(DECL_ARGS)
787 {
788
789 p->flags |= TERMP_NOSPACE;
790 return(1);
791 }
792
793
794 /* ARGSUSED */
795 static int
796 termp_pp_pre(DECL_ARGS)
797 {
798
799 vspace(p);
800 return(1);
801 }
802
803
804 /* ARGSUSED */
805 static int
806 termp_st_pre(DECL_ARGS)
807 {
808 const char *cp;
809
810 if (node->child && (cp = mdoc_a2st(node->child->string)))
811 word(p, cp);
812 return(0);
813 }
814
815
816 /* ARGSUSED */
817 static int
818 termp_rs_pre(DECL_ARGS)
819 {
820
821 if (MDOC_BLOCK == node->type && node->prev)
822 vspace(p);
823 return(1);
824 }
825
826
827 /* ARGSUSED */
828 static int
829 termp_rv_pre(DECL_ARGS)
830 {
831 int i;
832
833 if (-1 == (i = arg_getattr(MDOC_Std, node)))
834 errx(1, "expected -std argument");
835 if (1 != node->args->argv[i].sz)
836 errx(1, "expected -std argument");
837
838 newln(p);
839 word(p, "The");
840
841 p->flags |= ttypes[TTYPE_FUNC_NAME];
842 word(p, *node->args->argv[i].value);
843 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
844 p->flags |= TERMP_NOSPACE;
845
846 word(p, "() function returns the value 0 if successful;");
847 word(p, "otherwise the value -1 is returned and the");
848 word(p, "global variable");
849
850 p->flags |= ttypes[TTYPE_VAR_DECL];
851 word(p, "errno");
852 p->flags &= ~ttypes[TTYPE_VAR_DECL];
853
854 word(p, "is set to indicate the error.");
855
856 return(1);
857 }
858
859
860 /* ARGSUSED */
861 static int
862 termp_ex_pre(DECL_ARGS)
863 {
864 int i;
865
866 if (-1 == (i = arg_getattr(MDOC_Std, node)))
867 errx(1, "expected -std argument");
868 if (1 != node->args->argv[i].sz)
869 errx(1, "expected -std argument");
870
871 word(p, "The");
872 p->flags |= ttypes[TTYPE_PROG];
873 word(p, *node->args->argv[i].value);
874 p->flags &= ~ttypes[TTYPE_PROG];
875 word(p, "utility exits 0 on success, and >0 if an error occurs.");
876
877 return(1);
878 }
879
880
881 /* ARGSUSED */
882 static int
883 termp_nd_pre(DECL_ARGS)
884 {
885
886 word(p, "\\-");
887 return(1);
888 }
889
890
891 /* ARGSUSED */
892 static void
893 termp_bl_post(DECL_ARGS)
894 {
895
896 if (MDOC_BLOCK == node->type)
897 newln(p);
898 }
899
900
901 /* ARGSUSED */
902 static void
903 termp_op_post(DECL_ARGS)
904 {
905
906 if (MDOC_BODY != node->type)
907 return;
908 p->flags |= TERMP_NOSPACE;
909 word(p, "\\(rB");
910 }
911
912
913 /* ARGSUSED */
914 static int
915 termp_xr_pre(DECL_ARGS)
916 {
917 const struct mdoc_node *n;
918
919 if (NULL == (n = node->child))
920 errx(1, "expected text line argument");
921 word(p, n->string);
922 if (NULL == (n = n->next))
923 return(0);
924 p->flags |= TERMP_NOSPACE;
925 word(p, "(");
926 p->flags |= TERMP_NOSPACE;
927 word(p, n->string);
928 p->flags |= TERMP_NOSPACE;
929 word(p, ")");
930 return(0);
931 }
932
933
934 /* ARGSUSED */
935 static int
936 termp_vt_pre(DECL_ARGS)
937 {
938
939 /* FIXME: this can be "type name". */
940 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
941 return(1);
942 }
943
944
945 /* ARGSUSED */
946 static void
947 termp_vt_post(DECL_ARGS)
948 {
949
950 if (node->sec == SEC_SYNOPSIS)
951 vspace(p);
952 }
953
954
955 /* ARGSUSED */
956 static int
957 termp_fd_pre(DECL_ARGS)
958 {
959
960 /*
961 * FIXME: this naming is bad. This value is used, in general,
962 * for the #include header or other preprocessor statement.
963 */
964 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_DECL]);
965 return(1);
966 }
967
968
969 /* ARGSUSED */
970 static void
971 termp_fd_post(DECL_ARGS)
972 {
973
974 if (node->sec != SEC_SYNOPSIS)
975 return;
976 newln(p);
977 if (node->next && MDOC_Fd != node->next->tok)
978 vspace(p);
979 }
980
981
982 /* ARGSUSED */
983 static int
984 termp_sh_pre(DECL_ARGS)
985 {
986
987 switch (node->type) {
988 case (MDOC_HEAD):
989 vspace(p);
990 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SECTION]);
991 break;
992 case (MDOC_BODY):
993 p->offset = INDENT;
994 break;
995 default:
996 break;
997 }
998 return(1);
999 }
1000
1001
1002 /* ARGSUSED */
1003 static void
1004 termp_sh_post(DECL_ARGS)
1005 {
1006
1007 switch (node->type) {
1008 case (MDOC_HEAD):
1009 newln(p);
1010 break;
1011 case (MDOC_BODY):
1012 newln(p);
1013 p->offset = 0;
1014 break;
1015 default:
1016 break;
1017 }
1018 }
1019
1020
1021 /* ARGSUSED */
1022 static int
1023 termp_op_pre(DECL_ARGS)
1024 {
1025
1026 switch (node->type) {
1027 case (MDOC_BODY):
1028 word(p, "\\(lB");
1029 p->flags |= TERMP_NOSPACE;
1030 break;
1031 default:
1032 break;
1033 }
1034 return(1);
1035 }
1036
1037
1038 /* ARGSUSED */
1039 static int
1040 termp_bt_pre(DECL_ARGS)
1041 {
1042
1043 word(p, "is currently in beta test.");
1044 return(1);
1045 }
1046
1047
1048 /* ARGSUSED */
1049 static int
1050 termp_lb_pre(DECL_ARGS)
1051 {
1052 const char *lb;
1053
1054 if (NULL == node->child)
1055 errx(1, "expected text line argument");
1056 if ((lb = mdoc_a2lib(node->child->string))) {
1057 word(p, lb);
1058 return(0);
1059 }
1060 word(p, "library");
1061 return(1);
1062 }
1063
1064
1065 /* ARGSUSED */
1066 static void
1067 termp_lb_post(DECL_ARGS)
1068 {
1069
1070 newln(p);
1071 }
1072
1073
1074 /* ARGSUSED */
1075 static int
1076 termp_ud_pre(DECL_ARGS)
1077 {
1078
1079 word(p, "currently under development.");
1080 return(1);
1081 }
1082
1083
1084 /* ARGSUSED */
1085 static int
1086 termp_d1_pre(DECL_ARGS)
1087 {
1088
1089 if (MDOC_BODY != node->type)
1090 return(1);
1091 newln(p);
1092 p->offset += (pair->offset = INDENT);
1093 return(1);
1094 }
1095
1096
1097 /* ARGSUSED */
1098 static void
1099 termp_d1_post(DECL_ARGS)
1100 {
1101
1102 if (MDOC_BODY != node->type)
1103 return;
1104 newln(p);
1105 p->offset -= pair->offset;
1106 }
1107
1108
1109 /* ARGSUSED */
1110 static int
1111 termp_aq_pre(DECL_ARGS)
1112 {
1113
1114 if (MDOC_BODY != node->type)
1115 return(1);
1116 word(p, "\\(la");
1117 p->flags |= TERMP_NOSPACE;
1118 return(1);
1119 }
1120
1121
1122 /* ARGSUSED */
1123 static void
1124 termp_aq_post(DECL_ARGS)
1125 {
1126
1127 if (MDOC_BODY != node->type)
1128 return;
1129 p->flags |= TERMP_NOSPACE;
1130 word(p, "\\(ra");
1131 }
1132
1133
1134 /* ARGSUSED */
1135 static int
1136 termp_ft_pre(DECL_ARGS)
1137 {
1138
1139 if (SEC_SYNOPSIS == node->sec)
1140 if (node->prev && MDOC_Fo == node->prev->tok)
1141 vspace(p);
1142 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_TYPE]);
1143 return(1);
1144 }
1145
1146
1147 /* ARGSUSED */
1148 static void
1149 termp_ft_post(DECL_ARGS)
1150 {
1151
1152 if (SEC_SYNOPSIS == node->sec)
1153 newln(p);
1154 }
1155
1156
1157 /* ARGSUSED */
1158 static int
1159 termp_fn_pre(DECL_ARGS)
1160 {
1161 const struct mdoc_node *n;
1162
1163 if (NULL == node->child)
1164 errx(1, "expected text line arguments");
1165
1166 /* FIXME: can be "type funcname" "type varname"... */
1167
1168 p->flags |= ttypes[TTYPE_FUNC_NAME];
1169 word(p, node->child->string);
1170 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1171
1172 word(p, "(");
1173
1174 p->flags |= TERMP_NOSPACE;
1175 for (n = node->child->next; n; n = n->next) {
1176 p->flags |= ttypes[TTYPE_FUNC_ARG];
1177 word(p, n->string);
1178 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1179 if (n->next)
1180 word(p, ",");
1181 }
1182
1183 word(p, ")");
1184
1185 if (SEC_SYNOPSIS == node->sec)
1186 word(p, ";");
1187
1188 return(0);
1189 }
1190
1191
1192 /* ARGSUSED */
1193 static void
1194 termp_fn_post(DECL_ARGS)
1195 {
1196
1197 if (node->sec == SEC_SYNOPSIS && node->next)
1198 vspace(p);
1199
1200 }
1201
1202
1203 /* ARGSUSED */
1204 static int
1205 termp_sx_pre(DECL_ARGS)
1206 {
1207
1208 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK]);
1209 return(1);
1210 }
1211
1212
1213 /* ARGSUSED */
1214 static int
1215 termp_fa_pre(DECL_ARGS)
1216 {
1217 struct mdoc_node *n;
1218
1219 if (node->parent->tok != MDOC_Fo) {
1220 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_ARG]);
1221 return(1);
1222 }
1223
1224 for (n = node->child; n; n = n->next) {
1225 p->flags |= ttypes[TTYPE_FUNC_ARG];
1226 word(p, n->string);
1227 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1228 if (n->next)
1229 word(p, ",");
1230 }
1231
1232 if (node->next && node->next->tok == MDOC_Fa)
1233 word(p, ",");
1234
1235 return(0);
1236 }
1237
1238
1239 /* ARGSUSED */
1240 static int
1241 termp_va_pre(DECL_ARGS)
1242 {
1243
1244 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
1245 return(1);
1246 }
1247
1248
1249 /* ARGSUSED */
1250 static int
1251 termp_bd_pre(DECL_ARGS)
1252 {
1253 const struct mdoc_node *n;
1254 int i, type;
1255
1256 if (MDOC_BLOCK == node->type) {
1257 /* FIXME: parent prev? */
1258 if (node->prev)
1259 vspace(p);
1260 return(1);
1261 } else if (MDOC_BODY != node->type)
1262 return(1);
1263
1264 if (NULL == node->parent->args)
1265 errx(1, "missing display type");
1266
1267 pair->offset = p->offset;
1268
1269 for (type = -1, i = 0;
1270 i < (int)node->parent->args->argc; i++) {
1271 switch (node->parent->args->argv[i].arg) {
1272 case (MDOC_Ragged):
1273 /* FALLTHROUGH */
1274 case (MDOC_Filled):
1275 /* FALLTHROUGH */
1276 case (MDOC_Unfilled):
1277 /* FALLTHROUGH */
1278 case (MDOC_Literal):
1279 type = node->parent->args->argv[i].arg;
1280 i = (int)node->parent->args->argc;
1281 break;
1282 default:
1283 break;
1284 }
1285 }
1286
1287 if (NULL == node->parent->args)
1288 errx(1, "missing display type");
1289
1290 i = arg_getattr(MDOC_Offset, node->parent);
1291 if (-1 != i) {
1292 if (1 != node->parent->args->argv[i].sz)
1293 errx(1, "expected single value");
1294 p->offset += arg_offset(&node->parent->args->argv[i]);
1295 }
1296
1297 switch (type) {
1298 case (MDOC_Literal):
1299 /* FALLTHROUGH */
1300 case (MDOC_Unfilled):
1301 break;
1302 default:
1303 return(1);
1304 }
1305
1306 p->flags |= TERMP_LITERAL;
1307
1308 for (n = node->child; n; n = n->next) {
1309 if (MDOC_TEXT != n->type) {
1310 warnx("non-text children not yet allowed");
1311 continue;
1312 }
1313 word(p, n->string);
1314 flushln(p);
1315 }
1316
1317 return(0);
1318 }
1319
1320
1321 /* ARGSUSED */
1322 static void
1323 termp_bd_post(DECL_ARGS)
1324 {
1325
1326 if (MDOC_BODY != node->type)
1327 return;
1328
1329 if ( ! (p->flags & TERMP_LITERAL))
1330 flushln(p);
1331
1332 p->flags &= ~TERMP_LITERAL;
1333 p->offset = pair->offset;
1334 }
1335
1336
1337 /* ARGSUSED */
1338 static int
1339 termp_qq_pre(DECL_ARGS)
1340 {
1341
1342 if (MDOC_BODY != node->type)
1343 return(1);
1344 word(p, "\"");
1345 p->flags |= TERMP_NOSPACE;
1346 return(1);
1347 }
1348
1349
1350 /* ARGSUSED */
1351 static void
1352 termp_qq_post(DECL_ARGS)
1353 {
1354
1355 if (MDOC_BODY != node->type)
1356 return;
1357 p->flags |= TERMP_NOSPACE;
1358 word(p, "\"");
1359 }
1360
1361
1362 /* ARGSUSED */
1363 static int
1364 termp_bsx_pre(DECL_ARGS)
1365 {
1366
1367 word(p, "BSDI BSD/OS");
1368 return(1);
1369 }
1370
1371
1372 /* ARGSUSED */
1373 static void
1374 termp_bx_post(DECL_ARGS)
1375 {
1376
1377 if (node->child)
1378 p->flags |= TERMP_NOSPACE;
1379 word(p, "BSD");
1380 }
1381
1382
1383 /* ARGSUSED */
1384 static int
1385 termp_ox_pre(DECL_ARGS)
1386 {
1387
1388 word(p, "OpenBSD");
1389 return(1);
1390 }
1391
1392
1393 /* ARGSUSED */
1394 static int
1395 termp_ux_pre(DECL_ARGS)
1396 {
1397
1398 word(p, "UNIX");
1399 return(1);
1400 }
1401
1402
1403 /* ARGSUSED */
1404 static int
1405 termp_fx_pre(DECL_ARGS)
1406 {
1407
1408 word(p, "FreeBSD");
1409 return(1);
1410 }
1411
1412
1413 /* ARGSUSED */
1414 static int
1415 termp_nx_pre(DECL_ARGS)
1416 {
1417
1418 word(p, "NetBSD");
1419 return(1);
1420 }
1421
1422
1423 /* ARGSUSED */
1424 static int
1425 termp_sq_pre(DECL_ARGS)
1426 {
1427
1428 if (MDOC_BODY != node->type)
1429 return(1);
1430 word(p, "\\(oq");
1431 p->flags |= TERMP_NOSPACE;
1432 return(1);
1433 }
1434
1435
1436 /* ARGSUSED */
1437 static void
1438 termp_sq_post(DECL_ARGS)
1439 {
1440
1441 if (MDOC_BODY != node->type)
1442 return;
1443 p->flags |= TERMP_NOSPACE;
1444 word(p, "\\(aq");
1445 }
1446
1447
1448 /* ARGSUSED */
1449 static int
1450 termp_pf_pre(DECL_ARGS)
1451 {
1452
1453 p->flags |= TERMP_IGNDELIM;
1454 return(1);
1455 }
1456
1457
1458 /* ARGSUSED */
1459 static void
1460 termp_pf_post(DECL_ARGS)
1461 {
1462
1463 p->flags &= ~TERMP_IGNDELIM;
1464 p->flags |= TERMP_NOSPACE;
1465 }
1466
1467
1468 /* ARGSUSED */
1469 static int
1470 termp_ss_pre(DECL_ARGS)
1471 {
1472
1473 switch (node->type) {
1474 case (MDOC_BLOCK):
1475 newln(p);
1476 if (node->prev)
1477 vspace(p);
1478 break;
1479 case (MDOC_HEAD):
1480 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SSECTION]);
1481 p->offset = INDENT / 2;
1482 break;
1483 default:
1484 break;
1485 }
1486
1487 return(1);
1488 }
1489
1490
1491 /* ARGSUSED */
1492 static void
1493 termp_ss_post(DECL_ARGS)
1494 {
1495
1496 switch (node->type) {
1497 case (MDOC_HEAD):
1498 newln(p);
1499 p->offset = INDENT;
1500 break;
1501 default:
1502 break;
1503 }
1504 }
1505
1506
1507 /* ARGSUSED */
1508 static int
1509 termp_pa_pre(DECL_ARGS)
1510 {
1511
1512 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FILE]);
1513 return(1);
1514 }
1515
1516
1517 /* ARGSUSED */
1518 static int
1519 termp_em_pre(DECL_ARGS)
1520 {
1521
1522 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1523 return(1);
1524 }
1525
1526
1527 /* ARGSUSED */
1528 static int
1529 termp_cd_pre(DECL_ARGS)
1530 {
1531
1532 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CONFIG]);
1533 newln(p);
1534 return(1);
1535 }
1536
1537
1538 /* ARGSUSED */
1539 static int
1540 termp_cm_pre(DECL_ARGS)
1541 {
1542
1543 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
1544 return(1);
1545 }
1546
1547
1548 /* ARGSUSED */
1549 static int
1550 termp_ic_pre(DECL_ARGS)
1551 {
1552
1553 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD]);
1554 return(1);
1555 }
1556
1557
1558 /* ARGSUSED */
1559 static int
1560 termp_in_pre(DECL_ARGS)
1561 {
1562
1563 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_INCLUDE]);
1564 word(p, "#include");
1565 word(p, "<");
1566 p->flags |= TERMP_NOSPACE;
1567 return(1);
1568 }
1569
1570
1571 /* ARGSUSED */
1572 static void
1573 termp_in_post(DECL_ARGS)
1574 {
1575
1576 p->flags |= TERMP_NOSPACE;
1577 word(p, ">");
1578
1579 newln(p);
1580 if (SEC_SYNOPSIS != node->sec)
1581 return;
1582 if (node->next && MDOC_In != node->next->tok)
1583 vspace(p);
1584 }
1585
1586
1587 /* ARGSUSED */
1588 static int
1589 termp_at_pre(DECL_ARGS)
1590 {
1591 const char *att;
1592
1593 att = NULL;
1594
1595 if (node->child)
1596 att = mdoc_a2att(node->child->string);
1597 if (NULL == att)
1598 att = "AT&T UNIX";
1599
1600 word(p, att);
1601 return(0);
1602 }
1603
1604
1605 /* ARGSUSED */
1606 static int
1607 termp_brq_pre(DECL_ARGS)
1608 {
1609
1610 if (MDOC_BODY != node->type)
1611 return(1);
1612 word(p, "\\(lC");
1613 p->flags |= TERMP_NOSPACE;
1614 return(1);
1615 }
1616
1617
1618 /* ARGSUSED */
1619 static void
1620 termp_brq_post(DECL_ARGS)
1621 {
1622
1623 if (MDOC_BODY != node->type)
1624 return;
1625 p->flags |= TERMP_NOSPACE;
1626 word(p, "\\(rC");
1627 }
1628
1629
1630 /* ARGSUSED */
1631 static int
1632 termp_bq_pre(DECL_ARGS)
1633 {
1634
1635 if (MDOC_BODY != node->type)
1636 return(1);
1637 word(p, "\\(lB");
1638 p->flags |= TERMP_NOSPACE;
1639 return(1);
1640 }
1641
1642
1643 /* ARGSUSED */
1644 static void
1645 termp_bq_post(DECL_ARGS)
1646 {
1647
1648 if (MDOC_BODY != node->type)
1649 return;
1650 p->flags |= TERMP_NOSPACE;
1651 word(p, "\\(rB");
1652 }
1653
1654
1655 /* ARGSUSED */
1656 static int
1657 termp_pq_pre(DECL_ARGS)
1658 {
1659
1660 if (MDOC_BODY != node->type)
1661 return(1);
1662 word(p, "\\&(");
1663 p->flags |= TERMP_NOSPACE;
1664 return(1);
1665 }
1666
1667
1668 /* ARGSUSED */
1669 static void
1670 termp_pq_post(DECL_ARGS)
1671 {
1672
1673 if (MDOC_BODY != node->type)
1674 return;
1675 word(p, ")");
1676 }
1677
1678
1679 /* ARGSUSED */
1680 static int
1681 termp_fo_pre(DECL_ARGS)
1682 {
1683 const struct mdoc_node *n;
1684
1685 if (MDOC_BODY == node->type) {
1686 word(p, "(");
1687 p->flags |= TERMP_NOSPACE;
1688 return(1);
1689 } else if (MDOC_HEAD != node->type)
1690 return(1);
1691
1692 /* XXX - groff shows only first parameter */
1693
1694 p->flags |= ttypes[TTYPE_FUNC_NAME];
1695 for (n = node->child; n; n = n->next) {
1696 if (MDOC_TEXT != n->type)
1697 errx(1, "expected text line argument");
1698 word(p, n->string);
1699 }
1700 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1701
1702 return(0);
1703 }
1704
1705
1706 /* ARGSUSED */
1707 static void
1708 termp_fo_post(DECL_ARGS)
1709 {
1710
1711 if (MDOC_BODY != node->type)
1712 return;
1713 p->flags |= TERMP_NOSPACE;
1714 word(p, ")");
1715 p->flags |= TERMP_NOSPACE;
1716 word(p, ";");
1717 newln(p);
1718 }
1719
1720
1721 /* ARGSUSED */
1722 static int
1723 termp_bf_pre(DECL_ARGS)
1724 {
1725 const struct mdoc_node *n;
1726
1727 if (MDOC_HEAD == node->type) {
1728 return(0);
1729 } else if (MDOC_BLOCK != node->type)
1730 return(1);
1731
1732 if (NULL == (n = node->head->child)) {
1733 if (arg_hasattr(MDOC_Emphasis, node))
1734 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1735 else if (arg_hasattr(MDOC_Symbolic, node))
1736 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1737
1738 return(1);
1739 }
1740
1741 if (MDOC_TEXT != n->type)
1742 errx(1, "expected text line arguments");
1743
1744 if (0 == strcmp("Em", n->string))
1745 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1746 else if (0 == strcmp("Sy", n->string))
1747 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1748
1749 return(1);
1750 }
1751
1752
1753 /* ARGSUSED */
1754 static int
1755 termp_sy_pre(DECL_ARGS)
1756 {
1757
1758 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1759 return(1);
1760 }
1761
1762
1763 /* ARGSUSED */
1764 static int
1765 termp_ms_pre(DECL_ARGS)
1766 {
1767
1768 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMBOL]);
1769 return(1);
1770 }
1771
1772
1773
1774 /* ARGSUSED */
1775 static int
1776 termp_sm_pre(DECL_ARGS)
1777 {
1778
1779 #if notyet
1780 assert(node->child);
1781 if (0 == strcmp("off", node->child->data.text.string)) {
1782 p->flags &= ~TERMP_NONOSPACE;
1783 p->flags &= ~TERMP_NOSPACE;
1784 } else {
1785 p->flags |= TERMP_NONOSPACE;
1786 p->flags |= TERMP_NOSPACE;
1787 }
1788 #endif
1789
1790 return(0);
1791 }
1792
1793
1794 /* ARGSUSED */
1795 static int
1796 termp_ap_pre(DECL_ARGS)
1797 {
1798
1799 p->flags |= TERMP_NOSPACE;
1800 word(p, "\\(aq");
1801 p->flags |= TERMP_NOSPACE;
1802 return(1);
1803 }
1804
1805
1806 /* ARGSUSED */
1807 static int
1808 termp__t_pre(DECL_ARGS)
1809 {
1810
1811 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_REF_TITLE]);
1812 return(1);
1813 }
1814
1815
1816 /* ARGSUSED */
1817 static void
1818 termp____post(DECL_ARGS)
1819 {
1820
1821 p->flags |= TERMP_NOSPACE;
1822 word(p, node->next ? "," : ".");
1823 }
1824
1825
1826 /* ARGSUSED */
1827 static int
1828 termp_lk_pre(DECL_ARGS)
1829 {
1830 const struct mdoc_node *n;
1831
1832 if (NULL == (n = node->child))
1833 errx(1, "expected line argument");
1834
1835 p->flags |= ttypes[TTYPE_LINK_ANCHOR];
1836 word(p, n->string);
1837 p->flags &= ~ttypes[TTYPE_LINK_ANCHOR];
1838 p->flags |= TERMP_NOSPACE;
1839 word(p, ":");
1840
1841 p->flags |= ttypes[TTYPE_LINK_TEXT];
1842 for ( ; n; n = n->next) {
1843 word(p, n->string);
1844 }
1845 p->flags &= ~ttypes[TTYPE_LINK_TEXT];
1846
1847 return(0);
1848 }
1849
1850
1851 /* ARGSUSED */
1852 static int
1853 termp_mt_pre(DECL_ARGS)
1854 {
1855
1856 TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK_ANCHOR]);
1857 return(1);
1858 }
1859