Annotation of src/usr.bin/mandoc/man_term.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: man_term.c,v 1.7 2009/04/05 16:34:22 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 <assert.h>
! 20: #include <err.h>
! 21: #include <stdio.h>
! 22: #include <stdlib.h>
! 23: #include <string.h>
! 24:
! 25: #include "term.h"
! 26: #include "man.h"
! 27:
! 28: #define DECL_ARGS struct termp *p, \
! 29: const struct man_node *n, \
! 30: const struct man_meta *m
! 31:
! 32: struct termact {
! 33: int (*pre)(DECL_ARGS);
! 34: void (*post)(DECL_ARGS);
! 35: };
! 36:
! 37: static int pre_B(DECL_ARGS);
! 38: static int pre_BI(DECL_ARGS);
! 39: static int pre_BR(DECL_ARGS);
! 40: static int pre_I(DECL_ARGS);
! 41: static int pre_IB(DECL_ARGS);
! 42: static int pre_IP(DECL_ARGS);
! 43: static int pre_IR(DECL_ARGS);
! 44: static int pre_PP(DECL_ARGS);
! 45: static int pre_RB(DECL_ARGS);
! 46: static int pre_RI(DECL_ARGS);
! 47: static int pre_SH(DECL_ARGS);
! 48: static int pre_SS(DECL_ARGS);
! 49: static int pre_TP(DECL_ARGS);
! 50:
! 51: static void post_B(DECL_ARGS);
! 52: static void post_I(DECL_ARGS);
! 53: static void post_SH(DECL_ARGS);
! 54: static void post_SS(DECL_ARGS);
! 55:
! 56: static const struct termact termacts[MAN_MAX] = {
! 57: { NULL, NULL }, /* __ */
! 58: { NULL, NULL }, /* TH */
! 59: { pre_SH, post_SH }, /* SH */
! 60: { pre_SS, post_SS }, /* SS */
! 61: { pre_TP, NULL }, /* TP */
! 62: { pre_PP, NULL }, /* LP */
! 63: { pre_PP, NULL }, /* PP */
! 64: { pre_PP, NULL }, /* P */
! 65: { pre_IP, NULL }, /* IP */
! 66: { pre_PP, NULL }, /* HP */ /* FIXME */
! 67: { NULL, NULL }, /* SM */
! 68: { pre_B, post_B }, /* SB */
! 69: { pre_BI, NULL }, /* BI */
! 70: { pre_IB, NULL }, /* IB */
! 71: { pre_BR, NULL }, /* BR */
! 72: { pre_RB, NULL }, /* RB */
! 73: { NULL, NULL }, /* R */
! 74: { pre_B, post_B }, /* B */
! 75: { pre_I, post_I }, /* I */
! 76: { pre_IR, NULL }, /* IR */
! 77: { pre_RI, NULL }, /* RI */
! 78: { pre_PP, NULL }, /* br */
! 79: { NULL, NULL }, /* na */
! 80: { pre_I, post_I }, /* i */
! 81: };
! 82:
! 83: static void print_head(struct termp *,
! 84: const struct man_meta *);
! 85: static void print_body(DECL_ARGS);
! 86: static void print_node(DECL_ARGS);
! 87: static void print_foot(struct termp *,
! 88: const struct man_meta *);
! 89:
! 90:
! 91: int
! 92: man_run(struct termp *p, const struct man *m)
! 93: {
! 94:
! 95: print_head(p, man_meta(m));
! 96: p->flags |= TERMP_NOSPACE;
! 97: print_body(p, man_node(m), man_meta(m));
! 98: print_foot(p, man_meta(m));
! 99:
! 100: return(1);
! 101: }
! 102:
! 103:
! 104: /* ARGSUSED */
! 105: static int
! 106: pre_I(DECL_ARGS)
! 107: {
! 108:
! 109: p->flags |= TERMP_UNDER;
! 110: return(1);
! 111: }
! 112:
! 113:
! 114: /* ARGSUSED */
! 115: static void
! 116: post_I(DECL_ARGS)
! 117: {
! 118:
! 119: p->flags &= ~TERMP_UNDER;
! 120: }
! 121:
! 122:
! 123: /* ARGSUSED */
! 124: static int
! 125: pre_IR(DECL_ARGS)
! 126: {
! 127: const struct man_node *nn;
! 128: int i;
! 129:
! 130: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
! 131: if ( ! (i % 2))
! 132: p->flags |= TERMP_UNDER;
! 133: if (i > 0)
! 134: p->flags |= TERMP_NOSPACE;
! 135: print_node(p, nn, m);
! 136: if ( ! (i % 2))
! 137: p->flags &= ~TERMP_UNDER;
! 138: }
! 139: return(0);
! 140: }
! 141:
! 142:
! 143: /* ARGSUSED */
! 144: static int
! 145: pre_IB(DECL_ARGS)
! 146: {
! 147: const struct man_node *nn;
! 148: int i;
! 149:
! 150: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
! 151: p->flags |= i % 2 ? TERMP_BOLD : TERMP_UNDER;
! 152: if (i > 0)
! 153: p->flags |= TERMP_NOSPACE;
! 154: print_node(p, nn, m);
! 155: p->flags &= i % 2 ? ~TERMP_BOLD : ~TERMP_UNDER;
! 156: }
! 157: return(0);
! 158: }
! 159:
! 160:
! 161: /* ARGSUSED */
! 162: static int
! 163: pre_RB(DECL_ARGS)
! 164: {
! 165: const struct man_node *nn;
! 166: int i;
! 167:
! 168: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
! 169: if (i % 2)
! 170: p->flags |= TERMP_BOLD;
! 171: if (i > 0)
! 172: p->flags |= TERMP_NOSPACE;
! 173: print_node(p, nn, m);
! 174: if (i % 2)
! 175: p->flags &= ~TERMP_BOLD;
! 176: }
! 177: return(0);
! 178: }
! 179:
! 180:
! 181: /* ARGSUSED */
! 182: static int
! 183: pre_RI(DECL_ARGS)
! 184: {
! 185: const struct man_node *nn;
! 186: int i;
! 187:
! 188: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
! 189: if ( ! (i % 2))
! 190: p->flags |= TERMP_UNDER;
! 191: if (i > 0)
! 192: p->flags |= TERMP_NOSPACE;
! 193: print_node(p, nn, m);
! 194: if ( ! (i % 2))
! 195: p->flags &= ~TERMP_UNDER;
! 196: }
! 197: return(0);
! 198: }
! 199:
! 200:
! 201: /* ARGSUSED */
! 202: static int
! 203: pre_BR(DECL_ARGS)
! 204: {
! 205: const struct man_node *nn;
! 206: int i;
! 207:
! 208: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
! 209: if ( ! (i % 2))
! 210: p->flags |= TERMP_BOLD;
! 211: if (i > 0)
! 212: p->flags |= TERMP_NOSPACE;
! 213: print_node(p, nn, m);
! 214: if ( ! (i % 2))
! 215: p->flags &= ~TERMP_BOLD;
! 216: }
! 217: return(0);
! 218: }
! 219:
! 220:
! 221: /* ARGSUSED */
! 222: static int
! 223: pre_BI(DECL_ARGS)
! 224: {
! 225: const struct man_node *nn;
! 226: int i;
! 227:
! 228: for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
! 229: p->flags |= i % 2 ? TERMP_UNDER : TERMP_BOLD;
! 230: if (i > 0)
! 231: p->flags |= TERMP_NOSPACE;
! 232: print_node(p, nn, m);
! 233: p->flags &= i % 2 ? ~TERMP_UNDER : ~TERMP_BOLD;
! 234: }
! 235: return(0);
! 236: }
! 237:
! 238:
! 239: /* ARGSUSED */
! 240: static int
! 241: pre_B(DECL_ARGS)
! 242: {
! 243:
! 244: p->flags |= TERMP_BOLD;
! 245: return(1);
! 246: }
! 247:
! 248:
! 249: /* ARGSUSED */
! 250: static void
! 251: post_B(DECL_ARGS)
! 252: {
! 253:
! 254: p->flags &= ~TERMP_BOLD;
! 255: }
! 256:
! 257:
! 258: /* ARGSUSED */
! 259: static int
! 260: pre_PP(DECL_ARGS)
! 261: {
! 262:
! 263: term_vspace(p);
! 264: p->offset = INDENT;
! 265: return(0);
! 266: }
! 267:
! 268:
! 269: /* ARGSUSED */
! 270: static int
! 271: pre_IP(DECL_ARGS)
! 272: {
! 273: #if 0
! 274: const struct man_node *nn;
! 275: size_t offs;
! 276: #endif
! 277:
! 278: term_vspace(p);
! 279: p->offset = INDENT;
! 280:
! 281: #if 0
! 282: if (NULL == (nn = n->child))
! 283: return(1);
! 284: if (MAN_TEXT != nn->type)
! 285: errx(1, "expected text line argument");
! 286:
! 287: if (nn->next) {
! 288: if (MAN_TEXT != nn->next->type)
! 289: errx(1, "expected text line argument");
! 290: offs = (size_t)atoi(nn->next->string);
! 291: } else
! 292: offs = strlen(nn->string);
! 293:
! 294: p->offset += offs;
! 295: #endif
! 296: p->flags |= TERMP_NOSPACE;
! 297: return(0);
! 298: }
! 299:
! 300:
! 301: /* ARGSUSED */
! 302: static int
! 303: pre_TP(DECL_ARGS)
! 304: {
! 305: const struct man_node *nn;
! 306: size_t offs;
! 307:
! 308: term_vspace(p);
! 309: p->offset = INDENT;
! 310:
! 311: if (NULL == (nn = n->child))
! 312: return(1);
! 313:
! 314: if (nn->line == n->line) {
! 315: if (MAN_TEXT != nn->type)
! 316: errx(1, "expected text line argument");
! 317: offs = (size_t)atoi(nn->string);
! 318: nn = nn->next;
! 319: } else
! 320: offs = INDENT;
! 321:
! 322: for ( ; nn; nn = nn->next)
! 323: print_node(p, nn, m);
! 324:
! 325: term_flushln(p);
! 326: p->flags |= TERMP_NOSPACE;
! 327: p->offset += offs;
! 328: return(0);
! 329: }
! 330:
! 331:
! 332: /* ARGSUSED */
! 333: static int
! 334: pre_SS(DECL_ARGS)
! 335: {
! 336:
! 337: term_vspace(p);
! 338: p->flags |= TERMP_BOLD;
! 339: return(1);
! 340: }
! 341:
! 342:
! 343: /* ARGSUSED */
! 344: static void
! 345: post_SS(DECL_ARGS)
! 346: {
! 347:
! 348: term_flushln(p);
! 349: p->flags &= ~TERMP_BOLD;
! 350: p->flags |= TERMP_NOSPACE;
! 351: }
! 352:
! 353:
! 354: /* ARGSUSED */
! 355: static int
! 356: pre_SH(DECL_ARGS)
! 357: {
! 358:
! 359: term_vspace(p);
! 360: p->offset = 0;
! 361: p->flags |= TERMP_BOLD;
! 362: return(1);
! 363: }
! 364:
! 365:
! 366: /* ARGSUSED */
! 367: static void
! 368: post_SH(DECL_ARGS)
! 369: {
! 370:
! 371: term_flushln(p);
! 372: p->offset = INDENT;
! 373: p->flags &= ~TERMP_BOLD;
! 374: p->flags |= TERMP_NOSPACE;
! 375: }
! 376:
! 377:
! 378: static void
! 379: print_node(DECL_ARGS)
! 380: {
! 381: int c, sz;
! 382:
! 383: c = 1;
! 384:
! 385: switch (n->type) {
! 386: case(MAN_ELEM):
! 387: if (termacts[n->tok].pre)
! 388: c = (*termacts[n->tok].pre)(p, n, m);
! 389: break;
! 390: case(MAN_TEXT):
! 391: if (0 == *n->string) {
! 392: term_vspace(p);
! 393: break;
! 394: }
! 395: /*
! 396: * Note! This is hacky. Here, we recognise the `\c'
! 397: * escape embedded in so many -man pages. It's supposed
! 398: * to remove the subsequent space, so we mark NOSPACE if
! 399: * it's encountered in the string.
! 400: */
! 401: sz = (int)strlen(n->string);
! 402: term_word(p, n->string);
! 403: if (sz >= 2 && n->string[sz - 1] == 'c' &&
! 404: n->string[sz - 2] == '\\')
! 405: p->flags |= TERMP_NOSPACE;
! 406: break;
! 407: default:
! 408: break;
! 409: }
! 410:
! 411: if (c && n->child)
! 412: print_body(p, n->child, m);
! 413:
! 414: switch (n->type) {
! 415: case (MAN_ELEM):
! 416: if (termacts[n->tok].post)
! 417: (*termacts[n->tok].post)(p, n, m);
! 418: break;
! 419: default:
! 420: break;
! 421: }
! 422: }
! 423:
! 424:
! 425: static void
! 426: print_body(DECL_ARGS)
! 427: {
! 428: print_node(p, n, m);
! 429: if ( ! n->next)
! 430: return;
! 431: print_body(p, n->next, m);
! 432: }
! 433:
! 434:
! 435: static void
! 436: print_foot(struct termp *p, const struct man_meta *meta)
! 437: {
! 438: struct tm *tm;
! 439: char *buf;
! 440:
! 441: if (NULL == (buf = malloc(p->rmargin)))
! 442: err(1, "malloc");
! 443:
! 444: tm = localtime(&meta->date);
! 445:
! 446: if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
! 447: err(1, "strftime");
! 448:
! 449: term_vspace(p);
! 450:
! 451: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
! 452: p->rmargin = p->maxrmargin - strlen(buf);
! 453: p->offset = 0;
! 454:
! 455: if (meta->source)
! 456: term_word(p, meta->source);
! 457: if (meta->source)
! 458: term_word(p, "");
! 459: term_flushln(p);
! 460:
! 461: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 462: p->offset = p->rmargin;
! 463: p->rmargin = p->maxrmargin;
! 464: p->flags &= ~TERMP_NOBREAK;
! 465:
! 466: term_word(p, buf);
! 467: term_flushln(p);
! 468:
! 469: free(buf);
! 470: }
! 471:
! 472:
! 473: static void
! 474: print_head(struct termp *p, const struct man_meta *meta)
! 475: {
! 476: char *buf, *title;
! 477:
! 478: p->rmargin = p->maxrmargin;
! 479: p->offset = 0;
! 480:
! 481: if (NULL == (buf = malloc(p->rmargin)))
! 482: err(1, "malloc");
! 483: if (NULL == (title = malloc(p->rmargin)))
! 484: err(1, "malloc");
! 485:
! 486: if (meta->vol)
! 487: (void)strlcpy(buf, meta->vol, p->rmargin);
! 488: else
! 489: *buf = 0;
! 490:
! 491: (void)snprintf(title, p->rmargin, "%s(%d)",
! 492: meta->title, meta->msec);
! 493:
! 494: p->offset = 0;
! 495: p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
! 496: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
! 497:
! 498: term_word(p, title);
! 499: term_flushln(p);
! 500:
! 501: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 502: p->offset = p->rmargin;
! 503: p->rmargin = p->maxrmargin - strlen(title);
! 504:
! 505: term_word(p, buf);
! 506: term_flushln(p);
! 507:
! 508: p->offset = p->rmargin;
! 509: p->rmargin = p->maxrmargin;
! 510: p->flags &= ~TERMP_NOBREAK;
! 511: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 512:
! 513: term_word(p, title);
! 514: term_flushln(p);
! 515:
! 516: p->rmargin = p->maxrmargin;
! 517: p->offset = 0;
! 518: p->flags &= ~TERMP_NOSPACE;
! 519:
! 520: free(title);
! 521: free(buf);
! 522: }
! 523: