255b4e4e9b8f4e73b590e21361452cc384949af0
[mandoc.git] / term.c
1 /* $Id: term.c,v 1.17 2009/02/25 11:37:05 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 /* FIXME: handle nested lists. */
34
35 #define TTYPE_PROG 0
36 #define TTYPE_CMD_FLAG 1
37 #define TTYPE_CMD_ARG 2
38 #define TTYPE_SECTION 3
39 #define TTYPE_FUNC_DECL 4
40 #define TTYPE_VAR_DECL 5
41 #define TTYPE_FUNC_TYPE 6
42 #define TTYPE_FUNC_NAME 7
43 #define TTYPE_FUNC_ARG 8
44 #define TTYPE_LINK 9
45 #define TTYPE_SSECTION 10
46 #define TTYPE_FILE 11
47 #define TTYPE_EMPH 12
48 #define TTYPE_CONFIG 13
49 #define TTYPE_CMD 14
50 #define TTYPE_INCLUDE 15
51 #define TTYPE_SYMB 16
52 #define TTYPE_SYMBOL 17
53 #define TTYPE_NMAX 18
54
55 /*
56 * These define "styles" for element types, like command arguments or
57 * executable names. This is useful when multiple macros must decorate
58 * the same thing (like .Ex -std cmd and .Nm cmd).
59 */
60
61 const int ttypes[TTYPE_NMAX] = {
62 TERMP_BOLD, /* TTYPE_PROG */
63 TERMP_BOLD, /* TTYPE_CMD_FLAG */
64 TERMP_UNDERLINE, /* TTYPE_CMD_ARG */
65 TERMP_BOLD, /* TTYPE_SECTION */
66 TERMP_BOLD, /* TTYPE_FUNC_DECL */
67 TERMP_UNDERLINE, /* TTYPE_VAR_DECL */
68 TERMP_UNDERLINE, /* TTYPE_FUNC_TYPE */
69 TERMP_BOLD, /* TTYPE_FUNC_NAME */
70 TERMP_UNDERLINE, /* TTYPE_FUNC_ARG */
71 TERMP_UNDERLINE, /* TTYPE_LINK */
72 TERMP_BOLD, /* TTYPE_SSECTION */
73 TERMP_UNDERLINE, /* TTYPE_FILE */
74 TERMP_UNDERLINE, /* TTYPE_EMPH */
75 TERMP_BOLD, /* TTYPE_CONFIG */
76 TERMP_BOLD, /* TTYPE_CMD */
77 TERMP_BOLD, /* TTYPE_INCLUDE */
78 TERMP_BOLD, /* TTYPE_SYMB */
79 TERMP_BOLD /* TTYPE_SYMBOL */
80 };
81
82 static int arg_hasattr(int, size_t,
83 const struct mdoc_arg *);
84 static int arg_getattr(int, size_t,
85 const struct mdoc_arg *);
86 static size_t arg_offset(const struct mdoc_arg *);
87 static size_t arg_width(const struct mdoc_arg *);
88
89 /*
90 * What follows describes prefix and postfix operations for the abstract
91 * syntax tree descent.
92 */
93
94 #define DECL_ARGS \
95 struct termp *p, \
96 const struct mdoc_meta *meta, \
97 const struct mdoc_node *node
98
99 #define DECL_PRE(name) \
100 static int name##_pre(DECL_ARGS)
101 #define DECL_POST(name) \
102 static void name##_post(DECL_ARGS)
103 #define DECL_PREPOST(name) \
104 DECL_PRE(name); \
105 DECL_POST(name);
106
107 DECL_PREPOST(termp_aq);
108 DECL_PREPOST(termp_ar);
109 DECL_PREPOST(termp_bf);
110 DECL_PREPOST(termp_bd);
111 DECL_PREPOST(termp_bq);
112 DECL_PREPOST(termp_cd);
113 DECL_PREPOST(termp_cm);
114 DECL_PREPOST(termp_d1);
115 DECL_PREPOST(termp_dq);
116 DECL_PREPOST(termp_em);
117 DECL_PREPOST(termp_fa);
118 DECL_PREPOST(termp_fd);
119 DECL_PREPOST(termp_fl);
120 DECL_PREPOST(termp_fn);
121 DECL_PREPOST(termp_fo);
122 DECL_PREPOST(termp_ft);
123 DECL_PREPOST(termp_ic);
124 DECL_PREPOST(termp_in);
125 DECL_PREPOST(termp_it);
126 DECL_PREPOST(termp_ms);
127 DECL_PREPOST(termp_nm);
128 DECL_PREPOST(termp_op);
129 DECL_PREPOST(termp_pa);
130 DECL_PREPOST(termp_pf);
131 DECL_PREPOST(termp_pq);
132 DECL_PREPOST(termp_qq);
133 DECL_PREPOST(termp_sh);
134 DECL_PREPOST(termp_ss);
135 DECL_PREPOST(termp_sq);
136 DECL_PREPOST(termp_sx);
137 DECL_PREPOST(termp_sy);
138 DECL_PREPOST(termp_va);
139 DECL_PREPOST(termp_vt);
140
141 DECL_PRE(termp_at);
142 DECL_PRE(termp_bsx);
143 DECL_PRE(termp_bt);
144 DECL_PRE(termp_bx);
145 DECL_PRE(termp_ex);
146 DECL_PRE(termp_fx);
147 DECL_PRE(termp_nd);
148 DECL_PRE(termp_ns);
149 DECL_PRE(termp_nx);
150 DECL_PRE(termp_ox);
151 DECL_PRE(termp_pp);
152 DECL_PRE(termp_rv);
153 DECL_PRE(termp_st);
154 DECL_PRE(termp_ud);
155 DECL_PRE(termp_ux);
156 DECL_PRE(termp_xr);
157
158 DECL_POST(termp_bl);
159
160 const struct termact __termacts[MDOC_MAX] = {
161 { NULL, NULL }, /* \" */
162 { NULL, NULL }, /* Dd */
163 { NULL, NULL }, /* Dt */
164 { NULL, NULL }, /* Os */
165 { termp_sh_pre, termp_sh_post }, /* Sh */
166 { termp_ss_pre, termp_ss_post }, /* Ss */
167 { termp_pp_pre, NULL }, /* Pp */
168 { termp_d1_pre, termp_d1_post }, /* D1 */
169 { NULL, NULL }, /* Dl */
170 { termp_bd_pre, termp_bd_post }, /* Bd */
171 { NULL, NULL }, /* Ed */
172 { NULL, termp_bl_post }, /* Bl */
173 { NULL, NULL }, /* El */
174 { termp_it_pre, termp_it_post }, /* It */
175 { NULL, NULL }, /* Ad */
176 { NULL, NULL }, /* An */
177 { termp_ar_pre, termp_ar_post }, /* Ar */
178 { termp_cd_pre, termp_cd_post }, /* Cd */
179 { termp_cm_pre, termp_cm_post }, /* Cm */
180 { NULL, NULL }, /* Dv */
181 { NULL, NULL }, /* Er */
182 { NULL, NULL }, /* Ev */
183 { termp_ex_pre, NULL }, /* Ex */
184 { termp_fa_pre, termp_fa_post }, /* Fa */
185 { termp_fd_pre, termp_fd_post }, /* Fd */
186 { termp_fl_pre, termp_fl_post }, /* Fl */
187 { termp_fn_pre, termp_fn_post }, /* Fn */
188 { termp_ft_pre, termp_ft_post }, /* Ft */
189 { termp_ic_pre, termp_ic_post }, /* Ic */
190 { termp_in_pre, termp_in_post }, /* In */
191 { NULL, NULL }, /* Li */
192 { termp_nd_pre, NULL }, /* Nd */
193 { termp_nm_pre, termp_nm_post }, /* Nm */
194 { termp_op_pre, termp_op_post }, /* Op */
195 { NULL, NULL }, /* Ot */
196 { termp_pa_pre, termp_pa_post }, /* Pa */
197 { termp_rv_pre, NULL }, /* Rv */
198 { termp_st_pre, NULL }, /* St */
199 { termp_va_pre, termp_va_post }, /* Va */
200 { termp_vt_pre, termp_vt_post }, /* Vt */
201 { termp_xr_pre, NULL }, /* Xr */
202 { NULL, NULL }, /* %A */
203 { NULL, NULL }, /* %B */
204 { NULL, NULL }, /* %D */
205 { NULL, NULL }, /* %I */
206 { NULL, NULL }, /* %J */
207 { NULL, NULL }, /* %N */
208 { NULL, NULL }, /* %O */
209 { NULL, NULL }, /* %P */
210 { NULL, NULL }, /* %R */
211 { NULL, NULL }, /* %T */
212 { NULL, NULL }, /* %V */
213 { NULL, NULL }, /* Ac */
214 { termp_aq_pre, termp_aq_post }, /* Ao */
215 { termp_aq_pre, termp_aq_post }, /* Aq */
216 { termp_at_pre, NULL }, /* At */
217 { NULL, NULL }, /* Bc */
218 { termp_bf_pre, termp_bf_post }, /* Bf */
219 { termp_bq_pre, termp_bq_post }, /* Bo */
220 { termp_bq_pre, termp_bq_post }, /* Bq */
221 { termp_bsx_pre, NULL }, /* Bsx */
222 { termp_bx_pre, NULL }, /* Bx */
223 { NULL, NULL }, /* Db */
224 { NULL, NULL }, /* Dc */
225 { termp_dq_pre, termp_dq_post }, /* Do */
226 { termp_dq_pre, termp_dq_post }, /* Dq */
227 { NULL, NULL }, /* Ec */
228 { NULL, NULL }, /* Ef */
229 { termp_em_pre, termp_em_post }, /* Em */
230 { NULL, NULL }, /* Eo */
231 { termp_fx_pre, NULL }, /* Fx */
232 { termp_ms_pre, termp_ms_post }, /* Ms */
233 { NULL, NULL }, /* No */
234 { termp_ns_pre, NULL }, /* Ns */
235 { termp_nx_pre, NULL }, /* Nx */
236 { termp_ox_pre, NULL }, /* Ox */
237 { NULL, NULL }, /* Pc */
238 { termp_pf_pre, termp_pf_post }, /* Pf */
239 { termp_pq_pre, termp_pq_post }, /* Po */
240 { termp_pq_pre, termp_pq_post }, /* Pq */
241 { NULL, NULL }, /* Qc */
242 { termp_sq_pre, termp_sq_post }, /* Ql */
243 { termp_qq_pre, termp_qq_post }, /* Qo */
244 { termp_qq_pre, termp_qq_post }, /* Qq */
245 { NULL, NULL }, /* Re */
246 { NULL, NULL }, /* Rs */
247 { NULL, NULL }, /* Sc */
248 { termp_sq_pre, termp_sq_post }, /* So */
249 { termp_sq_pre, termp_sq_post }, /* Sq */
250 { NULL, NULL }, /* Sm */
251 { termp_sx_pre, termp_sx_post }, /* Sx */
252 { termp_sy_pre, termp_sy_post }, /* Sy */
253 { NULL, NULL }, /* Tn */
254 { termp_ux_pre, NULL }, /* Ux */
255 { NULL, NULL }, /* Xc */
256 { NULL, NULL }, /* Xo */
257 { termp_fo_pre, termp_fo_post }, /* Fo */
258 { NULL, NULL }, /* Fc */
259 { termp_op_pre, termp_op_post }, /* Oo */
260 { NULL, NULL }, /* Oc */
261 { NULL, NULL }, /* Bk */
262 { NULL, NULL }, /* Ek */
263 { termp_bt_pre, NULL }, /* Bt */
264 { NULL, NULL }, /* Hf */
265 { NULL, NULL }, /* Fr */
266 { termp_ud_pre, NULL }, /* Ud */
267 };
268
269 const struct termact *termacts = __termacts;
270
271
272 static size_t
273 arg_width(const struct mdoc_arg *arg)
274 {
275
276 /* TODO */
277 assert(*arg->value);
278 return(strlen(*arg->value));
279 }
280
281
282 static size_t
283 arg_offset(const struct mdoc_arg *arg)
284 {
285
286 /* TODO */
287 assert(*arg->value);
288 if (0 == strcmp(*arg->value, "indent"))
289 return(INDENT);
290 if (0 == strcmp(*arg->value, "indent-two"))
291 return(INDENT * 2);
292
293 return(strlen(*arg->value));
294 }
295
296
297 static int
298 arg_hasattr(int arg, size_t argc, const struct mdoc_arg *argv)
299 {
300
301 return(-1 != arg_getattr(arg, argc, argv));
302 }
303
304
305 static int
306 arg_getattr(int arg, size_t argc, const struct mdoc_arg *argv)
307 {
308 int i;
309
310 for (i = 0; i < (int)argc; i++)
311 if (argv[i].arg == arg)
312 return(i);
313 return(-1);
314 }
315
316
317 /* ARGSUSED */
318 static int
319 termp_dq_pre(DECL_ARGS)
320 {
321
322 if (MDOC_BODY != node->type)
323 return(1);
324
325 word(p, "``");
326 p->flags |= TERMP_NOSPACE;
327 return(1);
328 }
329
330
331 /* ARGSUSED */
332 static void
333 termp_dq_post(DECL_ARGS)
334 {
335
336 if (MDOC_BODY != node->type)
337 return;
338
339 p->flags |= TERMP_NOSPACE;
340 word(p, "''");
341 }
342
343
344 /* ARGSUSED */
345 static void
346 termp_it_post(DECL_ARGS)
347 {
348 const struct mdoc_node *n, *it;
349 const struct mdoc_block *bl;
350 int i;
351 size_t width, offset;
352
353 /*
354 * This (and termp_it_pre()) are the most complicated functions
355 * here. They must account for a considerable number of
356 * switches that completely change the output behaviour, like
357 * -tag versus -column. Yech.
358 */
359
360 switch (node->type) {
361 case (MDOC_BODY):
362 /* FALLTHROUGH */
363 case (MDOC_HEAD):
364 break;
365 default:
366 return;
367 }
368
369 it = node->parent;
370 assert(MDOC_BLOCK == it->type);
371 assert(MDOC_It == it->tok);
372
373 n = it->parent;
374 assert(MDOC_BODY == n->type);
375 assert(MDOC_Bl == n->tok);
376 n = n->parent;
377 bl = &n->data.block;
378
379 /* If `-tag', adjust our margins accordingly. */
380
381 if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
382 flushln(p);
383
384 /* FIXME: this should auto-size. */
385 i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
386 width = i >= 0 ? arg_width(&bl->argv[i]) : 10;
387
388 /* FIXME: nesting! Should happen at block. */
389 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
390 offset = i >= 0 ? arg_width(&bl->argv[i]) : 0;
391
392 if (MDOC_HEAD == node->type) {
393 p->rmargin = p->maxrmargin;
394 p->offset -= offset;
395 p->flags &= ~TERMP_NOBREAK;
396 } else {
397 p->offset -= width;
398 p->flags &= ~TERMP_NOLPAD;
399 }
400 }
401
402 if (arg_hasattr(MDOC_Ohang, bl->argc, bl->argv)) {
403 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
404 offset = i >= 0 ? arg_offset(&bl->argv[i]) : 0;
405
406 flushln(p);
407 p->offset -= offset;
408 return;
409 }
410 }
411
412
413 /* ARGSUSED */
414 static int
415 termp_it_pre(DECL_ARGS)
416 {
417 const struct mdoc_node *n, *it;
418 const struct mdoc_block *bl;
419 int i;
420 size_t width, offset;
421
422 /*
423 * Also see termp_it_post() for general comments.
424 */
425
426 switch (node->type) {
427 case (MDOC_BODY):
428 /* FALLTHROUGH */
429 case (MDOC_HEAD):
430 it = node->parent;
431 break;
432 case (MDOC_BLOCK):
433 it = node;
434 break;
435 default:
436 return(1);
437 }
438
439 assert(MDOC_BLOCK == it->type);
440 assert(MDOC_It == it->tok);
441
442 n = it->parent;
443 assert(MDOC_BODY == n->type);
444 assert(MDOC_Bl == n->tok);
445 n = n->parent;
446 bl = &n->data.block;
447
448 /* If `-compact', don't assert vertical space. */
449
450 if (MDOC_BLOCK == node->type) {
451 if (arg_hasattr(MDOC_Compact, bl->argc, bl->argv))
452 newln(p);
453 else
454 vspace(p);
455 return(1);
456 }
457
458 assert(MDOC_HEAD == node->type
459 || MDOC_BODY == node->type);
460
461 /* FIXME: see termp_it_post(). */
462
463 /* If `-tag', adjust our margins accordingly. */
464
465 if (arg_hasattr(MDOC_Tag, bl->argc, bl->argv)) {
466 p->flags |= TERMP_NOSPACE;
467
468 i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
469 width = i >= 0 ? arg_width(&bl->argv[i]) : 10;
470
471 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
472 offset = i >= 0 ? arg_offset(&bl->argv[i]) : 0;
473
474 if (MDOC_HEAD == node->type) {
475 p->flags |= TERMP_NOBREAK;
476 p->offset += offset;
477 p->rmargin = p->offset + width;
478 } else {
479 p->flags |= TERMP_NOSPACE;
480 p->flags |= TERMP_NOLPAD;
481 p->offset += width;
482 }
483 return(1);
484 }
485
486 /* If `-ohang', adjust left-margin. */
487
488 if (arg_hasattr(MDOC_Ohang, bl->argc, bl->argv)) {
489 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
490 offset = i >= 0 ? arg_offset(&bl->argv[i]) : 0;
491
492 p->flags |= TERMP_NOSPACE;
493 p->offset += offset;
494 return(1);
495 }
496
497 return(1);
498 }
499
500
501 /* ARGSUSED */
502 static void
503 termp_nm_post(DECL_ARGS)
504 {
505
506 p->flags &= ~ttypes[TTYPE_PROG];
507 }
508
509
510 /* ARGSUSED */
511 static void
512 termp_fl_post(DECL_ARGS)
513 {
514
515 p->flags &= ~ttypes[TTYPE_CMD_FLAG];
516 }
517
518
519 /* ARGSUSED */
520 static int
521 termp_ar_pre(DECL_ARGS)
522 {
523
524 p->flags |= ttypes[TTYPE_CMD_ARG];
525 if (NULL == node->child)
526 word(p, "...");
527 return(1);
528 }
529
530
531 /* ARGSUSED */
532 static int
533 termp_nm_pre(DECL_ARGS)
534 {
535
536 p->flags |= ttypes[TTYPE_PROG];
537 if (NULL == node->child)
538 word(p, meta->name);
539 return(1);
540 }
541
542
543 /* ARGSUSED */
544 static int
545 termp_ns_pre(DECL_ARGS)
546 {
547
548 p->flags |= TERMP_NOSPACE;
549 return(1);
550 }
551
552
553 /* ARGSUSED */
554 static int
555 termp_pp_pre(DECL_ARGS)
556 {
557
558 vspace(p);
559 return(1);
560 }
561
562
563 /* ARGSUSED */
564 static void
565 termp_ar_post(DECL_ARGS)
566 {
567
568 p->flags &= ~ttypes[TTYPE_CMD_ARG];
569 }
570
571
572 /* ARGSUSED */
573 static int
574 termp_st_pre(DECL_ARGS)
575 {
576 const char *tp;
577
578 assert(1 == node->data.elem.argc);
579
580 tp = mdoc_st2a(node->data.elem.argv[0].arg);
581 word(p, tp);
582
583 return(1);
584 }
585
586
587 /* ARGSUSED */
588 static int
589 termp_rv_pre(DECL_ARGS)
590 {
591 int i;
592
593 i = arg_getattr(MDOC_Std, node->data.elem.argc,
594 node->data.elem.argv);
595 assert(i >= 0);
596
597 newln(p);
598 word(p, "The");
599
600 p->flags |= ttypes[TTYPE_FUNC_NAME];
601 word(p, *node->data.elem.argv[i].value);
602 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
603
604 word(p, "() function returns the value 0 if successful;");
605 word(p, "otherwise the value -1 is returned and the");
606 word(p, "global variable");
607
608 p->flags |= ttypes[TTYPE_VAR_DECL];
609 word(p, "errno");
610 p->flags &= ~ttypes[TTYPE_VAR_DECL];
611
612 word(p, "is set to indicate the error.");
613
614 return(1);
615 }
616
617
618 /* ARGSUSED */
619 static int
620 termp_ex_pre(DECL_ARGS)
621 {
622 int i;
623
624 i = arg_getattr(MDOC_Std, node->data.elem.argc,
625 node->data.elem.argv);
626 assert(i >= 0);
627
628 word(p, "The");
629 p->flags |= ttypes[TTYPE_PROG];
630 word(p, *node->data.elem.argv[i].value);
631 p->flags &= ~ttypes[TTYPE_PROG];
632 word(p, "utility exits 0 on success, and >0 if an error occurs.");
633
634 return(1);
635 }
636
637
638 /* ARGSUSED */
639 static int
640 termp_nd_pre(DECL_ARGS)
641 {
642
643 word(p, "\\-");
644 return(1);
645 }
646
647
648 /* ARGSUSED */
649 static void
650 termp_bl_post(DECL_ARGS)
651 {
652
653 if (MDOC_BLOCK == node->type)
654 newln(p);
655 }
656
657
658 /* ARGSUSED */
659 static void
660 termp_op_post(DECL_ARGS)
661 {
662
663 if (MDOC_BODY != node->type)
664 return;
665 p->flags |= TERMP_NOSPACE;
666 word(p, "\\(rB");
667 }
668
669
670 /* ARGSUSED */
671 static void
672 termp_sh_post(DECL_ARGS)
673 {
674
675 switch (node->type) {
676 case (MDOC_HEAD):
677 p->flags &= ~ttypes[TTYPE_SECTION];
678 newln(p);
679 break;
680 case (MDOC_BODY):
681 newln(p);
682 p->offset = 0;
683 break;
684 default:
685 break;
686 }
687 }
688
689
690 /* ARGSUSED */
691 static int
692 termp_xr_pre(DECL_ARGS)
693 {
694 const struct mdoc_node *n;
695
696 n = node->child;
697 assert(n);
698
699 assert(MDOC_TEXT == n->type);
700 word(p, n->data.text.string);
701
702 if (NULL == (n = n->next))
703 return(0);
704
705 assert(MDOC_TEXT == n->type);
706 p->flags |= TERMP_NOSPACE;
707 word(p, "(");
708 p->flags |= TERMP_NOSPACE;
709 word(p, n->data.text.string);
710 p->flags |= TERMP_NOSPACE;
711 word(p, ")");
712
713 return(0);
714 }
715
716
717 /* ARGSUSED */
718 static int
719 termp_vt_pre(DECL_ARGS)
720 {
721
722 /* FIXME: this can be "type name". */
723 p->flags |= ttypes[TTYPE_VAR_DECL];
724 return(1);
725 }
726
727
728 /* ARGSUSED */
729 static void
730 termp_vt_post(DECL_ARGS)
731 {
732
733 p->flags &= ~ttypes[TTYPE_VAR_DECL];
734 if (node->sec == SEC_SYNOPSIS)
735 vspace(p);
736 }
737
738
739 /* ARGSUSED */
740 static int
741 termp_fd_pre(DECL_ARGS)
742 {
743
744 /*
745 * FIXME: this naming is bad. This value is used, in general,
746 * for the #include header or other preprocessor statement.
747 */
748 p->flags |= ttypes[TTYPE_FUNC_DECL];
749 return(1);
750 }
751
752
753 /* ARGSUSED */
754 static void
755 termp_fd_post(DECL_ARGS)
756 {
757
758 p->flags &= ~ttypes[TTYPE_FUNC_DECL];
759 if (node->sec == SEC_SYNOPSIS)
760 vspace(p);
761
762 }
763
764
765 /* ARGSUSED */
766 static int
767 termp_sh_pre(DECL_ARGS)
768 {
769
770 switch (node->type) {
771 case (MDOC_HEAD):
772 vspace(p);
773 p->flags |= ttypes[TTYPE_SECTION];
774 break;
775 case (MDOC_BODY):
776 p->offset = INDENT;
777 break;
778 default:
779 break;
780 }
781 return(1);
782 }
783
784
785 /* ARGSUSED */
786 static int
787 termp_op_pre(DECL_ARGS)
788 {
789
790 switch (node->type) {
791 case (MDOC_BODY):
792 word(p, "\\(lB");
793 p->flags |= TERMP_NOSPACE;
794 break;
795 default:
796 break;
797 }
798 return(1);
799 }
800
801
802 /* ARGSUSED */
803 static int
804 termp_bt_pre(DECL_ARGS)
805 {
806
807 word(p, "is currently in beta test.");
808 return(1);
809 }
810
811
812 /* ARGSUSED */
813 static int
814 termp_ud_pre(DECL_ARGS)
815 {
816
817 word(p, "currently under development.");
818 return(1);
819 }
820
821
822 /* ARGSUSED */
823 static int
824 termp_fl_pre(DECL_ARGS)
825 {
826
827 p->flags |= ttypes[TTYPE_CMD_FLAG];
828 word(p, "\\-");
829 p->flags |= TERMP_NOSPACE;
830 return(1);
831 }
832
833
834 /* ARGSUSED */
835 static int
836 termp_d1_pre(DECL_ARGS)
837 {
838
839 if (MDOC_BODY != node->type)
840 return(1);
841 newln(p);
842 p->offset += INDENT;
843 return(1);
844 }
845
846
847 /* ARGSUSED */
848 static void
849 termp_d1_post(DECL_ARGS)
850 {
851
852 if (MDOC_BODY != node->type)
853 return;
854 newln(p);
855 p->offset -= INDENT;
856 }
857
858
859 /* ARGSUSED */
860 static int
861 termp_aq_pre(DECL_ARGS)
862 {
863
864 if (MDOC_BODY != node->type)
865 return(1);
866 word(p, "<");
867 p->flags |= TERMP_NOSPACE;
868 return(1);
869 }
870
871
872 /* ARGSUSED */
873 static void
874 termp_aq_post(DECL_ARGS)
875 {
876
877 if (MDOC_BODY != node->type)
878 return;
879 p->flags |= TERMP_NOSPACE;
880 word(p, ">");
881 }
882
883
884 /* ARGSUSED */
885 static int
886 termp_ft_pre(DECL_ARGS)
887 {
888
889 p->flags |= ttypes[TTYPE_FUNC_TYPE];
890 return(1);
891 }
892
893
894 /* ARGSUSED */
895 static void
896 termp_ft_post(DECL_ARGS)
897 {
898
899 p->flags &= ~ttypes[TTYPE_FUNC_TYPE];
900 if (node->sec == SEC_SYNOPSIS)
901 newln(p);
902
903 }
904
905
906 /* ARGSUSED */
907 static int
908 termp_fn_pre(DECL_ARGS)
909 {
910 const struct mdoc_node *n;
911
912 assert(node->child);
913 assert(MDOC_TEXT == node->child->type);
914
915 /* FIXME: can be "type funcname" "type varname"... */
916
917 p->flags |= ttypes[TTYPE_FUNC_NAME];
918 word(p, node->child->data.text.string);
919 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
920
921 word(p, "(");
922
923 p->flags |= TERMP_NOSPACE;
924 for (n = node->child->next; n; n = n->next) {
925 assert(MDOC_TEXT == n->type);
926 p->flags |= ttypes[TTYPE_FUNC_ARG];
927 word(p, n->data.text.string);
928 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
929 if (n->next)
930 word(p, ",");
931 }
932
933 word(p, ")");
934
935 if (SEC_SYNOPSIS == node->sec)
936 word(p, ";");
937
938 return(0);
939 }
940
941
942 /* ARGSUSED */
943 static void
944 termp_fn_post(DECL_ARGS)
945 {
946
947 if (node->sec == SEC_SYNOPSIS)
948 vspace(p);
949
950 }
951
952
953 /* ARGSUSED */
954 static int
955 termp_sx_pre(DECL_ARGS)
956 {
957
958 p->flags |= ttypes[TTYPE_LINK];
959 return(1);
960 }
961
962
963 /* ARGSUSED */
964 static void
965 termp_sx_post(DECL_ARGS)
966 {
967
968 p->flags &= ~ttypes[TTYPE_LINK];
969 }
970
971
972 /* ARGSUSED */
973 static int
974 termp_fa_pre(DECL_ARGS)
975 {
976 struct mdoc_node *n;
977
978 if (node->parent->tok != MDOC_Fo) {
979 p->flags |= ttypes[TTYPE_FUNC_ARG];
980 return(1);
981 }
982
983 for (n = node->child; n; n = n->next) {
984 assert(MDOC_TEXT == n->type);
985
986 p->flags |= ttypes[TTYPE_FUNC_ARG];
987 word(p, n->data.text.string);
988 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
989
990 if (n->next)
991 word(p, ",");
992 }
993
994 if (node->next && node->next->tok == MDOC_Fa)
995 word(p, ",");
996
997 return(0);
998 }
999
1000
1001 /* ARGSUSED */
1002 static void
1003 termp_fa_post(DECL_ARGS)
1004 {
1005
1006 p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1007 }
1008
1009
1010 /* ARGSUSED */
1011 static int
1012 termp_va_pre(DECL_ARGS)
1013 {
1014
1015 p->flags |= ttypes[TTYPE_VAR_DECL];
1016 return(1);
1017 }
1018
1019
1020 /* ARGSUSED */
1021 static void
1022 termp_va_post(DECL_ARGS)
1023 {
1024
1025 p->flags &= ~ttypes[TTYPE_VAR_DECL];
1026 }
1027
1028
1029 /* ARGSUSED */
1030 static int
1031 termp_bd_pre(DECL_ARGS)
1032 {
1033 const struct mdoc_block *bl;
1034 const struct mdoc_node *n;
1035 int i;
1036
1037 if (MDOC_BLOCK == node->type) {
1038 vspace(p);
1039 return(1);
1040 } else if (MDOC_BODY != node->type)
1041 return(1);
1042
1043 assert(MDOC_BLOCK == node->parent->type);
1044
1045 bl = &node->parent->data.block;
1046
1047 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
1048 if (-1 != i) {
1049 assert(1 == bl->argv[i].sz);
1050 p->offset += arg_offset(&bl->argv[i]);
1051 }
1052
1053 if ( ! arg_hasattr(MDOC_Literal, bl->argc, bl->argv))
1054 return(1);
1055
1056 p->flags |= TERMP_LITERAL;
1057
1058 for (n = node->child; n; n = n->next) {
1059 assert(MDOC_TEXT == n->type); /* FIXME */
1060 if ((*n->data.text.string)) {
1061 word(p, n->data.text.string);
1062 flushln(p);
1063 } else
1064 vspace(p);
1065
1066 }
1067
1068 p->flags &= ~TERMP_LITERAL;
1069 return(0);
1070 }
1071
1072
1073 /* ARGSUSED */
1074 static void
1075 termp_bd_post(DECL_ARGS)
1076 {
1077 int i;
1078 const struct mdoc_block *bl;
1079
1080 if (MDOC_BODY != node->type)
1081 return;
1082
1083 assert(MDOC_BLOCK == node->parent->type);
1084 bl = &node->parent->data.block;
1085
1086 i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
1087 if (-1 != i) {
1088 assert(1 == bl->argv[i].sz);
1089 p->offset -= arg_offset(&bl->argv[i]);
1090 }
1091 }
1092
1093
1094 /* ARGSUSED */
1095 static int
1096 termp_qq_pre(DECL_ARGS)
1097 {
1098
1099 if (MDOC_BODY != node->type)
1100 return(1);
1101 word(p, "\"");
1102 p->flags |= TERMP_NOSPACE;
1103 return(1);
1104 }
1105
1106
1107 /* ARGSUSED */
1108 static void
1109 termp_qq_post(DECL_ARGS)
1110 {
1111
1112 if (MDOC_BODY != node->type)
1113 return;
1114 p->flags |= TERMP_NOSPACE;
1115 word(p, "\"");
1116 }
1117
1118
1119 /* ARGSUSED */
1120 static int
1121 termp_bsx_pre(DECL_ARGS)
1122 {
1123
1124 word(p, "BSDI BSD/OS");
1125 return(1);
1126 }
1127
1128
1129 /* ARGSUSED */
1130 static int
1131 termp_bx_pre(DECL_ARGS)
1132 {
1133
1134 word(p, "BSD");
1135 return(1);
1136 }
1137
1138
1139 /* ARGSUSED */
1140 static int
1141 termp_ox_pre(DECL_ARGS)
1142 {
1143
1144 word(p, "OpenBSD");
1145 return(1);
1146 }
1147
1148
1149 /* ARGSUSED */
1150 static int
1151 termp_ux_pre(DECL_ARGS)
1152 {
1153
1154 word(p, "UNIX");
1155 return(1);
1156 }
1157
1158
1159 /* ARGSUSED */
1160 static int
1161 termp_fx_pre(DECL_ARGS)
1162 {
1163
1164 word(p, "FreeBSD");
1165 return(1);
1166 }
1167
1168
1169 /* ARGSUSED */
1170 static int
1171 termp_nx_pre(DECL_ARGS)
1172 {
1173
1174 word(p, "NetBSD");
1175 return(1);
1176 }
1177
1178
1179 /* ARGSUSED */
1180 static int
1181 termp_sq_pre(DECL_ARGS)
1182 {
1183
1184 if (MDOC_BODY != node->type)
1185 return(1);
1186 word(p, "\'");
1187 p->flags |= TERMP_NOSPACE;
1188 return(1);
1189 }
1190
1191
1192 /* ARGSUSED */
1193 static void
1194 termp_sq_post(DECL_ARGS)
1195 {
1196
1197 if (MDOC_BODY != node->type)
1198 return;
1199 p->flags |= TERMP_NOSPACE;
1200 word(p, "\'");
1201 }
1202
1203
1204 /* ARGSUSED */
1205 static int
1206 termp_pf_pre(DECL_ARGS)
1207 {
1208
1209 p->flags |= TERMP_IGNDELIM;
1210 return(1);
1211 }
1212
1213
1214 /* ARGSUSED */
1215 static void
1216 termp_pf_post(DECL_ARGS)
1217 {
1218
1219 p->flags &= ~TERMP_IGNDELIM;
1220 p->flags |= TERMP_NOSPACE;
1221 }
1222
1223
1224 /* ARGSUSED */
1225 static int
1226 termp_ss_pre(DECL_ARGS)
1227 {
1228
1229 switch (node->type) {
1230 case (MDOC_HEAD):
1231 vspace(p);
1232 p->flags |= ttypes[TTYPE_SSECTION];
1233 p->offset = INDENT / 2;
1234 break;
1235 default:
1236 break;
1237 }
1238
1239 return(1);
1240 }
1241
1242
1243 /* ARGSUSED */
1244 static void
1245 termp_ss_post(DECL_ARGS)
1246 {
1247
1248 switch (node->type) {
1249 case (MDOC_HEAD):
1250 p->flags &= ~ttypes[TTYPE_SSECTION];
1251 newln(p);
1252 p->offset = INDENT;
1253 break;
1254 default:
1255 break;
1256 }
1257 }
1258
1259
1260 /* ARGSUSED */
1261 static int
1262 termp_pa_pre(DECL_ARGS)
1263 {
1264
1265 p->flags |= ttypes[TTYPE_FILE];
1266 return(1);
1267 }
1268
1269
1270 /* ARGSUSED */
1271 static void
1272 termp_pa_post(DECL_ARGS)
1273 {
1274
1275 p->flags &= ~ttypes[TTYPE_FILE];
1276 }
1277
1278
1279 /* ARGSUSED */
1280 static int
1281 termp_em_pre(DECL_ARGS)
1282 {
1283
1284 p->flags |= ttypes[TTYPE_EMPH];
1285 return(1);
1286 }
1287
1288
1289 /* ARGSUSED */
1290 static void
1291 termp_em_post(DECL_ARGS)
1292 {
1293
1294 p->flags &= ~ttypes[TTYPE_EMPH];
1295 }
1296
1297
1298 /* ARGSUSED */
1299 static int
1300 termp_cd_pre(DECL_ARGS)
1301 {
1302
1303 p->flags |= ttypes[TTYPE_CONFIG];
1304 return(1);
1305 }
1306
1307
1308 /* ARGSUSED */
1309 static void
1310 termp_cd_post(DECL_ARGS)
1311 {
1312
1313 p->flags &= ~ttypes[TTYPE_CONFIG];
1314 }
1315
1316
1317 /* ARGSUSED */
1318 static int
1319 termp_cm_pre(DECL_ARGS)
1320 {
1321
1322 p->flags |= ttypes[TTYPE_CMD_FLAG];
1323 return(1);
1324 }
1325
1326
1327 /* ARGSUSED */
1328 static void
1329 termp_cm_post(DECL_ARGS)
1330 {
1331
1332 p->flags &= ~ttypes[TTYPE_CMD_FLAG];
1333 }
1334
1335
1336 /* ARGSUSED */
1337 static int
1338 termp_ic_pre(DECL_ARGS)
1339 {
1340
1341 p->flags |= ttypes[TTYPE_CMD];
1342 return(1);
1343 }
1344
1345
1346 /* ARGSUSED */
1347 static void
1348 termp_ic_post(DECL_ARGS)
1349 {
1350
1351 p->flags &= ~ttypes[TTYPE_CMD];
1352 }
1353
1354
1355 /* ARGSUSED */
1356 static int
1357 termp_in_pre(DECL_ARGS)
1358 {
1359
1360 p->flags |= ttypes[TTYPE_INCLUDE];
1361 return(1);
1362 }
1363
1364
1365 /* ARGSUSED */
1366 static void
1367 termp_in_post(DECL_ARGS)
1368 {
1369
1370 p->flags &= ~ttypes[TTYPE_INCLUDE];
1371 }
1372
1373
1374 /* ARGSUSED */
1375 static int
1376 termp_at_pre(DECL_ARGS)
1377 {
1378 enum mdoc_att c;
1379
1380 c = ATT_DEFAULT;
1381 if (node->child) {
1382 assert(MDOC_TEXT == node->child->type);
1383 c = mdoc_atoatt(node->child->data.text.string);
1384 }
1385
1386 word(p, mdoc_att2a(c));
1387 return(0);
1388 }
1389
1390
1391 /* ARGSUSED */
1392 static int
1393 termp_bq_pre(DECL_ARGS)
1394 {
1395
1396 if (MDOC_BODY != node->type)
1397 return(1);
1398 word(p, "[");
1399 p->flags |= TERMP_NOSPACE;
1400 return(1);
1401 }
1402
1403
1404 /* ARGSUSED */
1405 static void
1406 termp_bq_post(DECL_ARGS)
1407 {
1408
1409 if (MDOC_BODY != node->type)
1410 return;
1411 word(p, "]");
1412 }
1413
1414
1415 /* ARGSUSED */
1416 static int
1417 termp_pq_pre(DECL_ARGS)
1418 {
1419
1420 if (MDOC_BODY != node->type)
1421 return(1);
1422 word(p, "(");
1423 p->flags |= TERMP_NOSPACE;
1424 return(1);
1425 }
1426
1427
1428 /* ARGSUSED */
1429 static void
1430 termp_pq_post(DECL_ARGS)
1431 {
1432
1433 if (MDOC_BODY != node->type)
1434 return;
1435 word(p, ")");
1436 }
1437
1438
1439 /* ARGSUSED */
1440 static int
1441 termp_fo_pre(DECL_ARGS)
1442 {
1443 const struct mdoc_node *n;
1444
1445 if (MDOC_BODY == node->type) {
1446 word(p, "(");
1447 p->flags |= TERMP_NOSPACE;
1448 return(1);
1449 } else if (MDOC_HEAD != node->type)
1450 return(1);
1451
1452 /* XXX - groff shows only first parameter */
1453
1454 p->flags |= ttypes[TTYPE_FUNC_NAME];
1455 for (n = node->child; n; n = n->next) {
1456 assert(MDOC_TEXT == n->type);
1457 word(p, n->data.text.string);
1458 }
1459 p->flags &= ~ttypes[TTYPE_FUNC_NAME];
1460
1461 return(0);
1462 }
1463
1464
1465 /* ARGSUSED */
1466 static void
1467 termp_fo_post(DECL_ARGS)
1468 {
1469
1470 if (MDOC_BODY != node->type)
1471 return;
1472 word(p, ")");
1473 word(p, ";");
1474 newln(p);
1475 }
1476
1477
1478 /* ARGSUSED */
1479 static int
1480 termp_bf_pre(DECL_ARGS)
1481 {
1482 const struct mdoc_node *n;
1483 const struct mdoc_block *b;
1484
1485 /* XXX - we skip over possible trailing HEAD tokens. */
1486
1487 if (MDOC_HEAD == node->type)
1488 return(0);
1489 else if (MDOC_BLOCK != node->type)
1490 return(1);
1491
1492 b = &node->data.block;
1493
1494 if (NULL == (n = b->head->child)) {
1495 if (arg_hasattr(MDOC_Emphasis, b->argc, b->argv))
1496 p->flags |= ttypes[TTYPE_EMPH];
1497 else if (arg_hasattr(MDOC_Symbolic, b->argc, b->argv))
1498 p->flags |= ttypes[TTYPE_SYMB];
1499
1500 return(1);
1501 }
1502
1503 assert(MDOC_TEXT == n->type);
1504
1505 if (0 == strcmp("Em", n->data.text.string))
1506 p->flags |= ttypes[TTYPE_EMPH];
1507 else if (0 == strcmp("Sy", n->data.text.string))
1508 p->flags |= ttypes[TTYPE_SYMB];
1509
1510 return(1);
1511 }
1512
1513
1514 /* ARGSUSED */
1515 static void
1516 termp_bf_post(DECL_ARGS)
1517 {
1518 const struct mdoc_node *n;
1519 const struct mdoc_block *b;
1520
1521 if (MDOC_BLOCK != node->type)
1522 return;
1523
1524 b = &node->data.block;
1525
1526 if (NULL == (n = b->head->child)) {
1527 if (arg_hasattr(MDOC_Emphasis, b->argc, b->argv))
1528 p->flags &= ~ttypes[TTYPE_EMPH];
1529 else if (arg_hasattr(MDOC_Symbolic, b->argc, b->argv))
1530 p->flags &= ~ttypes[TTYPE_SYMB];
1531
1532 return;
1533 }
1534
1535 assert(MDOC_TEXT == n->type);
1536
1537 if (0 == strcmp("Emphasis", n->data.text.string))
1538 p->flags &= ~ttypes[TTYPE_EMPH];
1539 else if (0 == strcmp("Symbolic", n->data.text.string))
1540 p->flags &= ~ttypes[TTYPE_SYMB];
1541
1542 return;
1543 }
1544
1545
1546 /* ARGSUSED */
1547 static int
1548 termp_sy_pre(DECL_ARGS)
1549 {
1550
1551 p->flags |= ttypes[TTYPE_SYMB];
1552 return(1);
1553 }
1554
1555
1556 /* ARGSUSED */
1557 static void
1558 termp_sy_post(DECL_ARGS)
1559 {
1560
1561 p->flags &= ~ttypes[TTYPE_SYMB];
1562 }
1563
1564
1565 /* ARGSUSED */
1566 static int
1567 termp_ms_pre(DECL_ARGS)
1568 {
1569
1570 p->flags |= ttypes[TTYPE_SYMBOL];
1571 return(1);
1572 }
1573
1574
1575 /* ARGSUSED */
1576 static void
1577 termp_ms_post(DECL_ARGS)
1578 {
1579
1580 p->flags &= ~ttypes[TTYPE_SYMBOL];
1581 }