Annotation of mandoc/man_term.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: term.c,v 1.69 2009/03/23 09:42:43 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_I(DECL_ARGS);
! 39: static int pre_PP(DECL_ARGS);
! 40: static int pre_SH(DECL_ARGS);
! 41: static int pre_SS(DECL_ARGS);
! 42: static int pre_TP(DECL_ARGS);
! 43:
! 44: static void post_B(DECL_ARGS);
! 45: static void post_I(DECL_ARGS);
! 46: static void post_SH(DECL_ARGS);
! 47: static void post_SS(DECL_ARGS);
! 48:
! 49: static const struct termact termacts[MAN_MAX] = {
! 50: { NULL, NULL }, /* __ */
! 51: { NULL, NULL }, /* TH */
! 52: { pre_SH, post_SH }, /* SH */
! 53: { pre_SS, post_SS }, /* SS */
! 54: { pre_TP, NULL }, /* TP */
! 55: { pre_PP, NULL }, /* LP */
! 56: { pre_PP, NULL }, /* PP */
! 57: { pre_PP, NULL }, /* P */
! 58: { NULL, NULL }, /* IP */
! 59: { pre_PP, NULL }, /* HP */ /* XXX */
! 60: { NULL, NULL }, /* SM */
! 61: { pre_B, post_B }, /* SB */
! 62: { NULL, NULL }, /* BI */
! 63: { NULL, NULL }, /* IB */
! 64: { NULL, NULL }, /* BR */
! 65: { NULL, NULL }, /* RB */
! 66: { NULL, NULL }, /* R */
! 67: { pre_B, post_B }, /* B */
! 68: { pre_I, post_I }, /* I */
! 69: { NULL, NULL }, /* IR */
! 70: { NULL, NULL }, /* RI */
! 71: };
! 72:
! 73: static void print_head(struct termp *,
! 74: const struct man_meta *);
! 75: static void print_body(DECL_ARGS);
! 76: static void print_node(DECL_ARGS);
! 77: static void print_foot(struct termp *,
! 78: const struct man_meta *);
! 79:
! 80:
! 81: int
! 82: man_run(struct termp *p, const struct man *m)
! 83: {
! 84:
! 85: print_head(p, man_meta(m));
! 86: p->flags |= TERMP_NOSPACE;
! 87: print_body(p, man_node(m), man_meta(m));
! 88: print_foot(p, man_meta(m));
! 89:
! 90: return(1);
! 91: }
! 92:
! 93:
! 94: static int
! 95: pre_I(DECL_ARGS)
! 96: {
! 97:
! 98: p->flags |= TERMP_UNDER;
! 99: return(1);
! 100: }
! 101:
! 102:
! 103: static void
! 104: post_I(DECL_ARGS)
! 105: {
! 106:
! 107: p->flags &= ~TERMP_UNDER;
! 108: }
! 109:
! 110:
! 111: static int
! 112: pre_B(DECL_ARGS)
! 113: {
! 114:
! 115: p->flags |= TERMP_BOLD;
! 116: return(1);
! 117: }
! 118:
! 119:
! 120: static void
! 121: post_B(DECL_ARGS)
! 122: {
! 123:
! 124: p->flags &= ~TERMP_BOLD;
! 125: }
! 126:
! 127:
! 128: static int
! 129: pre_PP(DECL_ARGS)
! 130: {
! 131:
! 132: term_vspace(p);
! 133: p->offset = INDENT;
! 134: return(0);
! 135: }
! 136:
! 137:
! 138: static int
! 139: pre_TP(DECL_ARGS)
! 140: {
! 141: const struct man_node *nn;
! 142: size_t offs;
! 143:
! 144: term_vspace(p);
! 145: p->offset = INDENT;
! 146:
! 147: if (NULL == (nn = n->child))
! 148: return(1);
! 149:
! 150: if (nn->line == n->line) {
! 151: if (MAN_TEXT != nn->type)
! 152: errx(1, "expected text line argument");
! 153: offs = atoi(nn->string);
! 154: nn = nn->next;
! 155: } else
! 156: offs = INDENT;
! 157:
! 158: for ( ; nn; nn = nn->next)
! 159: print_node(p, nn, m);
! 160:
! 161: term_flushln(p);
! 162: p->flags |= TERMP_NOSPACE;
! 163: p->offset += offs;
! 164: return(0);
! 165: }
! 166:
! 167:
! 168: static int
! 169: pre_SS(DECL_ARGS)
! 170: {
! 171:
! 172: term_vspace(p);
! 173: p->flags |= TERMP_BOLD;
! 174: return(1);
! 175: }
! 176:
! 177:
! 178: static void
! 179: post_SS(DECL_ARGS)
! 180: {
! 181:
! 182: term_flushln(p);
! 183: p->flags &= ~TERMP_BOLD;
! 184: p->flags |= TERMP_NOSPACE;
! 185: }
! 186:
! 187:
! 188: static int
! 189: pre_SH(DECL_ARGS)
! 190: {
! 191:
! 192: term_vspace(p);
! 193: p->offset = 0;
! 194: p->flags |= TERMP_BOLD;
! 195: return(1);
! 196: }
! 197:
! 198:
! 199: static void
! 200: post_SH(DECL_ARGS)
! 201: {
! 202:
! 203: term_flushln(p);
! 204: p->offset = INDENT;
! 205: p->flags &= ~TERMP_BOLD;
! 206: p->flags |= TERMP_NOSPACE;
! 207: }
! 208:
! 209:
! 210: static void
! 211: print_node(DECL_ARGS)
! 212: {
! 213: int c;
! 214:
! 215: c = 1;
! 216:
! 217: switch (n->type) {
! 218: case(MAN_ELEM):
! 219: if (termacts[n->tok].pre)
! 220: c = (*termacts[n->tok].pre)(p, n, m);
! 221: break;
! 222: case(MAN_TEXT):
! 223: if (*n->string) {
! 224: term_word(p, n->string);
! 225: break;
! 226: }
! 227: term_vspace(p);
! 228: break;
! 229: default:
! 230: break;
! 231: }
! 232:
! 233: if (c && n->child)
! 234: print_body(p, n->child, m);
! 235:
! 236: switch (n->type) {
! 237: case (MAN_ELEM):
! 238: if (termacts[n->tok].post)
! 239: (*termacts[n->tok].post)(p, n, m);
! 240: break;
! 241: default:
! 242: break;
! 243: }
! 244: }
! 245:
! 246:
! 247: static void
! 248: print_body(DECL_ARGS)
! 249: {
! 250: print_node(p, n, m);
! 251: if ( ! n->next)
! 252: return;
! 253: print_body(p, n->next, m);
! 254: }
! 255:
! 256:
! 257: static void
! 258: print_foot(struct termp *p, const struct man_meta *meta)
! 259: {
! 260: struct tm *tm;
! 261: char *buf;
! 262:
! 263: if (NULL == (buf = malloc(p->rmargin)))
! 264: err(1, "malloc");
! 265:
! 266: tm = localtime(&meta->date);
! 267:
! 268: #ifdef __OpenBSD__
! 269: if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
! 270: #else
! 271: if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
! 272: #endif
! 273: err(1, "strftime");
! 274:
! 275: /*
! 276: * This is /slightly/ different from regular groff output
! 277: * because we don't have page numbers. Print the following:
! 278: *
! 279: * OS MDOCDATE
! 280: */
! 281:
! 282: term_vspace(p);
! 283:
! 284: p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
! 285: p->rmargin = p->maxrmargin - strlen(buf);
! 286: p->offset = 0;
! 287:
! 288: if (meta->source)
! 289: term_word(p, meta->source);
! 290: if (meta->source)
! 291: term_word(p, "");
! 292: term_flushln(p);
! 293:
! 294: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 295: p->offset = p->rmargin;
! 296: p->rmargin = p->maxrmargin;
! 297: p->flags &= ~TERMP_NOBREAK;
! 298:
! 299: term_word(p, buf);
! 300: term_flushln(p);
! 301:
! 302: free(buf);
! 303: }
! 304:
! 305:
! 306: static void
! 307: print_head(struct termp *p, const struct man_meta *meta)
! 308: {
! 309: char *buf, *title;
! 310:
! 311: p->rmargin = p->maxrmargin;
! 312: p->offset = 0;
! 313:
! 314: if (NULL == (buf = malloc(p->rmargin)))
! 315: err(1, "malloc");
! 316: if (NULL == (title = malloc(p->rmargin)))
! 317: err(1, "malloc");
! 318:
! 319: /*
! 320: * The header is strange. It has three components, which are
! 321: * really two with the first duplicated. It goes like this:
! 322: *
! 323: * IDENTIFIER TITLE IDENTIFIER
! 324: *
! 325: * The IDENTIFIER is NAME(SECTION), which is the command-name
! 326: * (if given, or "unknown" if not) followed by the manual page
! 327: * section. These are given in `Dt'. The TITLE is a free-form
! 328: * string depending on the manual volume. If not specified, it
! 329: * switches on the manual section.
! 330: */
! 331:
! 332: if (meta->vol)
! 333: (void)strlcpy(buf, meta->vol, p->rmargin);
! 334: else
! 335: *buf = 0;
! 336:
! 337: (void)snprintf(title, p->rmargin, "%s(%d)",
! 338: meta->title, meta->msec);
! 339:
! 340: p->offset = 0;
! 341: p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
! 342: p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
! 343:
! 344: term_word(p, title);
! 345: term_flushln(p);
! 346:
! 347: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 348: p->offset = p->rmargin;
! 349: p->rmargin = p->maxrmargin - strlen(title);
! 350:
! 351: term_word(p, buf);
! 352: term_flushln(p);
! 353:
! 354: p->offset = p->rmargin;
! 355: p->rmargin = p->maxrmargin;
! 356: p->flags &= ~TERMP_NOBREAK;
! 357: p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
! 358:
! 359: term_word(p, title);
! 360: term_flushln(p);
! 361:
! 362: p->rmargin = p->maxrmargin;
! 363: p->offset = 0;
! 364: p->flags &= ~TERMP_NOSPACE;
! 365:
! 366: free(title);
! 367: free(buf);
! 368: }
! 369:
CVSweb