]> git.cameronkatri.com Git - mandoc.git/blob - term.c
Considerable mdoc.3 documentation.
[mandoc.git] / term.c
1 /* $Id: term.c,v 1.10 2009/02/23 09:33:34 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 <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "term.h"
24
25 #define INDENT 4
26
27 /*
28 * Performs actions on nodes of the abstract syntax tree. Both pre- and
29 * post-fix operations are defined here.
30 */
31
32 /* FIXME: indent/tab. */
33
34 #define TTYPE_PROG 0
35 #define TTYPE_CMD_FLAG 1
36 #define TTYPE_CMD_ARG 2
37 #define TTYPE_SECTION 3
38 #define TTYPE_FUNC_DECL 4
39 #define TTYPE_VAR_DECL 5
40 #define TTYPE_FUNC_TYPE 6
41 #define TTYPE_FUNC_NAME 7
42 #define TTYPE_FUNC_ARG 8
43 #define TTYPE_LINK 9
44 #define TTYPE_SSECTION 10
45 #define TTYPE_FILE 11
46 #define TTYPE_NMAX 12
47
48 /*
49 * These define "styles" for element types, like command arguments or
50 * executable names. This is useful when multiple macros must decorate
51 * the same thing (like .Ex -std cmd and .Nm cmd).
52 */
53
54 const int ttypes[TTYPE_NMAX] = {
55 TERMP_BOLD, /* TTYPE_PROG */
56 TERMP_BOLD, /* TTYPE_CMD_FLAG */
57 TERMP_UNDERLINE, /* TTYPE_CMD_ARG */
58 TERMP_BOLD, /* TTYPE_SECTION */
59 TERMP_BOLD, /* TTYPE_FUNC_DECL */
60 TERMP_UNDERLINE, /* TTYPE_VAR_DECL */
61 TERMP_UNDERLINE, /* TTYPE_FUNC_TYPE */
62 TERMP_BOLD, /* TTYPE_FUNC_NAME */
63 TERMP_UNDERLINE, /* TTYPE_FUNC_ARG */
64 TERMP_UNDERLINE, /* TTYPE_LINK */
65 TERMP_BOLD, /* TTYPE_SSECTION */
66 TERMP_UNDERLINE /* TTYPE_FILE */
67 };
68
69 static int arg_hasattr(int, size_t,
70 const struct mdoc_arg *);
71 static int arg_getattr(int, size_t,
72 const struct mdoc_arg *);
73 static size_t arg_offset(const char *);
74
75 /*
76 * What follows describes prefix and postfix operations for the abstract
77 * syntax tree descent.
78 */
79
80 #define DECL_ARGS \
81 struct termp *p, \
82 const struct mdoc_meta *meta, \
83 const struct mdoc_node *node
84
85 #define DECL_PRE(name) \
86 static int name##_pre(DECL_ARGS)
87 #define DECL_POST(name) \
88 static void name##_post(DECL_ARGS)
89 #define DECL_PREPOST(name) \
90 DECL_PRE(name); \
91 DECL_POST(name);
92
93 DECL_PREPOST(termp_aq);
94 DECL_PREPOST(termp_ar);
95 DECL_PREPOST(termp_d1);
96 DECL_PREPOST(termp_dq);
97 DECL_PREPOST(termp_fa);
98 DECL_PREPOST(termp_fd);
99 DECL_PREPOST(termp_fl);
100 DECL_PREPOST(termp_fn);
101 DECL_PREPOST(termp_ft);
102 DECL_PREPOST(termp_it);
103 DECL_PREPOST(termp_nm);
104 DECL_PREPOST(termp_op);
105 DECL_PREPOST(termp_pa);
106 DECL_PREPOST(termp_pf);
107 DECL_PREPOST(termp_qq);
108 DECL_PREPOST(termp_sh);
109 DECL_PREPOST(termp_ss);
110 DECL_PREPOST(termp_sq);
111 DECL_PREPOST(termp_sx);
112 DECL_PREPOST(termp_va);
113 DECL_PREPOST(termp_vt);
114
115 DECL_PRE(termp_bd);
116 DECL_PRE(termp_bx);
117 DECL_PRE(termp_ex);
118 DECL_PRE(termp_nd);
119 DECL_PRE(termp_ns);
120 DECL_PRE(termp_nx);
121 DECL_PRE(termp_ox);
122 DECL_PRE(termp_pp);
123 DECL_PRE(termp_ud);
124 DECL_PRE(termp_xr);
125
126 DECL_POST(termp_bl);
127
128 const struct termact __termacts[MDOC_MAX] = {
129 { NULL, NULL }, /* \" */
130 { NULL, NULL }, /* Dd */
131 { NULL, NULL }, /* Dt */
132 { NULL, NULL }, /* Os */
133 { termp_sh_pre, termp_sh_post }, /* Sh */
134 { termp_ss_pre, termp_ss_post }, /* Ss */
135 { termp_pp_pre, NULL }, /* Pp */
136 { termp_d1_pre, termp_d1_post }, /* D1 */
137 { NULL, NULL }, /* Dl */
138 { termp_bd_pre, NULL }, /* Bd */
139 { NULL, NULL }, /* Ed */
140 { NULL, termp_bl_post }, /* Bl */
141 { NULL, NULL }, /* El */
142 { termp_it_pre, termp_it_post }, /* It */
143 { NULL, NULL }, /* Ad */
144 { NULL, NULL }, /* An */
145 { termp_ar_pre, termp_ar_post }, /* Ar */
146 { NULL, NULL }, /* Cd */
147 { NULL, NULL }, /* Cm */
148 { NULL, NULL }, /* Dv */
149 { NULL, NULL }, /* Er */
150 { NULL, NULL }, /* Ev */
151 { termp_ex_pre, NULL }, /* Ex */
152 { termp_fa_pre, termp_fa_post }, /* Fa */
153 { termp_fd_pre, termp_fd_post }, /* Fd */
154 { termp_fl_pre, termp_fl_post }, /* Fl */
155 { termp_fn_pre, termp_fn_post }, /* Fn */
156 { termp_ft_pre, termp_ft_post }, /* Ft */
157 { NULL, NULL }, /* Ic */
158 { NULL, NULL }, /* In */
159 { NULL, NULL }, /* Li */
160 { termp_nd_pre, NULL }, /* Nd */
161 { termp_nm_pre, termp_nm_post }, /* Nm */
162 { termp_op_pre, termp_op_post }, /* Op */
163 { NULL, NULL }, /* Ot */
164 { termp_pa_pre, termp_pa_post }, /* Pa */
165 { NULL, NULL }, /* Rv */
166 { NULL, NULL }, /* St */
167 { termp_va_pre, termp_va_post }, /* Va */
168 { termp_vt_pre, termp_vt_post }, /* Vt */
169 { termp_xr_pre, NULL }, /* Xr */
170 { NULL, NULL }, /* %A */
171 { NULL, NULL }, /* %B */
172 { NULL, NULL }, /* %D */
173 { NULL, NULL }, /* %I */
174 { NULL, NULL }, /* %J */
175 { NULL, NULL }, /* %N */
176 { NULL, NULL }, /* %O */
177 { NULL, NULL }, /* %P */
178 { NULL, NULL }, /* %R */
179 { NULL, NULL }, /* %T */
180 { NULL, NULL }, /* %V */
181 { NULL, NULL }, /* Ac */
182 { NULL, NULL }, /* Ao */
183 { termp_aq_pre, termp_aq_post }, /* Aq */
184 { NULL, NULL }, /* At */
185 { NULL, NULL }, /* Bc */
186 { NULL, NULL }, /* Bf */
187 { NULL, NULL }, /* Bo */
188 { NULL, NULL }, /* Bq */
189 { NULL, NULL }, /* Bsx */
190 { termp_bx_pre, NULL }, /* Bx */
191 { NULL, NULL }, /* Db */
192 { NULL, NULL }, /* Dc */
193 { NULL, NULL }, /* Do */
194 { termp_dq_pre, termp_dq_post }, /* Dq */
195 { NULL, NULL }, /* Ec */
196 { NULL, NULL }, /* Ef */
197 { NULL, NULL }, /* Em */
198 { NULL, NULL }, /* Eo */
199 { NULL, NULL }, /* Fx */
200 { NULL, NULL }, /* Ms */
201 { NULL, NULL }, /* No */
202 { termp_ns_pre, NULL }, /* Ns */
203 { termp_nx_pre, NULL }, /* Nx */
204 { termp_ox_pre, NULL }, /* Ox */
205 { NULL, NULL }, /* Pc */
206 { termp_pf_pre, termp_pf_post }, /* Pf */
207 { NULL, NULL }, /* Po */
208 { NULL, NULL }, /* Pq */
209 { NULL, NULL }, /* Qc */
210 { NULL, NULL }, /* Ql */
211 { NULL, NULL }, /* Qo */
212 { termp_qq_pre, termp_qq_post }, /* Qq */
213 { NULL, NULL }, /* Re */
214 { NULL, NULL }, /* Rs */
215 { NULL, NULL }, /* Sc */
216 { NULL, NULL }, /* So */
217 { termp_sq_pre, termp_sq_post }, /* Sq */
218 { NULL, NULL }, /* Sm */
219 { termp_sx_pre, termp_sx_post }, /* Sx */
220 { NULL, NULL }, /* Sy */
221 { NULL, NULL }, /* Tn */
222 { NULL, NULL }, /* Ux */
223 { NULL, NULL }, /* Xc */
224 { NULL, NULL }, /* Xo */
225 { NULL, NULL }, /* Fo */
226 { NULL, NULL }, /* Fc */
227 { NULL, NULL }, /* Oo */
228 { NULL, NULL }, /* Oc */
229 { NULL, NULL }, /* Bk */
230 { NULL, NULL }, /* Ek */
231 { NULL, NULL }, /* Bt */
232 { NULL, NULL }, /* Hf */
233 { NULL, NULL }, /* Fr */
234 { termp_ud_pre, NULL }, /* Ud */
235 };
236
237 const struct termact *termacts = __termacts;
238
239
240 static size_t
241 arg_offset(const char *v)
242 {
243 if (0 == strcmp(v, "indent"))
244 return(INDENT);
245 if (0 == strcmp(v, "indent-two"))
246 return(INDENT * 2);
247
248 /* TODO */
249 return(0);
250 }
251
252
253 static int
254 arg_hasattr(int arg, size_t argc, const struct mdoc_arg *argv)
255 {
256
257 return(-1 != arg_getattr(arg, argc, argv));
258 }
259
260
261 static int
262 arg_getattr(int arg, size_t argc, const struct mdoc_arg *argv)
263 {
264 int i;
265
266 for (i = 0; i < (int)argc; i++)
267 if (argv[i].arg == arg)
268 return(i);
269 return(-1);
270 }
271
272
273 /* ARGSUSED */
274 static int
275 termp_dq_pre(DECL_ARGS)
276 {
277
278 if (MDOC_BODY != node->type)
279 return(1);
280
281 word(p, "``");
282 p->flags |= TERMP_NOSPACE;
283 return(1);
284 }
285
286
287 /* ARGSUSED */
288 static void
289 termp_dq_post(DECL_ARGS)
290 {
291
292 if (MDOC_BODY != node->type)
293 return;
294
295 p->flags |= TERMP_NOSPACE;
296 word(p, "''");
297 }
298
299
300 /* ARGSUSED */
301 static void
302 termp_it_post(DECL_ARGS)
303 {
304 const struct mdoc_node *n, *it;
305 const struct mdoc_block *bl;
306 int i;
307 size_t width;
308
309 /*
310 * This (and termp_it_pre()) are the most complicated functions
311 * here. They must account for a considerable number of
312 * switches that completely change the output behaviour, like
313 * -tag versus -column. Yech.
314 */
315
316 switch (node->type) {
317 case (MDOC_BODY):
318 /* FALLTHROUGH */
319 case (MDOC_HEAD):
320 break;
321 default:
322 return;
323 }
324
325 it = node->parent;
326 assert(MDOC_BLOCK == it->type);
327 assert(MDOC_It == it->tok);
328
329 n = it->parent;
330 assert(MDOC_BODY == n->type);
331 assert(MDOC_Bl == n->tok);
332 n = n->parent;
333 bl = &n->data.block;
334
335 /* If `-tag', adjust our margins accordingly. */
336
337 if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
338 i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
339 assert(i >= 0);
340 assert(1 == bl->argv[i].sz);
341 width = strlen(*bl->argv[i].value); /* XXX */
342
343 if (MDOC_HEAD == node->type) {
344 flushln(p);
345 /* FIXME: nested lists. */
346 p->rmargin = p->maxrmargin;
347 p->flags &= ~TERMP_NOBREAK;
348 } else {
349 flushln(p);
350 p->offset -= width + 1;
351 p->flags &= ~TERMP_NOLPAD;
352 }
353 return;
354 }
355
356 if (arg_hasattr(MDOC_Ohang, bl->argc, bl->argv)) {
357 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
358 width = 0;
359 if (i >= 0) {
360 assert(1 == bl->argv[i].sz);
361 width = arg_offset(*bl->argv[i].value);
362 }
363
364 flushln(p);
365 p->offset -= width;
366 return;
367 }
368 }
369
370
371 /* ARGSUSED */
372 static int
373 termp_it_pre(DECL_ARGS)
374 {
375 const struct mdoc_node *n, *it;
376 const struct mdoc_block *bl;
377 int i;
378 size_t width;
379
380 /*
381 * Also see termp_it_post() for general comments.
382 */
383
384 switch (node->type) {
385 case (MDOC_BODY):
386 /* FALLTHROUGH */
387 case (MDOC_HEAD):
388 it = node->parent;
389 break;
390 case (MDOC_BLOCK):
391 it = node;
392 break;
393 default:
394 return(1);
395 }
396
397 assert(MDOC_BLOCK == it->type);
398 assert(MDOC_It == it->tok);
399
400 n = it->parent;
401 assert(MDOC_BODY == n->type);
402 assert(MDOC_Bl == n->tok);
403 n = n->parent;
404 bl = &n->data.block;
405
406 /* If `-compact', don't assert vertical space. */
407
408 if (MDOC_BLOCK == node->type) {
409 if (arg_hasattr(MDOC_Compact, bl->argc, bl->argv))
410 newln(p);
411 else
412 vspace(p);
413 return(1);
414 }
415
416 assert(MDOC_HEAD == node->type
417 || MDOC_BODY == node->type);
418
419 /* If `-tag', adjust our margins accordingly. */
420
421 if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
422 i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
423 assert(i >= 0); /* XXX */
424 assert(1 == bl->argv[i].sz);
425 width = strlen(*bl->argv[i].value); /* XXX */
426
427 /* FIXME: nested lists. */
428
429 if (MDOC_HEAD == node->type) {
430 p->flags |= TERMP_NOBREAK;
431 p->flags |= TERMP_NOSPACE;
432 p->rmargin = p->offset + width;
433 } else {
434 p->flags |= TERMP_NOSPACE;
435 p->flags |= TERMP_NOLPAD;
436 p->offset += width + 1;
437 }
438 return(1);
439 }
440
441 /* If `-ohang', adjust left-margin. */
442
443 if (arg_hasattr(MDOC_Ohang, bl->argc, bl->argv)) {
444 width = 0;
445 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
446 if (i >= 0) {
447 assert(1 == bl->argv[i].sz);
448 width = arg_offset(*bl->argv[i].value);
449 }
450
451 p->flags |= TERMP_NOSPACE;
452 p->offset += width;
453 return(1);
454 }
455
456 return(1);
457 }
458
459
460 /* ARGSUSED */
461 static void
462 termp_nm_post(DECL_ARGS)
463 {
464
465 p->flags &= ~ttypes[TTYPE_PROG];
466 }
467
468
469 /* ARGSUSED */
470 static void
471 termp_fl_post(DECL_ARGS)
472 {
473
474 p->flags &= ~ttypes[TTYPE_CMD_FLAG];
475 }
476
477
478 /* ARGSUSED */
479 static int
480 termp_ar_pre(DECL_ARGS)
481 {
482
483 p->flags |= ttypes[TTYPE_CMD_ARG];
484 if (NULL == node->child)
485 word(p, "...");
486 return(1);
487 }
488
489
490 /* ARGSUSED */
491 static int
492 termp_nm_pre(DECL_ARGS)
493 {
494
495 p->flags |= ttypes[TTYPE_PROG];
496 if (NULL == node->child)
497 word(p, meta->name);
498 return(1);
499 }
500
501
502 /* ARGSUSED */
503 static int
504 termp_ns_pre(DECL_ARGS)
505 {
506
507 p->flags |= TERMP_NOSPACE;
508 return(1);
509 }
510
511
512 /* ARGSUSED */
513 static int
514 termp_pp_pre(DECL_ARGS)
515 {
516
517 vspace(p);
518 return(1);
519 }
520
521
522 /* ARGSUSED */
523 static void
524 termp_ar_post(DECL_ARGS)
525 {
526
527 p->flags &= ~ttypes[TTYPE_CMD_ARG];
528 }
529
530
531 /* ARGSUSED */
532 static int
533 termp_ex_pre(DECL_ARGS)
534 {
535 int i;
536
537 i = arg_getattr(MDOC_Std, node->data.elem.argc,
538 node->data.elem.argv);
539 assert(i >= 0);
540
541 word(p, "The");
542 p->flags |= ttypes[TTYPE_PROG];
543 word(p, *node->data.elem.argv[i].value);
544 p->flags &= ~ttypes[TTYPE_PROG];
545 word(p, "utility exits 0 on success, and >0 if an error occurs.");
546
547 return(1);
548 }
549
550
551 /* ARGSUSED */
552 static int
553 termp_nd_pre(DECL_ARGS)
554 {
555
556 word(p, "\\-");
557 return(1);
558 }
559
560
561 /* ARGSUSED */
562 static void
563 termp_bl_post(DECL_ARGS)
564 {
565
566 if (MDOC_BLOCK == node->type)
567 newln(p);
568 }
569
570
571 /* ARGSUSED */
572 static void
573 termp_op_post(DECL_ARGS)
574 {
575
576 if (MDOC_BODY != node->type)
577 return;
578 p->flags |= TERMP_NOSPACE;
579 word(p, "\\(rB");
580 }
581
582
583 /* ARGSUSED */
584 static void
585 termp_sh_post(DECL_ARGS)
586 {
587
588 switch (node->type) {
589 case (MDOC_HEAD):
590 p->flags &= ~ttypes[TTYPE_SECTION];
591 newln(p);
592 break;
593 case (MDOC_BODY):
594 newln(p);
595 p->offset = 0;
596 break;
597 default:
598 break;
599 }
600 }
601
602
603 /* ARGSUSED */
604 static int
605 termp_xr_pre(DECL_ARGS)
606 {
607 const struct mdoc_node *n;
608
609 n = node->child;
610 assert(n);
611
612 assert(MDOC_TEXT == n->type);
613 word(p, n->data.text.string);
614
615 if (NULL == (n = n->next))
616 return(0);
617
618 assert(MDOC_TEXT == n->type);
619 p->flags |= TERMP_NOSPACE;
620 word(p, "(");
621 p->flags |= TERMP_NOSPACE;
622 word(p, n->data.text.string);
623 p->flags |= TERMP_NOSPACE;
624 word(p, ")");
625
626 return(0);
627 }
628
629
630 /* ARGSUSED */
631 static int
632 termp_vt_pre(DECL_ARGS)
633 {
634
635 /* FIXME: this can be "type name". */
636 p->flags |= ttypes[TTYPE_VAR_DECL];
637 return(1);
638 }
639
640
641 /* ARGSUSED */
642 static void
643 termp_vt_post(DECL_ARGS)
644 {
645
646 p->flags &= ~ttypes[TTYPE_VAR_DECL];
647 if (node->sec == SEC_SYNOPSIS)
648 vspace(p);
649 }
650
651
652 /* ARGSUSED */
653 static int
654 termp_fd_pre(DECL_ARGS)
655 {
656
657 /*
658 * FIXME: this naming is bad. This value is used, in general,
659 * for the #include header or other preprocessor statement.
660 */
661 p->flags |= ttypes[TTYPE_FUNC_DECL];
662 return(1);
663 }
664
665
666 /* ARGSUSED */
667 static void
668 termp_fd_post(DECL_ARGS)
669 {
670
671 p->flags &= ~ttypes[TTYPE_FUNC_DECL];
672 if (node->sec == SEC_SYNOPSIS)
673 vspace(p);
674
675 }
676
677
678 /* ARGSUSED */
679 static int
680 termp_sh_pre(DECL_ARGS)
681 {
682
683 switch (node->type) {
684 case (MDOC_HEAD):
685 vspace(p);
686 p->flags |= ttypes[TTYPE_SECTION];
687 break;
688 case (MDOC_BODY):
689 p->offset = INDENT;
690 break;
691 default:
692 break;
693 }
694 return(1);
695 }
696
697
698 /* ARGSUSED */
699 static int
700 termp_op_pre(DECL_ARGS)
701 {
702
703 switch (node->type) {
704 case (MDOC_BODY):
705 word(p, "\\(lB");
706 p->flags |= TERMP_NOSPACE;
707 break;
708 default:
709 break;
710 }
711 return(1);
712 }
713
714
715 /* ARGSUSED */
716 static int
717 termp_ud_pre(DECL_ARGS)
718 {
719
720 word(p, "currently under development.");
721 return(1);
722 }
723
724
725 /* ARGSUSED */
726 static int
727 termp_fl_pre(DECL_ARGS)
728 {
729
730 p->flags |= ttypes[TTYPE_CMD_FLAG];
731 word(p, "\\-");
732 p->flags |= TERMP_NOSPACE;
733 return(1);
734 }
735
736
737 /* ARGSUSED */
738 static int
739 termp_d1_pre(DECL_ARGS)
740 {
741
742 if (MDOC_BODY != node->type)
743 return(1);
744 newln(p);
745 p->offset += INDENT;
746 return(1);
747 }
748
749
750 /* ARGSUSED */
751 static void
752 termp_d1_post(DECL_ARGS)
753 {
754
755 if (MDOC_BODY != node->type)
756 return;
757 newln(p);
758 p->offset -= INDENT;
759 }
760
761
762 /* ARGSUSED */
763 static int
764 termp_aq_pre(DECL_ARGS)
765 {
766
767 if (MDOC_BODY != node->type)
768 return(1);
769 word(p, "<");
770 p->flags |= TERMP_NOSPACE;
771 return(1);
772 }
773
774
775 /* ARGSUSED */
776 static void
777 termp_aq_post(DECL_ARGS)
778 {
779
780 if (MDOC_BODY != node->type)
781 return;
782 p->flags |= TERMP_NOSPACE;
783 word(p, ">");
784 }
785
786
787 /* ARGSUSED */
788 static int
789 termp_ft_pre(DECL_ARGS)
790 {
791
792 p->flags |= ttypes[TTYPE_FUNC_TYPE];
793 return(1);
794 }
795
796
797 /* ARGSUSED */
798 static void
799 termp_ft_post(DECL_ARGS)
800 {
801
802 p->flags &= ~ttypes[TTYPE_FUNC_TYPE];
803 if (node->sec == SEC_SYNOPSIS)
804 newln(p);
805
806 }
807
808
809 /* ARGSUSED */
810 static int
811 termp_fn_pre(DECL_ARGS)
812 {
813 const struct mdoc_node *n;
814
815 assert(node->child);
816 assert(MDOC_TEXT == node->child->type);
817
818 /* FIXME: can be "type funcname" "type varname"... */
819
820 p->flags |= ttypes[TTYPE_FUNC_NAME];
821 word(p, node->child->data.text.string);
822 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
823
824 p->flags |= TERMP_NOSPACE;
825 word(p, "(");
826
827 p->flags |= TERMP_NOSPACE;
828 for (n = node->child->next; n; n = n->next) {
829 assert(MDOC_TEXT == n->type);
830 p->flags |= ttypes[TTYPE_FUNC_ARG];
831 word(p, n->data.text.string);
832 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
833 if ((n->next))
834 word(p, ",");
835 }
836
837 p->flags |= TERMP_NOSPACE;
838 word(p, ")");
839
840 if (SEC_SYNOPSIS == node->sec)
841 word(p, ";");
842
843 return(0);
844 }
845
846
847 /* ARGSUSED */
848 static void
849 termp_fn_post(DECL_ARGS)
850 {
851
852 if (node->sec == SEC_SYNOPSIS)
853 vspace(p);
854
855 }
856
857
858 /* ARGSUSED */
859 static int
860 termp_sx_pre(DECL_ARGS)
861 {
862
863 p->flags |= ttypes[TTYPE_LINK];
864 return(1);
865 }
866
867
868 /* ARGSUSED */
869 static void
870 termp_sx_post(DECL_ARGS)
871 {
872
873 p->flags &= ~ttypes[TTYPE_LINK];
874 }
875
876
877 /* ARGSUSED */
878 static int
879 termp_fa_pre(DECL_ARGS)
880 {
881
882 p->flags |= ttypes[TTYPE_FUNC_ARG];
883 return(1);
884 }
885
886
887 /* ARGSUSED */
888 static void
889 termp_fa_post(DECL_ARGS)
890 {
891
892 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
893 }
894
895
896 /* ARGSUSED */
897 static int
898 termp_va_pre(DECL_ARGS)
899 {
900
901 p->flags |= ttypes[TTYPE_VAR_DECL];
902 return(1);
903 }
904
905
906 /* ARGSUSED */
907 static void
908 termp_va_post(DECL_ARGS)
909 {
910
911 p->flags &= ~ttypes[TTYPE_VAR_DECL];
912 }
913
914
915 /* ARGSUSED */
916 static int
917 termp_bd_pre(DECL_ARGS)
918 {
919 const struct mdoc_block *bl;
920 const struct mdoc_node *n;
921
922 if (MDOC_BLOCK == node->type) {
923 vspace(p);
924 return(1);
925 } else if (MDOC_BODY != node->type)
926 return(1);
927
928 assert(MDOC_BLOCK == node->parent->type);
929
930 bl = &node->parent->data.block;
931 if ( ! arg_hasattr(MDOC_Literal, bl->argc, bl->argv))
932 return(1);
933
934 p->flags |= TERMP_LITERAL;
935
936 for (n = node->child; n; n = n->next) {
937 assert(MDOC_TEXT == n->type); /* FIXME */
938 if ((*n->data.text.string)) {
939 word(p, n->data.text.string);
940 flushln(p);
941 } else
942 vspace(p);
943
944 }
945
946 p->flags &= ~TERMP_LITERAL;
947 return(0);
948 }
949
950
951 /* ARGSUSED */
952 static int
953 termp_qq_pre(DECL_ARGS)
954 {
955
956 if (MDOC_BODY != node->type)
957 return(1);
958 word(p, "\"");
959 p->flags |= TERMP_NOSPACE;
960 return(1);
961 }
962
963
964 /* ARGSUSED */
965 static void
966 termp_qq_post(DECL_ARGS)
967 {
968
969 if (MDOC_BODY != node->type)
970 return;
971 p->flags |= TERMP_NOSPACE;
972 word(p, "\"");
973 }
974
975
976 /* ARGSUSED */
977 static int
978 termp_bx_pre(DECL_ARGS)
979 {
980
981 word(p, "BSD");
982 return(1);
983 }
984
985
986 /* ARGSUSED */
987 static int
988 termp_ox_pre(DECL_ARGS)
989 {
990
991 word(p, "OpenBSD");
992 return(1);
993 }
994
995
996 /* ARGSUSED */
997 static int
998 termp_nx_pre(DECL_ARGS)
999 {
1000
1001 word(p, "NetBSD");
1002 return(1);
1003 }
1004
1005
1006 /* ARGSUSED */
1007 static int
1008 termp_sq_pre(DECL_ARGS)
1009 {
1010
1011 if (MDOC_BODY != node->type)
1012 return(1);
1013 word(p, "`");
1014 p->flags |= TERMP_NOSPACE;
1015 return(1);
1016 }
1017
1018
1019 /* ARGSUSED */
1020 static void
1021 termp_sq_post(DECL_ARGS)
1022 {
1023
1024 if (MDOC_BODY != node->type)
1025 return;
1026 p->flags |= TERMP_NOSPACE;
1027 word(p, "\'");
1028 }
1029
1030
1031 /* ARGSUSED */
1032 static int
1033 termp_pf_pre(DECL_ARGS)
1034 {
1035
1036 p->flags |= TERMP_IGNDELIM;
1037 return(1);
1038 }
1039
1040
1041 /* ARGSUSED */
1042 static void
1043 termp_pf_post(DECL_ARGS)
1044 {
1045
1046 p->flags &= ~TERMP_IGNDELIM;
1047 p->flags |= TERMP_NOSPACE;
1048 }
1049
1050
1051 /* ARGSUSED */
1052 static int
1053 termp_ss_pre(DECL_ARGS)
1054 {
1055
1056 switch (node->type) {
1057 case (MDOC_HEAD):
1058 vspace(p);
1059 p->flags |= ttypes[TTYPE_SSECTION];
1060 p->offset = INDENT / 2;
1061 break;
1062 default:
1063 break;
1064 }
1065
1066 return(1);
1067 }
1068
1069
1070 /* ARGSUSED */
1071 static void
1072 termp_ss_post(DECL_ARGS)
1073 {
1074
1075 switch (node->type) {
1076 case (MDOC_HEAD):
1077 p->flags &= ~ttypes[TTYPE_SSECTION];
1078 newln(p);
1079 p->offset = INDENT;
1080 break;
1081 default:
1082 break;
1083 }
1084 }
1085
1086
1087 /* ARGSUSED */
1088 static int
1089 termp_pa_pre(DECL_ARGS)
1090 {
1091
1092 p->flags |= ttypes[TTYPE_FILE];
1093 return(1);
1094 }
1095
1096
1097 /* ARGSUSED */
1098 static void
1099 termp_pa_post(DECL_ARGS)
1100 {
1101
1102 p->flags &= ~ttypes[TTYPE_FILE];
1103 }