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