mandoc(1): Update to 1.9.13.
[dragonfly.git] / usr.bin / mandoc / man_term.c
CommitLineData
32c903ac 1/* $Id: man_term.c,v 1.47 2009/10/30 18:53:08 kristaps Exp $ */
589e7c1d
SW
2/*
3 * Copyright (c) 2008, 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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17#include <sys/types.h>
18
19#include <assert.h>
20#include <ctype.h>
589e7c1d
SW
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "out.h"
26#include "man.h"
27#include "term.h"
28#include "chars.h"
29#include "main.h"
30
31#define INDENT 7
32#define HALFINDENT 3
33
cbce6d97
SW
34/* FIXME: have PD set the default vspace width. */
35
589e7c1d
SW
36struct mtermp {
37 int fl;
38#define MANT_LITERAL (1 << 0)
39 /*
40 * Default amount to indent the left margin after leading text
41 * has been printed (e.g., `HP' left-indent, `TP' and `IP' body
42 * indent). This needs to be saved because `HP' and so on, if
43 * not having a specified value, must default.
44 *
45 * Note that this is the indentation AFTER the left offset, so
46 * the total offset is usually offset + lmargin.
47 */
48 size_t lmargin;
49 /*
50 * The default offset, i.e., the amount between any text and the
51 * page boundary.
52 */
53 size_t offset;
54};
55
56#define DECL_ARGS struct termp *p, \
57 struct mtermp *mt, \
58 const struct man_node *n, \
59 const struct man_meta *m
60
61struct termact {
62 int (*pre)(DECL_ARGS);
63 void (*post)(DECL_ARGS);
64};
65
32c903ac
SW
66#ifdef __linux__
67extern size_t strlcpy(char *, const char *, size_t);
68extern size_t strlcat(char *, const char *, size_t);
69#endif
70
cbce6d97
SW
71static int a2width(const struct man_node *);
72static int a2height(const struct man_node *);
589e7c1d 73
cbce6d97 74static void print_man_head(struct termp *,
589e7c1d 75 const struct man_meta *);
cbce6d97
SW
76static void print_man_body(DECL_ARGS);
77static void print_man_node(DECL_ARGS);
78static void print_man_foot(struct termp *,
589e7c1d
SW
79 const struct man_meta *);
80static void print_bvspace(struct termp *,
81 const struct man_node *);
82
83static int pre_B(DECL_ARGS);
84static int pre_BI(DECL_ARGS);
85static int pre_HP(DECL_ARGS);
86static int pre_I(DECL_ARGS);
87static int pre_IP(DECL_ARGS);
88static int pre_IR(DECL_ARGS);
89static int pre_PP(DECL_ARGS);
90static int pre_RB(DECL_ARGS);
91static int pre_RI(DECL_ARGS);
92static int pre_RS(DECL_ARGS);
93static int pre_SH(DECL_ARGS);
94static int pre_SS(DECL_ARGS);
95static int pre_TP(DECL_ARGS);
96static int pre_br(DECL_ARGS);
97static int pre_fi(DECL_ARGS);
98static int pre_ign(DECL_ARGS);
99static int pre_nf(DECL_ARGS);
100static int pre_r(DECL_ARGS);
101static int pre_sp(DECL_ARGS);
102
103static void post_B(DECL_ARGS);
104static void post_I(DECL_ARGS);
105static void post_IP(DECL_ARGS);
106static void post_HP(DECL_ARGS);
107static void post_RS(DECL_ARGS);
108static void post_SH(DECL_ARGS);
109static void post_SS(DECL_ARGS);
110static void post_TP(DECL_ARGS);
111static void post_i(DECL_ARGS);
112
113static const struct termact termacts[MAN_MAX] = {
114 { pre_br, NULL }, /* br */
115 { NULL, NULL }, /* TH */
116 { pre_SH, post_SH }, /* SH */
117 { pre_SS, post_SS }, /* SS */
118 { pre_TP, post_TP }, /* TP */
119 { pre_PP, NULL }, /* LP */
120 { pre_PP, NULL }, /* PP */
121 { pre_PP, NULL }, /* P */
122 { pre_IP, post_IP }, /* IP */
123 { pre_HP, post_HP }, /* HP */
124 { NULL, NULL }, /* SM */
125 { pre_B, post_B }, /* SB */
126 { pre_BI, NULL }, /* BI */
127 { pre_BI, NULL }, /* IB */
128 { pre_RB, NULL }, /* BR */
129 { pre_RB, NULL }, /* RB */
130 { NULL, NULL }, /* R */
131 { pre_B, post_B }, /* B */
132 { pre_I, post_I }, /* I */
133 { pre_IR, NULL }, /* IR */
134 { pre_RI, NULL }, /* RI */
135 { NULL, NULL }, /* na */
136 { pre_I, post_i }, /* i */
137 { pre_sp, NULL }, /* sp */
138 { pre_nf, NULL }, /* nf */
139 { pre_fi, NULL }, /* fi */
140 { pre_r, NULL }, /* r */
141 { NULL, NULL }, /* RE */
142 { pre_RS, post_RS }, /* RS */
143 { pre_ign, NULL }, /* DT */
144 { pre_ign, NULL }, /* UC */
cbce6d97 145 { pre_ign, NULL }, /* PD */
589e7c1d
SW
146};
147
148
149
150void
151terminal_man(void *arg, const struct man *man)
152{
153 struct termp *p;
154 const struct man_node *n;
155 const struct man_meta *m;
156 struct mtermp mt;
157
158 p = (struct termp *)arg;
159
160 if (NULL == p->symtab)
161 switch (p->enc) {
162 case (TERMENC_ASCII):
163 p->symtab = chars_init(CHARS_ASCII);
164 break;
165 default:
166 abort();
167 /* NOTREACHED */
168 }
169
170 n = man_node(man);
171 m = man_meta(man);
172
cbce6d97 173 print_man_head(p, m);
589e7c1d
SW
174 p->flags |= TERMP_NOSPACE;
175
176 mt.fl = 0;
177 mt.lmargin = INDENT;
178 mt.offset = INDENT;
179
180 if (n->child)
cbce6d97
SW
181 print_man_body(p, &mt, n->child, m);
182 print_man_foot(p, m);
589e7c1d
SW
183}
184
185
186static int
cbce6d97 187a2height(const struct man_node *n)
589e7c1d
SW
188{
189 struct roffsu su;
190
191 assert(MAN_TEXT == n->type);
192 assert(n->string);
193 if ( ! a2roffsu(n->string, &su, SCALE_VS))
194 SCALE_VS_INIT(&su, strlen(n->string));
195
196 return((int)term_vspan(&su));
197}
198
199
200static int
cbce6d97 201a2width(const struct man_node *n)
589e7c1d
SW
202{
203 struct roffsu su;
204
205 assert(MAN_TEXT == n->type);
206 assert(n->string);
207 if ( ! a2roffsu(n->string, &su, SCALE_BU))
208 return(-1);
209
210 return((int)term_hspan(&su));
211}
212
213
214static void
215print_bvspace(struct termp *p, const struct man_node *n)
216{
217 term_newln(p);
218
219 if (NULL == n->prev)
220 return;
221
222 if (MAN_SS == n->prev->tok)
223 return;
224 if (MAN_SH == n->prev->tok)
225 return;
226
227 term_vspace(p);
228}
229
230
231/* ARGSUSED */
232static int
233pre_ign(DECL_ARGS)
234{
235
236 return(0);
237}
238
239
240/* ARGSUSED */
241static int
242pre_I(DECL_ARGS)
243{
244
245 p->under++;
246 return(1);
247}
248
249
250/* ARGSUSED */
251static int
252pre_r(DECL_ARGS)
253{
254
255 p->bold = p->under = 0;
256 return(1);
257}
258
259
260/* ARGSUSED */
261static void
262post_i(DECL_ARGS)
263{
264
265 if (n->nchild)
266 p->under--;
267}
268
269
270/* ARGSUSED */
271static void
272post_I(DECL_ARGS)
273{
274
275 p->under--;
276}
277
278
279/* ARGSUSED */
280static int
281pre_fi(DECL_ARGS)
282{
283
284 mt->fl &= ~MANT_LITERAL;
285 return(1);
286}
287
288
289/* ARGSUSED */
290static int
291pre_nf(DECL_ARGS)
292{
293
294 term_newln(p);
295 mt->fl |= MANT_LITERAL;
296 return(1);
297}
298
299
300/* ARGSUSED */
301static int
302pre_IR(DECL_ARGS)
303{
304 const struct man_node *nn;
305 int i;
306
307 for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
308 if ( ! (i % 2))
309 p->under++;
310 if (i > 0)
311 p->flags |= TERMP_NOSPACE;
cbce6d97 312 print_man_node(p, mt, nn, m);
589e7c1d
SW
313 if ( ! (i % 2))
314 p->under--;
315 }
316 return(0);
317}
318
319
320/* ARGSUSED */
321static int
322pre_RB(DECL_ARGS)
323{
324 const struct man_node *nn;
325 int i;
326
327 for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
328 if (i % 2 && MAN_RB == n->tok)
329 p->bold++;
330 else if ( ! (i % 2) && MAN_RB != n->tok)
331 p->bold++;
332
333 if (i > 0)
334 p->flags |= TERMP_NOSPACE;
335
cbce6d97 336 print_man_node(p, mt, nn, m);
589e7c1d
SW
337
338 if (i % 2 && MAN_RB == n->tok)
339 p->bold--;
340 else if ( ! (i % 2) && MAN_RB != n->tok)
341 p->bold--;
342 }
343 return(0);
344}
345
346
347/* ARGSUSED */
348static int
349pre_RI(DECL_ARGS)
350{
351 const struct man_node *nn;
352 int i;
353
354 for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
355 if ( ! (i % 2))
356 p->under++;
357 if (i > 0)
358 p->flags |= TERMP_NOSPACE;
cbce6d97 359 print_man_node(p, mt, nn, m);
589e7c1d
SW
360 if ( ! (i % 2))
361 p->under--;
362 }
363 return(0);
364}
365
366
367/* ARGSUSED */
368static int
369pre_BI(DECL_ARGS)
370{
371 const struct man_node *nn;
372 int i;
373
374 for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
375 if (i % 2 && MAN_BI == n->tok)
376 p->under++;
377 else if (i % 2)
378 p->bold++;
379 else if (MAN_BI == n->tok)
380 p->bold++;
381 else
382 p->under++;
383
384 if (i)
385 p->flags |= TERMP_NOSPACE;
cbce6d97 386 print_man_node(p, mt, nn, m);
589e7c1d
SW
387
388 if (i % 2 && MAN_BI == n->tok)
389 p->under--;
390 else if (i % 2)
391 p->bold--;
392 else if (MAN_BI == n->tok)
393 p->bold--;
394 else
395 p->under--;
396 }
397 return(0);
398}
399
400
401/* ARGSUSED */
402static int
403pre_B(DECL_ARGS)
404{
405
406 p->bold++;
407 return(1);
408}
409
410
411/* ARGSUSED */
412static void
413post_B(DECL_ARGS)
414{
415
416 p->bold--;
417}
418
419
420/* ARGSUSED */
421static int
422pre_sp(DECL_ARGS)
423{
424 int i, len;
425
cbce6d97 426 len = n->child ? a2height(n->child) : 1;
589e7c1d
SW
427
428 if (0 == len)
429 term_newln(p);
430 for (i = 0; i < len; i++)
431 term_vspace(p);
432
433 return(0);
434}
435
436
437/* ARGSUSED */
438static int
439pre_br(DECL_ARGS)
440{
441
442 term_newln(p);
443 return(0);
444}
445
446
447/* ARGSUSED */
448static int
449pre_HP(DECL_ARGS)
450{
451 size_t len;
452 int ival;
453 const struct man_node *nn;
454
455 switch (n->type) {
456 case (MAN_BLOCK):
457 print_bvspace(p, n);
458 return(1);
459 case (MAN_BODY):
460 p->flags |= TERMP_NOBREAK;
461 p->flags |= TERMP_TWOSPACE;
462 break;
463 default:
464 return(0);
465 }
466
467 len = mt->lmargin;
468 ival = -1;
469
470 /* Calculate offset. */
471
472 if (NULL != (nn = n->parent->head->child))
cbce6d97 473 if ((ival = a2width(nn)) >= 0)
589e7c1d
SW
474 len = (size_t)ival;
475
476 if (0 == len)
477 len = 1;
478
479 p->offset = mt->offset;
480 p->rmargin = mt->offset + len;
481
482 if (ival >= 0)
483 mt->lmargin = (size_t)ival;
484
485 return(1);
486}
487
488
489/* ARGSUSED */
490static void
491post_HP(DECL_ARGS)
492{
493
494 switch (n->type) {
495 case (MAN_BLOCK):
496 term_flushln(p);
497 break;
498 case (MAN_BODY):
499 term_flushln(p);
500 p->flags &= ~TERMP_NOBREAK;
501 p->flags &= ~TERMP_TWOSPACE;
502 p->offset = mt->offset;
503 p->rmargin = p->maxrmargin;
504 break;
505 default:
506 break;
507 }
508}
509
510
511/* ARGSUSED */
512static int
513pre_PP(DECL_ARGS)
514{
515
516 switch (n->type) {
517 case (MAN_BLOCK):
518 mt->lmargin = INDENT;
519 print_bvspace(p, n);
520 break;
521 default:
522 p->offset = mt->offset;
523 break;
524 }
525
526 return(1);
527}
528
529
530/* ARGSUSED */
531static int
532pre_IP(DECL_ARGS)
533{
534 const struct man_node *nn;
535 size_t len;
536 int ival;
537
538 switch (n->type) {
539 case (MAN_BODY):
540 p->flags |= TERMP_NOLPAD;
541 p->flags |= TERMP_NOSPACE;
542 break;
543 case (MAN_HEAD):
544 p->flags |= TERMP_NOBREAK;
545 p->flags |= TERMP_TWOSPACE;
546 break;
547 case (MAN_BLOCK):
548 print_bvspace(p, n);
549 /* FALLTHROUGH */
550 default:
551 return(1);
552 }
553
554 len = mt->lmargin;
555 ival = -1;
556
557 /* Calculate offset. */
558
559 if (NULL != (nn = n->parent->head->child))
560 if (NULL != (nn = nn->next)) {
561 for ( ; nn->next; nn = nn->next)
562 /* Do nothing. */ ;
cbce6d97 563 if ((ival = a2width(nn)) >= 0)
589e7c1d
SW
564 len = (size_t)ival;
565 }
566
567 switch (n->type) {
568 case (MAN_HEAD):
569 /* Handle zero-width lengths. */
570 if (0 == len)
571 len = 1;
572
573 p->offset = mt->offset;
574 p->rmargin = mt->offset + len;
575 if (ival < 0)
576 break;
577
578 /* Set the saved left-margin. */
579 mt->lmargin = (size_t)ival;
580
581 /* Don't print the length value. */
582 for (nn = n->child; nn->next; nn = nn->next)
cbce6d97 583 print_man_node(p, mt, nn, m);
589e7c1d
SW
584 return(0);
585 case (MAN_BODY):
586 p->offset = mt->offset + len;
587 p->rmargin = p->maxrmargin;
588 break;
589 default:
590 break;
591 }
592
593 return(1);
594}
595
596
597/* ARGSUSED */
598static void
599post_IP(DECL_ARGS)
600{
601
602 switch (n->type) {
603 case (MAN_HEAD):
604 term_flushln(p);
605 p->flags &= ~TERMP_NOBREAK;
606 p->flags &= ~TERMP_TWOSPACE;
607 p->rmargin = p->maxrmargin;
608 break;
609 case (MAN_BODY):
610 term_flushln(p);
611 p->flags &= ~TERMP_NOLPAD;
612 break;
613 default:
614 break;
615 }
616}
617
618
619/* ARGSUSED */
620static int
621pre_TP(DECL_ARGS)
622{
623 const struct man_node *nn;
624 size_t len;
625 int ival;
626
627 switch (n->type) {
628 case (MAN_HEAD):
629 p->flags |= TERMP_NOBREAK;
630 p->flags |= TERMP_TWOSPACE;
631 break;
632 case (MAN_BODY):
633 p->flags |= TERMP_NOLPAD;
634 p->flags |= TERMP_NOSPACE;
635 break;
636 case (MAN_BLOCK):
637 print_bvspace(p, n);
638 /* FALLTHROUGH */
639 default:
640 return(1);
641 }
642
643 len = (size_t)mt->lmargin;
644 ival = -1;
645
646 /* Calculate offset. */
647
648 if (NULL != (nn = n->parent->head->child))
649 if (NULL != nn->next)
cbce6d97 650 if ((ival = a2width(nn)) >= 0)
589e7c1d
SW
651 len = (size_t)ival;
652
653 switch (n->type) {
654 case (MAN_HEAD):
655 /* Handle zero-length properly. */
656 if (0 == len)
657 len = 1;
658
659 p->offset = mt->offset;
660 p->rmargin = mt->offset + len;
661
662 /* Don't print same-line elements. */
663 for (nn = n->child; nn; nn = nn->next)
664 if (nn->line > n->line)
cbce6d97 665 print_man_node(p, mt, nn, m);
589e7c1d
SW
666
667 if (ival >= 0)
668 mt->lmargin = (size_t)ival;
669
670 return(0);
671 case (MAN_BODY):
672 p->offset = mt->offset + len;
673 p->rmargin = p->maxrmargin;
674 break;
675 default:
676 break;
677 }
678
679 return(1);
680}
681
682
683/* ARGSUSED */
684static void
685post_TP(DECL_ARGS)
686{
687
688 switch (n->type) {
689 case (MAN_HEAD):
690 term_flushln(p);
691 p->flags &= ~TERMP_NOBREAK;
692 p->flags &= ~TERMP_TWOSPACE;
693 p->rmargin = p->maxrmargin;
694 break;
695 case (MAN_BODY):
696 term_flushln(p);
697 p->flags &= ~TERMP_NOLPAD;
698 break;
699 default:
700 break;
701 }
702}
703
704
705/* ARGSUSED */
706static int
707pre_SS(DECL_ARGS)
708{
709
710 switch (n->type) {
711 case (MAN_BLOCK):
712 mt->lmargin = INDENT;
713 mt->offset = INDENT;
714 /* If following a prior empty `SS', no vspace. */
715 if (n->prev && MAN_SS == n->prev->tok)
716 if (NULL == n->prev->body->child)
717 break;
718 if (NULL == n->prev)
719 break;
720 term_vspace(p);
721 break;
722 case (MAN_HEAD):
723 p->bold++;
724 p->offset = HALFINDENT;
725 break;
726 case (MAN_BODY):
727 p->offset = mt->offset;
728 break;
729 default:
730 break;
731 }
732
733 return(1);
734}
735
736
737/* ARGSUSED */
738static void
739post_SS(DECL_ARGS)
740{
741
742 switch (n->type) {
743 case (MAN_HEAD):
744 term_newln(p);
745 p->bold--;
746 break;
747 case (MAN_BODY):
748 term_newln(p);
749 break;
750 default:
751 break;
752 }
753}
754
755
756/* ARGSUSED */
757static int
758pre_SH(DECL_ARGS)
759{
760
761 switch (n->type) {
762 case (MAN_BLOCK):
763 mt->lmargin = INDENT;
764 mt->offset = INDENT;
765 /* If following a prior empty `SH', no vspace. */
766 if (n->prev && MAN_SH == n->prev->tok)
767 if (NULL == n->prev->body->child)
768 break;
769 term_vspace(p);
770 break;
771 case (MAN_HEAD):
772 p->bold++;
773 p->offset = 0;
774 break;
775 case (MAN_BODY):
776 p->offset = mt->offset;
777 break;
778 default:
779 break;
780 }
781
782 return(1);
783}
784
785
786/* ARGSUSED */
787static void
788post_SH(DECL_ARGS)
789{
790
791 switch (n->type) {
792 case (MAN_HEAD):
793 term_newln(p);
794 p->bold--;
795 break;
796 case (MAN_BODY):
797 term_newln(p);
798 break;
799 default:
800 break;
801 }
802}
803
804
805/* ARGSUSED */
806static int
807pre_RS(DECL_ARGS)
808{
809 const struct man_node *nn;
810 int ival;
811
812 switch (n->type) {
813 case (MAN_BLOCK):
814 term_newln(p);
815 return(1);
816 case (MAN_HEAD):
817 return(0);
818 default:
819 break;
820 }
821
822 if (NULL == (nn = n->parent->head->child)) {
823 mt->offset = mt->lmargin + INDENT;
824 p->offset = mt->offset;
825 return(1);
826 }
827
cbce6d97 828 if ((ival = a2width(nn)) < 0)
589e7c1d
SW
829 return(1);
830
831 mt->offset = INDENT + (size_t)ival;
832 p->offset = mt->offset;
833
834 return(1);
835}
836
837
838/* ARGSUSED */
839static void
840post_RS(DECL_ARGS)
841{
842
843 switch (n->type) {
844 case (MAN_BLOCK):
845 mt->offset = mt->lmargin = INDENT;
846 break;
847 default:
848 term_newln(p);
849 p->offset = INDENT;
850 break;
851 }
852}
853
854
855static void
cbce6d97 856print_man_node(DECL_ARGS)
589e7c1d
SW
857{
858 int c, sz;
859
860 c = 1;
861
862 switch (n->type) {
863 case(MAN_TEXT):
864 if (0 == *n->string) {
865 term_vspace(p);
866 break;
867 }
868 /*
869 * Note! This is hacky. Here, we recognise the `\c'
870 * escape embedded in so many -man pages. It's supposed
871 * to remove the subsequent space, so we mark NOSPACE if
872 * it's encountered in the string.
873 */
874 sz = (int)strlen(n->string);
875 term_word(p, n->string);
876 if (sz >= 2 && n->string[sz - 1] == 'c' &&
877 n->string[sz - 2] == '\\')
878 p->flags |= TERMP_NOSPACE;
879 /* FIXME: this means that macro lines are munged! */
880 if (MANT_LITERAL & mt->fl) {
881 p->flags |= TERMP_NOSPACE;
882 term_flushln(p);
883 }
884 break;
885 default:
886 if (termacts[n->tok].pre)
887 c = (*termacts[n->tok].pre)(p, mt, n, m);
888 break;
889 }
890
891 if (c && n->child)
cbce6d97 892 print_man_body(p, mt, n->child, m);
589e7c1d
SW
893
894 if (MAN_TEXT != n->type)
895 if (termacts[n->tok].post)
896 (*termacts[n->tok].post)(p, mt, n, m);
897}
898
899
900static void
cbce6d97 901print_man_body(DECL_ARGS)
589e7c1d
SW
902{
903
cbce6d97 904 print_man_node(p, mt, n, m);
589e7c1d
SW
905 if ( ! n->next)
906 return;
cbce6d97 907 print_man_body(p, mt, n->next, m);
589e7c1d
SW
908}
909
910
911static void
cbce6d97 912print_man_foot(struct termp *p, const struct man_meta *meta)
589e7c1d 913{
cbce6d97 914 char buf[DATESIZ];
589e7c1d 915
cbce6d97 916 time2a(meta->date, buf, DATESIZ);
589e7c1d
SW
917
918 term_vspace(p);
919
920 p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
921 p->rmargin = p->maxrmargin - strlen(buf);
922 p->offset = 0;
923
924 if (meta->source)
925 term_word(p, meta->source);
926 if (meta->source)
927 term_word(p, "");
928 term_flushln(p);
929
930 p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
931 p->offset = p->rmargin;
932 p->rmargin = p->maxrmargin;
933 p->flags &= ~TERMP_NOBREAK;
934
935 term_word(p, buf);
936 term_flushln(p);
937}
938
939
940static void
32c903ac 941print_man_head(struct termp *p, const struct man_meta *m)
589e7c1d 942{
32c903ac 943 char buf[BUFSIZ], title[BUFSIZ];
589e7c1d
SW
944
945 p->rmargin = p->maxrmargin;
946 p->offset = 0;
32c903ac 947 buf[0] = title[0] = '\0';
589e7c1d 948
32c903ac
SW
949 if (m->vol)
950 strlcpy(buf, m->vol, BUFSIZ);
589e7c1d 951
32c903ac 952 snprintf(title, BUFSIZ, "%s(%d)", m->title, m->msec);
589e7c1d
SW
953
954 p->offset = 0;
955 p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
956 p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
957
958 term_word(p, title);
959 term_flushln(p);
960
961 p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
962 p->offset = p->rmargin;
963 p->rmargin = p->maxrmargin - strlen(title);
964
965 term_word(p, buf);
966 term_flushln(p);
967
968 p->offset = p->rmargin;
969 p->rmargin = p->maxrmargin;
970 p->flags &= ~TERMP_NOBREAK;
971 p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
972
973 term_word(p, title);
974 term_flushln(p);
975
976 p->rmargin = p->maxrmargin;
977 p->offset = 0;
978 p->flags &= ~TERMP_NOSPACE;
589e7c1d 979}