Annotation of mandoc/term.c, Revision 1.2
1.2 ! kristaps 1: /* $Id: term.c,v 1.1 2009/02/20 11:04:23 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 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>
1.2 ! kristaps 20: #include <ctype.h>
1.1 kristaps 21: #include <curses.h>
22: #include <err.h>
23: #include <stdlib.h>
24: #include <stdio.h>
25: #include <string.h>
26: #include <term.h>
27: #include <unistd.h>
28:
1.2 ! kristaps 29: #include "private.h"
1.1 kristaps 30:
31:
1.2 ! kristaps 32: enum termesc {
! 33: ESC_CLEAR,
! 34: ESC_BOLD,
! 35: ESC_UNDERLINE
! 36: };
! 37:
! 38: struct termp {
! 39: size_t maxvisible;
! 40: size_t maxcols;
! 41: size_t indent;
! 42: size_t col;
! 43: int flags;
! 44: #define TERMP_BOLD (1 << 0)
! 45: #define TERMP_UNDERLINE (1 << 1)
! 46: #define TERMP_NOSPACE (1 << 2)
! 47: char *buf;
! 48: };
! 49:
! 50: struct termact {
! 51: int (*pre)(struct termp *,
! 52: const struct mdoc_meta *,
1.1 kristaps 53: const struct mdoc_node *);
1.2 ! kristaps 54: int (*post)(struct termp *,
! 55: const struct mdoc_meta *,
! 56: const struct mdoc_node *);
! 57: };
! 58:
! 59: static void termprint_r(struct termp *,
! 60: const struct mdoc_meta *,
! 61: const struct mdoc_node *);
! 62: static void termprint_header(struct termp *,
1.1 kristaps 63: const struct mdoc_meta *);
1.2 ! kristaps 64: static void termprint_footer(struct termp *,
1.1 kristaps 65: const struct mdoc_meta *);
66:
1.2 ! kristaps 67: static void newln(struct termp *);
! 68: static void vspace(struct termp *);
! 69: static void pword(struct termp *, const char *, size_t);
! 70: static void word(struct termp *, const char *);
! 71:
! 72: static int termp_it_pre(struct termp *,
! 73: const struct mdoc_meta *,
! 74: const struct mdoc_node *);
! 75: static int termp_ns_pre(struct termp *,
! 76: const struct mdoc_meta *,
! 77: const struct mdoc_node *);
! 78: static int termp_pp_pre(struct termp *,
! 79: const struct mdoc_meta *,
! 80: const struct mdoc_node *);
! 81: static int termp_fl_pre(struct termp *,
! 82: const struct mdoc_meta *,
! 83: const struct mdoc_node *);
! 84: static int termp_op_pre(struct termp *,
! 85: const struct mdoc_meta *,
! 86: const struct mdoc_node *);
! 87: static int termp_op_post(struct termp *,
! 88: const struct mdoc_meta *,
! 89: const struct mdoc_node *);
! 90: static int termp_bl_post(struct termp *,
! 91: const struct mdoc_meta *,
! 92: const struct mdoc_node *);
! 93: static int termp_sh_post(struct termp *,
! 94: const struct mdoc_meta *,
! 95: const struct mdoc_node *);
! 96: static int termp_sh_pre(struct termp *,
! 97: const struct mdoc_meta *,
! 98: const struct mdoc_node *);
! 99: static int termp_nd_pre(struct termp *,
! 100: const struct mdoc_meta *,
! 101: const struct mdoc_node *);
! 102: static int termp_bold_pre(struct termp *,
! 103: const struct mdoc_meta *,
! 104: const struct mdoc_node *);
! 105: static int termp_under_pre(struct termp *,
! 106: const struct mdoc_meta *,
! 107: const struct mdoc_node *);
! 108: static int termp_bold_post(struct termp *,
! 109: const struct mdoc_meta *,
! 110: const struct mdoc_node *);
! 111: static int termp_under_post(struct termp *,
! 112: const struct mdoc_meta *,
! 113: const struct mdoc_node *);
! 114:
! 115: const struct termact termacts[MDOC_MAX] = {
! 116: { NULL, NULL }, /* \" */
! 117: { NULL, NULL }, /* Dd */
! 118: { NULL, NULL }, /* Dt */
! 119: { NULL, NULL }, /* Os */
! 120: { termp_sh_pre, termp_sh_post }, /* Sh */
! 121: { NULL, NULL }, /* Ss */
! 122: { termp_pp_pre, NULL }, /* Pp */
! 123: { NULL, NULL }, /* D1 */
! 124: { NULL, NULL }, /* Dl */
! 125: { NULL, NULL }, /* Bd */
! 126: { NULL, NULL }, /* Ed */
! 127: { NULL, termp_bl_post }, /* Bl */
! 128: { NULL, NULL }, /* El */
! 129: { termp_it_pre, NULL }, /* It */
! 130: { NULL, NULL }, /* Ad */
! 131: { NULL, NULL }, /* An */
! 132: { termp_under_pre, termp_under_post }, /* Ar */
! 133: { NULL, NULL }, /* Cd */
! 134: { NULL, NULL }, /* Cm */
! 135: { NULL, NULL }, /* Dv */
! 136: { NULL, NULL }, /* Er */
! 137: { NULL, NULL }, /* Ev */
! 138: { NULL, NULL }, /* Ex */
! 139: { NULL, NULL }, /* Fa */
! 140: { NULL, NULL }, /* Fd */
! 141: { termp_fl_pre, termp_bold_post }, /* Fl */
! 142: { NULL, NULL }, /* Fn */
! 143: { NULL, NULL }, /* Ft */
! 144: { NULL, NULL }, /* Ic */
! 145: { NULL, NULL }, /* In */
! 146: { NULL, NULL }, /* Li */
! 147: { termp_nd_pre, NULL }, /* Nd */
! 148: { termp_bold_pre, termp_bold_post }, /* Nm */
! 149: { termp_op_pre, termp_op_post }, /* Op */
! 150: { NULL, NULL }, /* Ot */
! 151: { NULL, NULL }, /* Pa */
! 152: { NULL, NULL }, /* Rv */
! 153: { NULL, NULL }, /* St */
! 154: { NULL, NULL }, /* Va */
! 155: { NULL, NULL }, /* Vt */
! 156: { NULL, NULL }, /* Xr */
! 157: { NULL, NULL }, /* %A */
! 158: { NULL, NULL }, /* %B */
! 159: { NULL, NULL }, /* %D */
! 160: { NULL, NULL }, /* %I */
! 161: { NULL, NULL }, /* %J */
! 162: { NULL, NULL }, /* %N */
! 163: { NULL, NULL }, /* %O */
! 164: { NULL, NULL }, /* %P */
! 165: { NULL, NULL }, /* %R */
! 166: { NULL, NULL }, /* %T */
! 167: { NULL, NULL }, /* %V */
! 168: { NULL, NULL }, /* Ac */
! 169: { NULL, NULL }, /* Ao */
! 170: { NULL, NULL }, /* Aq */
! 171: { NULL, NULL }, /* At */
! 172: { NULL, NULL }, /* Bc */
! 173: { NULL, NULL }, /* Bf */
! 174: { NULL, NULL }, /* Bo */
! 175: { NULL, NULL }, /* Bq */
! 176: { NULL, NULL }, /* Bsx */
! 177: { NULL, NULL }, /* Bx */
! 178: { NULL, NULL }, /* Db */
! 179: { NULL, NULL }, /* Dc */
! 180: { NULL, NULL }, /* Do */
! 181: { NULL, NULL }, /* Dq */
! 182: { NULL, NULL }, /* Ec */
! 183: { NULL, NULL }, /* Ef */
! 184: { NULL, NULL }, /* Em */
! 185: { NULL, NULL }, /* Eo */
! 186: { NULL, NULL }, /* Fx */
! 187: { NULL, NULL }, /* Ms */
! 188: { NULL, NULL }, /* No */
! 189: { termp_ns_pre, NULL }, /* Ns */
! 190: { NULL, NULL }, /* Nx */
! 191: { NULL, NULL }, /* Ox */
! 192: { NULL, NULL }, /* Pc */
! 193: { NULL, NULL }, /* Pf */
! 194: { NULL, NULL }, /* Po */
! 195: { NULL, NULL }, /* Pq */
! 196: { NULL, NULL }, /* Qc */
! 197: { NULL, NULL }, /* Ql */
! 198: { NULL, NULL }, /* Qo */
! 199: { NULL, NULL }, /* Qq */
! 200: { NULL, NULL }, /* Re */
! 201: { NULL, NULL }, /* Rs */
! 202: { NULL, NULL }, /* Sc */
! 203: { NULL, NULL }, /* So */
! 204: { NULL, NULL }, /* Sq */
! 205: { NULL, NULL }, /* Sm */
! 206: { NULL, NULL }, /* Sx */
! 207: { NULL, NULL }, /* Sy */
! 208: { NULL, NULL }, /* Tn */
! 209: { NULL, NULL }, /* Ux */
! 210: { NULL, NULL }, /* Xc */
! 211: { NULL, NULL }, /* Xo */
! 212: { NULL, NULL }, /* Fo */
! 213: { NULL, NULL }, /* Fc */
! 214: { NULL, NULL }, /* Oo */
! 215: { NULL, NULL }, /* Oc */
! 216: { NULL, NULL }, /* Bk */
! 217: { NULL, NULL }, /* Ek */
! 218: { NULL, NULL }, /* Bt */
! 219: { NULL, NULL }, /* Hf */
! 220: { NULL, NULL }, /* Fr */
! 221: { NULL, NULL }, /* Ud */
! 222: };
! 223:
! 224:
! 225: static void
! 226: flush(struct termp *p)
! 227: {
! 228: size_t i, j, vsz, vis, maxvis;
! 229:
! 230: maxvis = p->maxvisible - (p->indent * 4);
! 231: vis = 0;
! 232:
! 233: for (j = 0; j < (p->indent * 4); j++)
! 234: putchar(' ');
! 235:
! 236: for (i = 0; i < p->col; i++) {
! 237: for (j = i, vsz = 0; j < p->col; j++) {
! 238: if (isspace(p->buf[j]))
! 239: break;
! 240: else if (27 == p->buf[j]) {
! 241: assert(j + 4 <= p->col);
! 242: j += 3;
! 243: } else
! 244: vsz++;
! 245: }
! 246: assert(vsz > 0);
! 247:
! 248: if (vis && vis + vsz >= maxvis) {
! 249: putchar('\n');
! 250: for (j = 0; j < (p->indent * 4); j++)
! 251: putchar(' ');
! 252: vis = 0;
! 253: }
! 254:
! 255: for ( ; i < p->col; i++) {
! 256: if (isspace(p->buf[i]))
! 257: break;
! 258: putchar(p->buf[i]);
! 259: }
! 260: vis += vsz;
! 261: if (i < p->col) {
! 262: putchar(' ');
! 263: vis++;
! 264: }
! 265: }
! 266:
! 267: putchar('\n');
! 268: p->col = 0;
! 269: }
! 270:
! 271:
! 272: static void
! 273: newln(struct termp *p)
! 274: {
! 275:
! 276: p->flags |= TERMP_NOSPACE;
! 277: if (0 == p->col)
! 278: return;
! 279: flush(p);
! 280: }
! 281:
! 282:
! 283: static void
! 284: vspace(struct termp *p)
! 285: {
! 286:
! 287: newln(p);
! 288: putchar('\n');
! 289: }
! 290:
! 291:
! 292: static void
! 293: chara(struct termp *p, char c)
! 294: {
! 295:
! 296: if (p->col + 1 >= p->maxcols)
! 297: errx(1, "line overrun");
! 298:
! 299: p->buf[(p->col)++] = c;
! 300: }
! 301:
! 302:
! 303: static void
! 304: escape(struct termp *p, enum termesc esc)
! 305: {
! 306:
! 307: if (p->col + 4 >= p->maxcols)
! 308: errx(1, "line overrun");
! 309:
! 310: p->buf[(p->col)++] = 27;
! 311: p->buf[(p->col)++] = '[';
! 312: switch (esc) {
! 313: case (ESC_CLEAR):
! 314: p->buf[(p->col)++] = '0';
! 315: break;
! 316: case (ESC_BOLD):
! 317: p->buf[(p->col)++] = '1';
! 318: break;
! 319: case (ESC_UNDERLINE):
! 320: p->buf[(p->col)++] = '4';
! 321: break;
! 322: default:
! 323: abort();
! 324: /* NOTREACHED */
! 325: }
! 326: p->buf[(p->col)++] = 'm';
! 327: }
! 328:
! 329:
! 330: static void
! 331: pword(struct termp *p, const char *word, size_t len)
! 332: {
! 333: size_t i;
! 334:
! 335: assert(len > 0);
! 336:
! 337: if ( ! (p->flags & TERMP_NOSPACE))
! 338: chara(p, ' ');
! 339:
! 340: p->flags &= ~TERMP_NOSPACE;
! 341:
! 342: if (p->flags & TERMP_BOLD)
! 343: escape(p, ESC_BOLD);
! 344: if (p->flags & TERMP_UNDERLINE)
! 345: escape(p, ESC_UNDERLINE);
! 346:
! 347: for (i = 0; i < len; i++)
! 348: chara(p, word[i]);
! 349:
! 350: if (p->flags & TERMP_BOLD ||
! 351: p->flags & TERMP_UNDERLINE)
! 352: escape(p, ESC_CLEAR);
! 353: }
! 354:
! 355:
! 356: static void
! 357: word(struct termp *p, const char *word)
! 358: {
! 359: size_t i, j, len;
! 360:
! 361: /* TODO: delimiters? */
! 362:
! 363: len = strlen(word);
! 364: assert(len > 0);
! 365:
! 366: for (j = i = 0; i < len; i++) {
! 367: if ( ! isspace(word[i])) {
! 368: j++;
! 369: continue;
! 370: }
! 371: if (0 == j)
! 372: continue;
! 373: assert(i >= j);
! 374: pword(p, &word[i - j], j);
! 375: j = 0;
! 376: }
! 377: if (j > 0) {
! 378: assert(i >= j);
! 379: pword(p, &word[i - j], j);
! 380: }
! 381: }
! 382:
! 383:
! 384: static int
! 385: termp_it_pre(struct termp *p, const struct mdoc_meta *meta,
! 386: const struct mdoc_node *node)
! 387: {
! 388:
! 389: switch (node->type) {
! 390: case (MDOC_HEAD):
! 391: /* TODO: only print one, if compat. */
! 392: vspace(p);
! 393: break;
1.1 kristaps 394: default:
395: break;
396: }
1.2 ! kristaps 397: return(1);
! 398: }
1.1 kristaps 399:
1.2 ! kristaps 400:
! 401: static int
! 402: termp_bold_post(struct termp *p, const struct mdoc_meta *meta,
! 403: const struct mdoc_node *node)
! 404: {
! 405:
! 406: p->flags &= ~TERMP_BOLD;
! 407: return(1);
! 408: }
! 409:
! 410:
! 411: static int
! 412: termp_under_pre(struct termp *p, const struct mdoc_meta *meta,
! 413: const struct mdoc_node *node)
! 414: {
! 415:
! 416: p->flags |= TERMP_UNDERLINE;
! 417: return(1);
1.1 kristaps 418: }
419:
420:
1.2 ! kristaps 421: static int
! 422: termp_bold_pre(struct termp *p, const struct mdoc_meta *meta,
! 423: const struct mdoc_node *node)
1.1 kristaps 424: {
425:
1.2 ! kristaps 426: p->flags |= TERMP_BOLD;
! 427: return(1);
! 428: }
! 429:
! 430:
! 431: static int
! 432: termp_ns_pre(struct termp *p, const struct mdoc_meta *meta,
! 433: const struct mdoc_node *node)
! 434: {
! 435:
! 436: p->flags |= TERMP_NOSPACE;
! 437: return(1);
! 438: }
! 439:
! 440:
! 441: static int
! 442: termp_pp_pre(struct termp *p, const struct mdoc_meta *meta,
! 443: const struct mdoc_node *node)
! 444: {
! 445:
! 446: vspace(p);
! 447: return(1);
! 448: }
! 449:
! 450:
! 451: static int
! 452: termp_under_post(struct termp *p, const struct mdoc_meta *meta,
! 453: const struct mdoc_node *node)
! 454: {
! 455:
! 456: p->flags &= ~TERMP_UNDERLINE;
! 457: return(1);
! 458: }
! 459:
! 460:
! 461: static int
! 462: termp_nd_pre(struct termp *p, const struct mdoc_meta *meta,
! 463: const struct mdoc_node *node)
! 464: {
! 465:
! 466: word(p, "-");
! 467: return(1);
! 468: }
! 469:
! 470:
! 471: static int
! 472: termp_bl_post(struct termp *p, const struct mdoc_meta *meta,
! 473: const struct mdoc_node *node)
! 474: {
! 475:
! 476: switch (node->type) {
! 477: case (MDOC_BLOCK):
! 478: newln(p);
! 479: break;
1.1 kristaps 480: default:
481: break;
482: }
1.2 ! kristaps 483: return(1);
1.1 kristaps 484: }
485:
486:
1.2 ! kristaps 487: static int
! 488: termp_op_post(struct termp *p, const struct mdoc_meta *meta,
! 489: const struct mdoc_node *node)
! 490: {
! 491:
! 492: switch (node->type) {
! 493: case (MDOC_BODY):
! 494: p->flags |= TERMP_NOSPACE;
! 495: word(p, "\\(rB");
! 496: break;
! 497: default:
! 498: break;
! 499: }
! 500: return(1);
! 501: }
! 502:
! 503:
! 504: static int
! 505: termp_sh_post(struct termp *p, const struct mdoc_meta *meta,
! 506: const struct mdoc_node *node)
1.1 kristaps 507: {
508:
1.2 ! kristaps 509: switch (node->type) {
! 510: case (MDOC_HEAD):
! 511: p->flags &= ~TERMP_BOLD;
! 512: newln(p);
! 513: break;
! 514: case (MDOC_BODY):
! 515: newln(p);
! 516: (p->indent)--;
! 517: break;
! 518: default:
! 519: break;
! 520: }
! 521: return(1);
! 522: }
! 523:
1.1 kristaps 524:
1.2 ! kristaps 525: static int
! 526: termp_sh_pre(struct termp *p, const struct mdoc_meta *meta,
! 527: const struct mdoc_node *node)
! 528: {
1.1 kristaps 529:
1.2 ! kristaps 530: switch (node->type) {
! 531: case (MDOC_HEAD):
! 532: vspace(p);
! 533: p->flags |= TERMP_BOLD;
! 534: break;
! 535: case (MDOC_BODY):
! 536: (p->indent)++;
! 537: break;
! 538: default:
! 539: break;
1.1 kristaps 540: }
1.2 ! kristaps 541: return(1);
! 542: }
! 543:
1.1 kristaps 544:
1.2 ! kristaps 545: static int
! 546: termp_op_pre(struct termp *p, const struct mdoc_meta *meta,
! 547: const struct mdoc_node *node)
! 548: {
! 549:
! 550: switch (node->type) {
! 551: case (MDOC_BODY):
! 552: word(p, "\\(lB");
! 553: p->flags |= TERMP_NOSPACE;
! 554: break;
! 555: default:
! 556: break;
! 557: }
! 558: return(1);
1.1 kristaps 559: }
560:
561:
562: static int
1.2 ! kristaps 563: termp_fl_pre(struct termp *p, const struct mdoc_meta *meta,
! 564: const struct mdoc_node *node)
1.1 kristaps 565: {
566:
1.2 ! kristaps 567: p->flags |= TERMP_BOLD;
! 568: word(p, "-");
! 569: p->flags |= TERMP_NOSPACE;
1.1 kristaps 570: return(1);
571: }
572:
573:
574: static void
1.2 ! kristaps 575: termprint_r(struct termp *p, const struct mdoc_meta *meta,
! 576: const struct mdoc_node *node)
! 577: {
! 578:
! 579: /* Pre-processing ----------------- */
! 580:
! 581: if (MDOC_TEXT != node->type) {
! 582: if (termacts[node->tok].pre)
! 583: if ( ! (*termacts[node->tok].pre)(p, meta, node))
! 584: return;
! 585: } else /* MDOC_TEXT == node->type */
! 586: word(p, node->data.text.string);
! 587:
! 588: /* Children ---------------------- */
! 589:
! 590: if (NULL == node->child) {
! 591: /* No-child processing. */
! 592: switch (node->type) {
! 593: case (MDOC_ELEM):
! 594: switch (node->tok) {
! 595: case (MDOC_Nm):
! 596: word(p, "progname"); /* TODO */
! 597: break;
! 598: case (MDOC_Ar):
! 599: word(p, "...");
! 600: break;
! 601: default:
! 602: break;
! 603: }
! 604: break;
! 605: default:
! 606: break;
! 607: }
! 608: } else
! 609: termprint_r(p, meta, node->child);
! 610:
! 611: /* Post-processing --------------- */
! 612:
! 613: if (MDOC_TEXT != node->type) {
! 614: if (termacts[node->tok].post)
! 615: if ( ! (*termacts[node->tok].post)(p, meta, node))
! 616: return;
! 617: }
! 618:
! 619: /* Siblings ---------------------- */
! 620:
! 621: if (node->next)
! 622: termprint_r(p, meta, node->next);
! 623: }
! 624:
! 625:
! 626: static void
! 627: termprint_footer(struct termp *p, const struct mdoc_meta *meta)
1.1 kristaps 628: {
629: struct tm *tm;
630: char *buf, *os;
631: size_t sz, osz, ssz, i;
632:
1.2 ! kristaps 633: if (NULL == (buf = malloc(p->maxvisible)))
1.1 kristaps 634: err(1, "malloc");
1.2 ! kristaps 635: if (NULL == (os = malloc(p->maxvisible)))
1.1 kristaps 636: err(1, "malloc");
637:
638: tm = localtime(&meta->date);
1.2 ! kristaps 639: if (NULL == strftime(buf, p->maxvisible, "%B %d, %Y", tm))
1.1 kristaps 640: err(1, "strftime");
641:
1.2 ! kristaps 642: osz = strlcpy(os, meta->os, p->maxvisible);
1.1 kristaps 643:
644: sz = strlen(buf);
645: ssz = sz + osz + 1;
646:
1.2 ! kristaps 647: if (ssz > p->maxvisible) {
! 648: ssz -= p->maxvisible;
1.1 kristaps 649: assert(ssz <= osz);
650: os[osz - ssz] = 0;
651: ssz = 1;
652: } else
1.2 ! kristaps 653: ssz = p->maxvisible - ssz + 1;
1.1 kristaps 654:
1.2 ! kristaps 655: printf("\n");
1.1 kristaps 656: printf("%s", os);
657: for (i = 0; i < ssz; i++)
658: printf(" ");
659:
660: printf("%s\n", buf);
1.2 ! kristaps 661: fflush(stdout);
1.1 kristaps 662:
663: free(buf);
664: free(os);
665: }
666:
667:
668: static void
1.2 ! kristaps 669: termprint_header(struct termp *p, const struct mdoc_meta *meta)
1.1 kristaps 670: {
1.2 ! kristaps 671: char *msec, *buf, *title, *pp;
! 672: size_t ssz, tsz, ttsz, i;;
1.1 kristaps 673:
1.2 ! kristaps 674: if (NULL == (buf = malloc(p->maxvisible)))
1.1 kristaps 675: err(1, "malloc");
1.2 ! kristaps 676: if (NULL == (title = malloc(p->maxvisible)))
1.1 kristaps 677: err(1, "malloc");
678:
1.2 ! kristaps 679: if (NULL == (pp = mdoc_vol2a(meta->vol)))
! 680: switch (meta->msec) {
! 681: case (MSEC_1):
! 682: /* FALLTHROUGH */
! 683: case (MSEC_6):
! 684: /* FALLTHROUGH */
! 685: case (MSEC_7):
! 686: pp = mdoc_vol2a(VOL_URM);
! 687: break;
! 688: case (MSEC_8):
! 689: pp = mdoc_vol2a(VOL_SMM);
! 690: break;
! 691: case (MSEC_2):
! 692: /* FALLTHROUGH */
! 693: case (MSEC_3):
! 694: /* FALLTHROUGH */
! 695: case (MSEC_4):
! 696: /* FALLTHROUGH */
! 697: case (MSEC_5):
! 698: pp = mdoc_vol2a(VOL_PRM);
! 699: break;
! 700: case (MSEC_9):
! 701: pp = mdoc_vol2a(VOL_KM);
! 702: break;
! 703: default:
! 704: /* FIXME: capitalise. */
! 705: if (NULL == (pp = mdoc_msec2a(meta->msec)))
! 706: pp = mdoc_msec2a(MSEC_local);
! 707: break;
! 708: }
! 709: assert(pp);
1.1 kristaps 710:
1.2 ! kristaps 711: tsz = strlcpy(buf, pp, p->maxvisible);
! 712: assert(tsz < p->maxvisible);
1.1 kristaps 713:
1.2 ! kristaps 714: if ((pp = mdoc_arch2a(meta->arch))) {
! 715: tsz = strlcat(buf, " (", p->maxvisible);
! 716: assert(tsz < p->maxvisible);
! 717: tsz = strlcat(buf, pp, p->maxvisible);
! 718: assert(tsz < p->maxvisible);
! 719: tsz = strlcat(buf, ")", p->maxvisible);
! 720: assert(tsz < p->maxvisible);
! 721: }
! 722:
! 723: ttsz = strlcpy(title, meta->title, p->maxvisible);
! 724:
! 725: if (NULL == (msec = mdoc_msec2a(meta->msec)))
1.1 kristaps 726: msec = "";
727:
728: ssz = (2 * (ttsz + 2 + strlen(msec))) + tsz + 2;
729:
1.2 ! kristaps 730: if (ssz > p->maxvisible) {
! 731: if ((ssz -= p->maxvisible) % 2)
1.1 kristaps 732: ssz++;
733: ssz /= 2;
734:
735: assert(ssz <= ttsz);
736: title[ttsz - ssz] = 0;
737: ssz = 1;
738: } else
1.2 ! kristaps 739: ssz = ((p->maxvisible - ssz) / 2) + 1;
1.1 kristaps 740:
741: printf("%s(%s)", title, msec);
742:
743: for (i = 0; i < ssz; i++)
744: printf(" ");
745:
746: printf("%s", buf);
747:
748: for (i = 0; i < ssz; i++)
749: printf(" ");
750:
1.2 ! kristaps 751: printf("%s(%s)\n", title, msec);
! 752: fflush(stdout);
1.1 kristaps 753:
754: free(title);
755: free(buf);
756: }
757:
758:
759: int
760: termprint(const struct mdoc_node *node,
761: const struct mdoc_meta *meta)
762: {
1.2 ! kristaps 763: struct termp p;
1.1 kristaps 764:
765: if (ERR == setupterm(NULL, STDOUT_FILENO, NULL))
766: return(0);
767:
1.2 ! kristaps 768: p.maxvisible = columns < 60 ? 60 : (size_t)columns;
! 769: p.maxcols = 1024;
! 770: p.indent = p.col = 0;
! 771: p.flags = TERMP_NOSPACE;
! 772:
! 773: if (NULL == (p.buf = malloc(p.maxcols)))
! 774: err(1, "malloc");
! 775:
! 776: termprint_header(&p, meta);
! 777: termprint_r(&p, meta, node);
! 778: termprint_footer(&p, meta);
! 779:
! 780: free(p.buf);
1.1 kristaps 781:
782: return(1);
783: }
784:
785:
CVSweb