Annotation of mandoc/man_term.c, Revision 1.21
1.21 ! kristaps 1: /* $Id: man_term.c,v 1.20 2009/08/13 12:15:58 kristaps Exp $ */
1.1 kristaps 2: /*
1.9 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.8 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.8 kristaps 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.
1.1 kristaps 16: */
17: #include <assert.h>
1.18 kristaps 18: #include <ctype.h>
1.1 kristaps 19: #include <err.h>
20: #include <stdio.h>
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include "term.h"
25: #include "man.h"
26:
1.18 kristaps 27: #define INDENT 7
28: #define HALFINDENT 3
29:
1.2 kristaps 30: #ifdef __linux__
31: extern size_t strlcpy(char *, const char *, size_t);
32: extern size_t strlcat(char *, const char *, size_t);
33: #endif
34:
1.19 kristaps 35: #define MANT_LITERAL (1 << 0)
36:
1.1 kristaps 37: #define DECL_ARGS struct termp *p, \
1.19 kristaps 38: int *fl, \
1.1 kristaps 39: const struct man_node *n, \
40: const struct man_meta *m
41:
42: struct termact {
43: int (*pre)(DECL_ARGS);
44: void (*post)(DECL_ARGS);
45: };
46:
47: static int pre_B(DECL_ARGS);
1.3 kristaps 48: static int pre_BI(DECL_ARGS);
49: static int pre_BR(DECL_ARGS);
1.19 kristaps 50: static int pre_HP(DECL_ARGS);
1.1 kristaps 51: static int pre_I(DECL_ARGS);
1.3 kristaps 52: static int pre_IB(DECL_ARGS);
1.4 kristaps 53: static int pre_IP(DECL_ARGS);
1.3 kristaps 54: static int pre_IR(DECL_ARGS);
1.1 kristaps 55: static int pre_PP(DECL_ARGS);
1.3 kristaps 56: static int pre_RB(DECL_ARGS);
57: static int pre_RI(DECL_ARGS);
1.1 kristaps 58: static int pre_SH(DECL_ARGS);
59: static int pre_SS(DECL_ARGS);
60: static int pre_TP(DECL_ARGS);
1.19 kristaps 61: static int pre_br(DECL_ARGS);
62: static int pre_fi(DECL_ARGS);
63: static int pre_nf(DECL_ARGS);
64: static int pre_r(DECL_ARGS);
65: static int pre_sp(DECL_ARGS);
1.1 kristaps 66:
67: static void post_B(DECL_ARGS);
68: static void post_I(DECL_ARGS);
1.20 kristaps 69: static void post_HP(DECL_ARGS);
1.1 kristaps 70: static void post_SH(DECL_ARGS);
71: static void post_SS(DECL_ARGS);
1.21 ! kristaps 72: static void post_TP(DECL_ARGS);
1.19 kristaps 73: static void post_i(DECL_ARGS);
1.1 kristaps 74:
75: static const struct termact termacts[MAN_MAX] = {
1.15 kristaps 76: { pre_br, NULL }, /* br */
1.1 kristaps 77: { NULL, NULL }, /* TH */
78: { pre_SH, post_SH }, /* SH */
79: { pre_SS, post_SS }, /* SS */
1.21 ! kristaps 80: { pre_TP, post_TP }, /* TP */
1.1 kristaps 81: { pre_PP, NULL }, /* LP */
82: { pre_PP, NULL }, /* PP */
83: { pre_PP, NULL }, /* P */
1.4 kristaps 84: { pre_IP, NULL }, /* IP */
1.20 kristaps 85: { pre_HP, post_HP }, /* HP */
1.1 kristaps 86: { NULL, NULL }, /* SM */
87: { pre_B, post_B }, /* SB */
1.3 kristaps 88: { pre_BI, NULL }, /* BI */
89: { pre_IB, NULL }, /* IB */
90: { pre_BR, NULL }, /* BR */
91: { pre_RB, NULL }, /* RB */
1.1 kristaps 92: { NULL, NULL }, /* R */
93: { pre_B, post_B }, /* B */
94: { pre_I, post_I }, /* I */
1.3 kristaps 95: { pre_IR, NULL }, /* IR */
96: { pre_RI, NULL }, /* RI */
1.19 kristaps 97: { NULL, NULL }, /* na */ /* TODO: document that has no effect */
98: { pre_I, post_i }, /* i */
99: { pre_sp, NULL }, /* sp */
100: { pre_nf, NULL }, /* nf */
101: { pre_fi, NULL }, /* fi */
102: { pre_r, NULL }, /* r */
1.1 kristaps 103: };
104:
105: static void print_head(struct termp *,
106: const struct man_meta *);
107: static void print_body(DECL_ARGS);
108: static void print_node(DECL_ARGS);
109: static void print_foot(struct termp *,
110: const struct man_meta *);
1.18 kristaps 111: static void fmt_block_vspace(struct termp *,
112: const struct man_node *);
113: static int arg_width(const struct man_node *);
1.1 kristaps 114:
115:
116: int
117: man_run(struct termp *p, const struct man *m)
118: {
1.19 kristaps 119: int fl;
1.1 kristaps 120:
121: print_head(p, man_meta(m));
122: p->flags |= TERMP_NOSPACE;
1.14 kristaps 123: assert(man_node(m));
124: assert(MAN_ROOT == man_node(m)->type);
1.19 kristaps 125:
126: fl = 0;
1.14 kristaps 127: if (man_node(m)->child)
1.19 kristaps 128: print_body(p, &fl, man_node(m)->child, man_meta(m));
1.1 kristaps 129: print_foot(p, man_meta(m));
130:
131: return(1);
132: }
133:
134:
1.18 kristaps 135: static void
136: fmt_block_vspace(struct termp *p, const struct man_node *n)
137: {
138: term_newln(p);
139:
140: if (NULL == n->prev)
141: return;
142:
143: if (MAN_SS == n->prev->tok)
144: return;
145: if (MAN_SH == n->prev->tok)
146: return;
147:
148: term_vspace(p);
149: }
150:
151:
152: static int
153: arg_width(const struct man_node *n)
154: {
155: int i, len;
156: const char *p;
157:
158: assert(MAN_TEXT == n->type);
159: assert(n->string);
160:
161: p = n->string;
162:
163: if (0 == (len = (int)strlen(p)))
164: return(-1);
165:
166: for (i = 0; i < len; i++)
167: if ( ! isdigit((u_char)p[i]))
168: break;
169:
170: if (i == len - 1) {
171: if ('n' == p[len - 1] || 'm' == p[len - 1])
172: return(atoi(p));
173: } else if (i == len)
174: return(atoi(p));
175:
176: return(-1);
177: }
178:
179:
1.3 kristaps 180: /* ARGSUSED */
1.1 kristaps 181: static int
182: pre_I(DECL_ARGS)
183: {
184:
185: p->flags |= TERMP_UNDER;
186: return(1);
187: }
188:
189:
1.3 kristaps 190: /* ARGSUSED */
1.19 kristaps 191: static int
192: pre_r(DECL_ARGS)
193: {
194:
195: p->flags &= ~TERMP_UNDER;
196: p->flags &= ~TERMP_BOLD;
197: return(1);
198: }
199:
200:
201: /* ARGSUSED */
202: static void
203: post_i(DECL_ARGS)
204: {
205:
206: if (n->nchild)
207: p->flags &= ~TERMP_UNDER;
208: }
209:
210:
211: /* ARGSUSED */
1.1 kristaps 212: static void
213: post_I(DECL_ARGS)
214: {
215:
216: p->flags &= ~TERMP_UNDER;
217: }
218:
219:
1.3 kristaps 220: /* ARGSUSED */
221: static int
1.19 kristaps 222: pre_fi(DECL_ARGS)
223: {
224:
225: *fl &= ~MANT_LITERAL;
226: return(1);
227: }
228:
229:
230: /* ARGSUSED */
231: static int
232: pre_nf(DECL_ARGS)
233: {
234:
235: term_newln(p);
236: *fl |= MANT_LITERAL;
237: return(1);
238: }
239:
240:
241: /* ARGSUSED */
242: static int
1.3 kristaps 243: pre_IR(DECL_ARGS)
244: {
245: const struct man_node *nn;
246: int i;
247:
248: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
249: if ( ! (i % 2))
250: p->flags |= TERMP_UNDER;
1.4 kristaps 251: if (i > 0)
252: p->flags |= TERMP_NOSPACE;
1.19 kristaps 253: print_node(p, fl, nn, m);
1.3 kristaps 254: if ( ! (i % 2))
255: p->flags &= ~TERMP_UNDER;
256: }
257: return(0);
258: }
259:
260:
261: /* ARGSUSED */
262: static int
263: pre_IB(DECL_ARGS)
264: {
265: const struct man_node *nn;
266: int i;
267:
268: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
269: p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
1.4 kristaps 270: if (i > 0)
271: p->flags |= TERMP_NOSPACE;
1.19 kristaps 272: print_node(p, fl, nn, m);
1.3 kristaps 273: p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
274: }
275: return(0);
276: }
277:
278:
279: /* ARGSUSED */
280: static int
281: pre_RB(DECL_ARGS)
282: {
283: const struct man_node *nn;
284: int i;
285:
286: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
287: if (i % 2)
288: p->flags |= TERMP_BOLD;
1.4 kristaps 289: if (i > 0)
290: p->flags |= TERMP_NOSPACE;
1.19 kristaps 291: print_node(p, fl, nn, m);
1.3 kristaps 292: if (i % 2)
293: p->flags &= ~TERMP_BOLD;
294: }
295: return(0);
296: }
297:
298:
299: /* ARGSUSED */
300: static int
301: pre_RI(DECL_ARGS)
302: {
303: const struct man_node *nn;
304: int i;
305:
306: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
307: if ( ! (i % 2))
308: p->flags |= TERMP_UNDER;
1.4 kristaps 309: if (i > 0)
310: p->flags |= TERMP_NOSPACE;
1.19 kristaps 311: print_node(p, fl, nn, m);
1.3 kristaps 312: if ( ! (i % 2))
313: p->flags &= ~TERMP_UNDER;
314: }
315: return(0);
316: }
317:
318:
319: /* ARGSUSED */
320: static int
321: pre_BR(DECL_ARGS)
322: {
323: const struct man_node *nn;
324: int i;
325:
326: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
327: if ( ! (i % 2))
328: p->flags |= TERMP_BOLD;
1.4 kristaps 329: if (i > 0)
330: p->flags |= TERMP_NOSPACE;
1.19 kristaps 331: print_node(p, fl, nn, m);
1.3 kristaps 332: if ( ! (i % 2))
333: p->flags &= ~TERMP_BOLD;
334: }
335: return(0);
336: }
337:
338:
339: /* ARGSUSED */
340: static int
341: pre_BI(DECL_ARGS)
342: {
343: const struct man_node *nn;
344: int i;
345:
346: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
347: p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
1.4 kristaps 348: if (i > 0)
349: p->flags |= TERMP_NOSPACE;
1.19 kristaps 350: print_node(p, fl, nn, m);
1.3 kristaps 351: p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
352: }
353: return(0);
354: }
355:
356:
357: /* ARGSUSED */
1.1 kristaps 358: static int
359: pre_B(DECL_ARGS)
360: {
361:
362: p->flags |= TERMP_BOLD;
363: return(1);
364: }
365:
366:
1.3 kristaps 367: /* ARGSUSED */
1.1 kristaps 368: static void
369: post_B(DECL_ARGS)
370: {
371:
372: p->flags &= ~TERMP_BOLD;
373: }
374:
375:
1.3 kristaps 376: /* ARGSUSED */
1.1 kristaps 377: static int
1.19 kristaps 378: pre_sp(DECL_ARGS)
379: {
380: int i, len;
381:
382: if (NULL == n->child) {
383: term_vspace(p);
384: return(0);
385: }
386:
387: len = atoi(n->child->string);
388: if (0 == len)
389: term_newln(p);
390: for (i = 0; i < len; i++)
391: term_vspace(p);
392:
393: return(0);
394: }
395:
396:
397: /* ARGSUSED */
398: static int
1.15 kristaps 399: pre_br(DECL_ARGS)
400: {
401:
402: term_newln(p);
403: return(0);
404: }
405:
406:
407: /* ARGSUSED */
408: static int
1.19 kristaps 409: pre_HP(DECL_ARGS)
410: {
411:
1.20 kristaps 412: switch (n->type) {
413: case (MAN_BLOCK):
414: fmt_block_vspace(p, n);
415: break;
416: case (MAN_BODY):
417: p->flags |= TERMP_NOBREAK;
418: p->flags |= TERMP_TWOSPACE;
419: p->offset = INDENT;
420: p->rmargin = INDENT * 2;
421: break;
422: default:
423: return(0);
424: }
425:
1.19 kristaps 426: return(1);
427: }
428:
429:
430: /* ARGSUSED */
1.20 kristaps 431: static void
432: post_HP(DECL_ARGS)
433: {
434:
435: switch (n->type) {
436: case (MAN_BODY):
437: term_flushln(p);
438: p->flags &= ~TERMP_NOBREAK;
439: p->flags &= ~TERMP_TWOSPACE;
440: p->offset = INDENT;
441: p->rmargin = p->maxrmargin;
442: break;
443: default:
444: break;
445: }
446: }
447:
448:
449: /* ARGSUSED */
1.19 kristaps 450: static int
1.1 kristaps 451: pre_PP(DECL_ARGS)
452: {
453:
1.19 kristaps 454: switch (n->type) {
455: case (MAN_BLOCK):
456: fmt_block_vspace(p, n);
457: break;
458: default:
459: p->offset = INDENT;
460: break;
461: }
462:
463: return(1);
1.1 kristaps 464: }
465:
466:
1.3 kristaps 467: /* ARGSUSED */
1.1 kristaps 468: static int
1.4 kristaps 469: pre_IP(DECL_ARGS)
470: {
1.19 kristaps 471: /* TODO */
472: #if 0
1.4 kristaps 473: const struct man_node *nn;
1.18 kristaps 474: size_t offs, sv;
475: int ival;
476:
477: fmt_block_vspace(p, n);
478:
479: p->flags |= TERMP_NOSPACE;
1.4 kristaps 480:
1.18 kristaps 481: sv = p->offset;
1.4 kristaps 482: p->offset = INDENT;
483:
1.18 kristaps 484: if (NULL == n->child)
1.4 kristaps 485: return(1);
486:
1.18 kristaps 487: p->flags |= TERMP_NOBREAK;
488:
489: offs = sv;
490:
491: /*
492: * If the last token is number-looking (3m, 3n, 3) then
493: * interpret it as the width specifier, else we stick with the
494: * prior saved offset. XXX - obviously not documented.
495: */
496: for (nn = n->child; nn; nn = nn->next) {
497: if (NULL == nn->next) {
498: ival = arg_width(nn);
499: if (ival >= 0) {
500: offs = (size_t)ival;
501: break;
502: }
503: }
1.19 kristaps 504: print_node(p, fl, nn, m);
1.18 kristaps 505: }
506:
507: p->rmargin = p->offset + offs;
508:
509: term_flushln(p);
510:
511: p->offset = offs;
512: p->rmargin = p->maxrmargin;
1.4 kristaps 513:
1.18 kristaps 514: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
1.12 kristaps 515:
1.4 kristaps 516: return(0);
1.19 kristaps 517: #endif
518: return(1);
1.4 kristaps 519: }
520:
521:
522: /* ARGSUSED */
523: static int
1.1 kristaps 524: pre_TP(DECL_ARGS)
525: {
526:
1.21 ! kristaps 527: switch (n->type) {
! 528: case (MAN_BLOCK):
! 529: fmt_block_vspace(p, n);
! 530: break;
! 531: case (MAN_HEAD):
! 532: p->rmargin = INDENT * 2;
! 533: p->offset = INDENT;
! 534: p->flags |= TERMP_NOBREAK;
! 535: p->flags |= TERMP_TWOSPACE;
! 536: break;
! 537: case (MAN_BODY):
! 538: p->flags |= TERMP_NOLPAD;
! 539: p->flags |= TERMP_NOSPACE;
! 540: p->offset = INDENT * 2;
! 541: break;
! 542: default:
! 543: break;
! 544: }
1.16 kristaps 545:
1.21 ! kristaps 546: return(1);
! 547: }
1.1 kristaps 548:
549:
1.21 ! kristaps 550: /* ARGSUSED */
! 551: static void
! 552: post_TP(DECL_ARGS)
! 553: {
1.1 kristaps 554:
1.21 ! kristaps 555: switch (n->type) {
! 556: case (MAN_HEAD):
! 557: term_flushln(p);
! 558: p->flags &= ~TERMP_NOBREAK;
! 559: p->flags &= ~TERMP_TWOSPACE;
! 560: p->rmargin = p->maxrmargin;
! 561: break;
! 562: case (MAN_BODY):
! 563: term_flushln(p);
! 564: p->flags &= ~TERMP_NOLPAD;
! 565: break;
! 566: default:
! 567: break;
! 568: }
1.1 kristaps 569: }
570:
571:
1.3 kristaps 572: /* ARGSUSED */
1.1 kristaps 573: static int
574: pre_SS(DECL_ARGS)
575: {
576:
1.19 kristaps 577: switch (n->type) {
578: case (MAN_BLOCK):
579: term_newln(p);
580: if (n->prev)
581: term_vspace(p);
582: break;
583: case (MAN_HEAD):
584: p->flags |= TERMP_BOLD;
585: p->offset = HALFINDENT;
586: break;
587: default:
588: p->offset = INDENT;
589: break;
590: }
591:
1.1 kristaps 592: return(1);
593: }
594:
595:
1.3 kristaps 596: /* ARGSUSED */
1.1 kristaps 597: static void
598: post_SS(DECL_ARGS)
599: {
600:
1.19 kristaps 601: switch (n->type) {
602: case (MAN_HEAD):
603: term_newln(p);
604: p->flags &= ~TERMP_BOLD;
605: break;
606: default:
607: break;
608: }
1.1 kristaps 609: }
610:
611:
1.3 kristaps 612: /* ARGSUSED */
1.1 kristaps 613: static int
614: pre_SH(DECL_ARGS)
615: {
1.19 kristaps 616: /*
617: * XXX: undocumented: using two `SH' macros in sequence has no
618: * vspace between calls, only a newline.
619: */
620: switch (n->type) {
621: case (MAN_BLOCK):
622: if (n->prev && MAN_SH == n->prev->tok)
623: if (NULL == n->prev->body->child)
624: break;
625: term_vspace(p);
626: break;
627: case (MAN_HEAD):
628: p->flags |= TERMP_BOLD;
629: p->offset = 0;
630: break;
631: case (MAN_BODY):
632: p->offset = INDENT;
633: break;
634: default:
635: break;
636: }
1.1 kristaps 637:
638: return(1);
639: }
640:
641:
1.3 kristaps 642: /* ARGSUSED */
1.1 kristaps 643: static void
644: post_SH(DECL_ARGS)
645: {
646:
1.19 kristaps 647: switch (n->type) {
648: case (MAN_HEAD):
649: term_newln(p);
650: p->flags &= ~TERMP_BOLD;
651: break;
652: case (MAN_BODY):
653: term_newln(p);
654: break;
655: default:
656: break;
657: }
1.1 kristaps 658: }
659:
660:
661: static void
662: print_node(DECL_ARGS)
663: {
1.4 kristaps 664: int c, sz;
1.1 kristaps 665:
666: c = 1;
667:
668: switch (n->type) {
669: case(MAN_TEXT):
1.4 kristaps 670: if (0 == *n->string) {
671: term_vspace(p);
1.1 kristaps 672: break;
673: }
1.4 kristaps 674: /*
675: * Note! This is hacky. Here, we recognise the `\c'
676: * escape embedded in so many -man pages. It's supposed
677: * to remove the subsequent space, so we mark NOSPACE if
678: * it's encountered in the string.
679: */
680: sz = (int)strlen(n->string);
681: term_word(p, n->string);
682: if (sz >= 2 && n->string[sz - 1] == 'c' &&
683: n->string[sz - 2] == '\\')
684: p->flags |= TERMP_NOSPACE;
1.19 kristaps 685: /* FIXME: this means that macro lines are munged! */
686: if (MANT_LITERAL & *fl) {
687: p->flags |= TERMP_NOSPACE;
688: term_flushln(p);
689: }
1.1 kristaps 690: break;
691: default:
1.19 kristaps 692: if (termacts[n->tok].pre)
693: c = (*termacts[n->tok].pre)(p, fl, n, m);
1.1 kristaps 694: break;
695: }
696:
697: if (c && n->child)
1.19 kristaps 698: print_body(p, fl, n->child, m);
1.1 kristaps 699:
1.19 kristaps 700: if (MAN_TEXT != n->type)
1.1 kristaps 701: if (termacts[n->tok].post)
1.19 kristaps 702: (*termacts[n->tok].post)(p, fl, n, m);
1.1 kristaps 703: }
704:
705:
706: static void
707: print_body(DECL_ARGS)
708: {
1.19 kristaps 709:
710: print_node(p, fl, n, m);
1.1 kristaps 711: if ( ! n->next)
712: return;
1.19 kristaps 713: print_body(p, fl, n->next, m);
1.1 kristaps 714: }
715:
716:
717: static void
718: print_foot(struct termp *p, const struct man_meta *meta)
719: {
720: struct tm *tm;
721: char *buf;
722:
723: if (NULL == (buf = malloc(p->rmargin)))
724: err(1, "malloc");
725:
726: tm = localtime(&meta->date);
727:
728: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
729: err(1, "strftime");
730:
731: term_vspace(p);
732:
733: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
734: p->rmargin = p->maxrmargin - strlen(buf);
735: p->offset = 0;
736:
737: if (meta->source)
738: term_word(p, meta->source);
739: if (meta->source)
740: term_word(p, "");
741: term_flushln(p);
742:
743: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
744: p->offset = p->rmargin;
745: p->rmargin = p->maxrmargin;
746: p->flags &= ~TERMP_NOBREAK;
747:
748: term_word(p, buf);
749: term_flushln(p);
750:
751: free(buf);
752: }
753:
754:
755: static void
756: print_head(struct termp *p, const struct man_meta *meta)
757: {
758: char *buf, *title;
759:
760: p->rmargin = p->maxrmargin;
761: p->offset = 0;
762:
763: if (NULL == (buf = malloc(p->rmargin)))
764: err(1, "malloc");
765: if (NULL == (title = malloc(p->rmargin)))
766: err(1, "malloc");
767:
768: if (meta->vol)
769: (void)strlcpy(buf, meta->vol, p->rmargin);
770: else
771: *buf = 0;
772:
773: (void)snprintf(title, p->rmargin, "%s(%d)",
774: meta->title, meta->msec);
775:
776: p->offset = 0;
1.10 kristaps 777: p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
1.1 kristaps 778: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
779:
780: term_word(p, title);
781: term_flushln(p);
782:
783: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
784: p->offset = p->rmargin;
785: p->rmargin = p->maxrmargin - strlen(title);
786:
787: term_word(p, buf);
788: term_flushln(p);
789:
790: p->offset = p->rmargin;
791: p->rmargin = p->maxrmargin;
792: p->flags &= ~TERMP_NOBREAK;
793: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
794:
795: term_word(p, title);
796: term_flushln(p);
797:
798: p->rmargin = p->maxrmargin;
799: p->offset = 0;
800: p->flags &= ~TERMP_NOSPACE;
801:
802: free(title);
803: free(buf);
804: }
805:
CVSweb