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