Annotation of mandoc/tbl_term.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: term.c,v 1.13 2009/09/14 09:06:40 kristaps Exp $ */
! 2: /*
! 3: * Copyright (c) 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: #ifdef HAVE_CONFIG_H
! 18: #include "config.h"
! 19: #endif
! 20:
! 21: #include <assert.h>
! 22: #include <stdio.h>
! 23: #include <stdlib.h>
! 24: #include <string.h>
! 25:
! 26: #include "mandoc.h"
! 27: #include "out.h"
! 28: #include "term.h"
! 29:
! 30: /* FIXME: `n' modifier doesn't always do the right thing. */
! 31: /* FIXME: `n' modifier doesn't use the cell-spacing buffer. */
! 32:
! 33: static inline void tbl_char(struct termp *, char, int);
! 34: static void tbl_hframe(struct termp *,
! 35: const struct tbl_span *);
! 36: static void tbl_data_number(struct termp *,
! 37: const struct tbl *,
! 38: const struct tbl_dat *, int);
! 39: static void tbl_data_literal(struct termp *,
! 40: const struct tbl_dat *, int);
! 41: static void tbl_data_spanner(struct termp *,
! 42: const struct tbl_dat *, int);
! 43: static void tbl_data(struct termp *, const struct tbl *,
! 44: const struct tbl_dat *, int);
! 45: static void tbl_spanner(struct termp *,
! 46: const struct tbl_head *);
! 47: static void tbl_hrule(struct termp *,
! 48: const struct tbl_span *);
! 49: static void tbl_vframe(struct termp *, const struct tbl *);
! 50:
! 51: void
! 52: term_tbl(struct termp *tp, const struct tbl_span *sp)
! 53: {
! 54: const struct tbl_head *hp;
! 55: const struct tbl_dat *dp;
! 56:
! 57: if (TBL_SPAN_FIRST & sp->flags)
! 58: term_flushln(tp);
! 59:
! 60: if (TBL_SPAN_FIRST & sp->flags)
! 61: tbl_hframe(tp, sp);
! 62:
! 63: tp->flags |= TERMP_NONOSPACE;
! 64: tp->flags |= TERMP_NOSPACE;
! 65:
! 66: tbl_vframe(tp, sp->tbl);
! 67:
! 68: switch (sp->pos) {
! 69: case (TBL_SPAN_HORIZ):
! 70: /* FALLTHROUGH */
! 71: case (TBL_SPAN_DHORIZ):
! 72: tbl_hrule(tp, sp);
! 73: tbl_vframe(tp, sp->tbl);
! 74: term_newln(tp);
! 75: tp->flags &= ~TERMP_NONOSPACE;
! 76: return;
! 77: default:
! 78: break;
! 79: }
! 80:
! 81: dp = sp->first;
! 82: for (hp = sp->head; hp; hp = hp->next) {
! 83: switch (hp->pos) {
! 84: case (TBL_HEAD_VERT):
! 85: /* FALLTHROUGH */
! 86: case (TBL_HEAD_DVERT):
! 87: tbl_spanner(tp, hp);
! 88: break;
! 89: case (TBL_HEAD_DATA):
! 90: tbl_data(tp, sp->tbl, dp, hp->width);
! 91: if (dp)
! 92: dp = dp->next;
! 93: break;
! 94: default:
! 95: abort();
! 96: /* NOTREACHED */
! 97: }
! 98: }
! 99:
! 100: tbl_vframe(tp, sp->tbl);
! 101: term_flushln(tp);
! 102:
! 103: if (TBL_SPAN_LAST & sp->flags)
! 104: tbl_hframe(tp, sp);
! 105:
! 106: tp->flags &= ~TERMP_NONOSPACE;
! 107:
! 108: }
! 109:
! 110: static void
! 111: tbl_hrule(struct termp *tp, const struct tbl_span *sp)
! 112: {
! 113: const struct tbl_head *hp;
! 114: char c;
! 115:
! 116: /*
! 117: * An hrule extends across the entire table and is demarked by a
! 118: * standalone `_' or whatnot in lieu of a table row. Spanning
! 119: * headers are marked by a `+', as are table boundaries.
! 120: */
! 121:
! 122: c = '-';
! 123: if (TBL_SPAN_DHORIZ == sp->pos)
! 124: c = '=';
! 125:
! 126: /* FIXME: don't use `+' between data and a spanner! */
! 127:
! 128: for (hp = sp->head; hp; hp = hp->next) {
! 129: switch (hp->pos) {
! 130: case (TBL_HEAD_DATA):
! 131: tbl_char(tp, c, hp->width);
! 132: break;
! 133: case (TBL_HEAD_DVERT):
! 134: tbl_char(tp, '+', hp->width);
! 135: /* FALLTHROUGH */
! 136: case (TBL_HEAD_VERT):
! 137: tbl_char(tp, '+', hp->width);
! 138: break;
! 139: default:
! 140: abort();
! 141: /* NOTREACHED */
! 142: }
! 143: }
! 144: }
! 145:
! 146: static void
! 147: tbl_hframe(struct termp *tp, const struct tbl_span *sp)
! 148: {
! 149: const struct tbl_head *hp;
! 150:
! 151: if ( ! (TBL_OPT_BOX & sp->tbl->opts ||
! 152: TBL_OPT_DBOX & sp->tbl->opts))
! 153: return;
! 154:
! 155: tp->flags |= TERMP_NONOSPACE;
! 156: tp->flags |= TERMP_NOSPACE;
! 157:
! 158: /*
! 159: * Print out the horizontal part of a frame or double frame. A
! 160: * double frame has an unbroken `-' outer line the width of the
! 161: * table, bordered by `+'. The frame (or inner frame, in the
! 162: * case of the double frame) is a `-' bordered by `+' and broken
! 163: * by `+' whenever a span is encountered.
! 164: */
! 165:
! 166: if (TBL_OPT_DBOX & sp->tbl->opts) {
! 167: term_word(tp, "+");
! 168: for (hp = sp->head; hp; hp = hp->next)
! 169: tbl_char(tp, '-', hp->width);
! 170: term_word(tp, "+");
! 171: term_flushln(tp);
! 172: }
! 173:
! 174: term_word(tp, "+");
! 175: for (hp = sp->head; hp; hp = hp->next) {
! 176: switch (hp->pos) {
! 177: case (TBL_HEAD_DATA):
! 178: tbl_char(tp, '-', hp->width);
! 179: break;
! 180: default:
! 181: tbl_char(tp, '+', hp->width);
! 182: break;
! 183: }
! 184: }
! 185: term_word(tp, "+");
! 186: term_flushln(tp);
! 187: }
! 188:
! 189: static void
! 190: tbl_data(struct termp *tp, const struct tbl *tbl,
! 191: const struct tbl_dat *dp, int width)
! 192: {
! 193: enum tbl_cellt pos;
! 194:
! 195: if (NULL == dp) {
! 196: tbl_char(tp, ASCII_NBRSP, width);
! 197: return;
! 198: }
! 199:
! 200: switch (dp->pos) {
! 201: case (TBL_DATA_HORIZ):
! 202: /* FALLTHROUGH */
! 203: case (TBL_DATA_DHORIZ):
! 204: tbl_data_spanner(tp, dp, width);
! 205: return;
! 206: default:
! 207: break;
! 208: }
! 209:
! 210: pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
! 211:
! 212: switch (pos) {
! 213: case (TBL_CELL_HORIZ):
! 214: /* FALLTHROUGH */
! 215: case (TBL_CELL_DHORIZ):
! 216: tbl_data_spanner(tp, dp, width);
! 217: break;
! 218: case (TBL_CELL_LONG):
! 219: /* FALLTHROUGH */
! 220: case (TBL_CELL_CENTRE):
! 221: /* FALLTHROUGH */
! 222: case (TBL_CELL_LEFT):
! 223: /* FALLTHROUGH */
! 224: case (TBL_CELL_RIGHT):
! 225: tbl_data_literal(tp, dp, width);
! 226: break;
! 227: case (TBL_CELL_NUMBER):
! 228: tbl_data_number(tp, tbl, dp, width);
! 229: break;
! 230: default:
! 231: abort();
! 232: /* NOTREACHED */
! 233: }
! 234: }
! 235: static void
! 236: tbl_spanner(struct termp *tp, const struct tbl_head *hp)
! 237: {
! 238:
! 239: switch (hp->pos) {
! 240: case (TBL_HEAD_VERT):
! 241: term_word(tp, "|");
! 242: break;
! 243: case (TBL_HEAD_DVERT):
! 244: term_word(tp, "||");
! 245: break;
! 246: default:
! 247: break;
! 248: }
! 249: }
! 250:
! 251: static void
! 252: tbl_vframe(struct termp *tp, const struct tbl *tbl)
! 253: {
! 254: /* Always just a single vertical line. */
! 255:
! 256: if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)
! 257: term_word(tp, "|");
! 258: }
! 259:
! 260:
! 261: static inline void
! 262: tbl_char(struct termp *tp, char c, int len)
! 263: {
! 264: int i;
! 265: char cp[2];
! 266:
! 267: cp[0] = c;
! 268: cp[1] = '\0';
! 269:
! 270: for (i = 0; i < len; i++)
! 271: term_word(tp, cp);
! 272: }
! 273:
! 274: static void
! 275: tbl_data_spanner(struct termp *tp, const struct tbl_dat *dp, int width)
! 276: {
! 277:
! 278: switch (dp->pos) {
! 279: case (TBL_DATA_HORIZ):
! 280: case (TBL_DATA_NHORIZ):
! 281: tbl_char(tp, '-', width);
! 282: break;
! 283: case (TBL_DATA_DHORIZ):
! 284: case (TBL_DATA_NDHORIZ):
! 285: tbl_char(tp, '=', width);
! 286: break;
! 287: default:
! 288: break;
! 289: }
! 290: }
! 291:
! 292: static void
! 293: tbl_data_literal(struct termp *tp, const struct tbl_dat *dp, int width)
! 294: {
! 295: int padl, padr;
! 296: enum tbl_cellt pos;
! 297:
! 298: padl = padr = 0;
! 299:
! 300: pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT;
! 301:
! 302: switch (pos) {
! 303: case (TBL_CELL_LONG):
! 304: padl = 1;
! 305: padr = width - (int)strlen(dp->string) - 1;
! 306: break;
! 307: case (TBL_CELL_CENTRE):
! 308: padl = width - (int)strlen(dp->string);
! 309: if (padl % 2)
! 310: padr++;
! 311: padl /= 2;
! 312: padr += padl;
! 313: break;
! 314: case (TBL_CELL_RIGHT):
! 315: padl = width - (int)strlen(dp->string);
! 316: break;
! 317: default:
! 318: padr = width - (int)strlen(dp->string);
! 319: break;
! 320: }
! 321:
! 322: tbl_char(tp, ASCII_NBRSP, padl);
! 323: term_word(tp, dp->string);
! 324: tbl_char(tp, ASCII_NBRSP, padr);
! 325: }
! 326:
! 327: static void
! 328: tbl_data_number(struct termp *tp, const struct tbl *tbl,
! 329: const struct tbl_dat *dp, int width)
! 330: {
! 331: char *decp, pnt;
! 332: int d, padl, sz;
! 333:
! 334: /*
! 335: * See calc_data_number(). Left-pad by taking the offset of our
! 336: * and the maximum decimal; right-pad by the remaining amount.
! 337: */
! 338:
! 339: sz = (int)strlen(dp->string);
! 340: pnt = tbl->decimal;
! 341:
! 342: if (NULL == (decp = strchr(dp->string, pnt))) {
! 343: d = sz + 1;
! 344: } else {
! 345: d = (int)(decp - dp->string) + 1;
! 346: }
! 347:
! 348: assert(d <= dp->layout->head->decimal);
! 349: assert(sz - d <= dp->layout->head->width -
! 350: dp->layout->head->decimal);
! 351:
! 352: padl = dp->layout->head->decimal - d + 1;
! 353: assert(width - sz - padl);
! 354:
! 355: tbl_char(tp, ASCII_NBRSP, padl);
! 356: term_word(tp, dp->string);
! 357: tbl_char(tp, ASCII_NBRSP, width - sz - padl);
! 358: }
CVSweb