Annotation of mandoc/tbl_layout.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: layout.c,v 1.7 2009/09/11 13:24:04 kristaps Exp $ */
! 2: /*
! 3: * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
! 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: #include <assert.h>
! 18: #include <ctype.h>
! 19: #include <stdlib.h>
! 20: #include <string.h>
! 21:
! 22: #include "mandoc.h"
! 23: #include "libmandoc.h"
! 24: #include "libroff.h"
! 25:
! 26: struct tbl_phrase {
! 27: char name;
! 28: enum tbl_cellt key;
! 29: };
! 30:
! 31: #define KEYS_MAX 17
! 32:
! 33: static const struct tbl_phrase keys[KEYS_MAX] = {
! 34: { 'c', TBL_CELL_CENTRE },
! 35: { 'C', TBL_CELL_CENTRE },
! 36: { 'r', TBL_CELL_RIGHT },
! 37: { 'R', TBL_CELL_RIGHT },
! 38: { 'l', TBL_CELL_LEFT },
! 39: { 'L', TBL_CELL_LEFT },
! 40: { 'n', TBL_CELL_NUMBER },
! 41: { 'N', TBL_CELL_NUMBER },
! 42: { 's', TBL_CELL_SPAN },
! 43: { 'S', TBL_CELL_SPAN },
! 44: { 'a', TBL_CELL_LONG },
! 45: { 'A', TBL_CELL_LONG },
! 46: { '^', TBL_CELL_DOWN },
! 47: { '-', TBL_CELL_HORIZ },
! 48: { '_', TBL_CELL_HORIZ },
! 49: { '=', TBL_CELL_DHORIZ },
! 50: { '|', TBL_CELL_VERT }
! 51: };
! 52:
! 53: static int mods(struct tbl *, struct tbl_cell *,
! 54: int, const char *, int *);
! 55: static int cell(struct tbl *, struct tbl_row *,
! 56: int, const char *, int *);
! 57: static void row(struct tbl *, int, const char *, int *);
! 58:
! 59: static int
! 60: mods(struct tbl *tbl, struct tbl_cell *cp,
! 61: int ln, const char *p, int *pos)
! 62: {
! 63: char buf[5];
! 64: int i;
! 65:
! 66: mod:
! 67: /*
! 68: * XXX: since, at least for now, modifiers are non-conflicting
! 69: * (are separable by value, regardless of position), we let
! 70: * modifiers come in any order. The existing tbl doesn't let
! 71: * this happen.
! 72: */
! 73: switch (p[*pos]) {
! 74: case ('\0'):
! 75: /* FALLTHROUGH */
! 76: case (' '):
! 77: /* FALLTHROUGH */
! 78: case ('\t'):
! 79: /* FALLTHROUGH */
! 80: case (','):
! 81: /* FALLTHROUGH */
! 82: case ('.'):
! 83: return(1);
! 84: default:
! 85: break;
! 86: }
! 87:
! 88: /* Parse numerical spacing from modifier string. */
! 89:
! 90: if (isdigit((unsigned char)p[*pos])) {
! 91: for (i = 0; i < 4; i++) {
! 92: if ( ! isdigit((unsigned char)p[*pos + i]))
! 93: break;
! 94: buf[i] = p[*pos + i];
! 95: }
! 96: buf[i] = '\0';
! 97:
! 98: /* No greater than 4 digits. */
! 99:
! 100: if (4 == i) {
! 101: TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos);
! 102: return(0);
! 103: }
! 104:
! 105: *pos += i;
! 106: cp->spacing = atoi(buf);
! 107:
! 108: goto mod;
! 109: /* NOTREACHED */
! 110: }
! 111:
! 112: /* TODO: GNU has many more extensions. */
! 113:
! 114: switch (p[(*pos)++]) {
! 115: case ('z'):
! 116: /* FALLTHROUGH */
! 117: case ('Z'):
! 118: cp->flags |= TBL_CELL_WIGN;
! 119: goto mod;
! 120: case ('u'):
! 121: /* FALLTHROUGH */
! 122: case ('U'):
! 123: cp->flags |= TBL_CELL_UP;
! 124: goto mod;
! 125: case ('e'):
! 126: /* FALLTHROUGH */
! 127: case ('E'):
! 128: cp->flags |= TBL_CELL_EQUAL;
! 129: goto mod;
! 130: case ('t'):
! 131: /* FALLTHROUGH */
! 132: case ('T'):
! 133: cp->flags |= TBL_CELL_TALIGN;
! 134: goto mod;
! 135: case ('d'):
! 136: /* FALLTHROUGH */
! 137: case ('D'):
! 138: cp->flags |= TBL_CELL_BALIGN;
! 139: goto mod;
! 140: case ('f'):
! 141: /* FALLTHROUGH */
! 142: case ('B'):
! 143: /* FALLTHROUGH */
! 144: case ('I'):
! 145: /* FALLTHROUGH */
! 146: case ('b'):
! 147: /* FALLTHROUGH */
! 148: case ('i'):
! 149: break;
! 150: default:
! 151: TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1);
! 152: return(0);
! 153: }
! 154:
! 155: switch (p[(*pos)++]) {
! 156: case ('b'):
! 157: /* FALLTHROUGH */
! 158: case ('B'):
! 159: cp->flags |= TBL_CELL_BOLD;
! 160: goto mod;
! 161: case ('i'):
! 162: /* FALLTHROUGH */
! 163: case ('I'):
! 164: cp->flags |= TBL_CELL_ITALIC;
! 165: goto mod;
! 166: default:
! 167: break;
! 168: }
! 169:
! 170: TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1);
! 171: return(0);
! 172: }
! 173:
! 174: static int
! 175: cell(struct tbl *tbl, struct tbl_row *rp,
! 176: int ln, const char *p, int *pos)
! 177: {
! 178: struct tbl_cell *cp;
! 179: int i;
! 180: enum tbl_cellt c;
! 181:
! 182: /* Parse the column position (`r', `R', `|', ...). */
! 183:
! 184: for (i = 0; i < KEYS_MAX; i++)
! 185: if (p[*pos] == keys[i].name)
! 186: break;
! 187:
! 188: if (KEYS_MAX == i) {
! 189: TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos);
! 190: return(0);
! 191: }
! 192:
! 193: (*pos)++;
! 194: c = keys[i].key;
! 195:
! 196: /* Extra check for the double-vertical. */
! 197:
! 198: if (TBL_CELL_VERT == c && '|' == p[*pos]) {
! 199: (*pos)++;
! 200: c = TBL_CELL_DVERT;
! 201: }
! 202:
! 203: /* Disallow adjacent spacers. */
! 204:
! 205: if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) &&
! 206: (TBL_CELL_VERT == rp->last->pos ||
! 207: TBL_CELL_DVERT == rp->last->pos)) {
! 208: TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1);
! 209: return(0);
! 210: }
! 211:
! 212: /* Allocate cell then parse its modifiers. */
! 213:
! 214: cp = mandoc_calloc(1, sizeof(struct tbl_cell));
! 215: cp->pos = c;
! 216:
! 217: if (rp->last) {
! 218: rp->last->next = cp;
! 219: rp->last = cp;
! 220: } else
! 221: rp->last = rp->first = cp;
! 222:
! 223: return(mods(tbl, cp, ln, p, pos));
! 224: }
! 225:
! 226:
! 227: static void
! 228: row(struct tbl *tbl, int ln, const char *p, int *pos)
! 229: {
! 230: struct tbl_row *rp;
! 231:
! 232: row: /*
! 233: * EBNF describing this section:
! 234: *
! 235: * row ::= row_list [:space:]* [.]?[\n]
! 236: * row_list ::= [:space:]* row_elem row_tail
! 237: * row_tail ::= [:space:]*[,] row_list |
! 238: * epsilon
! 239: * row_elem ::= [\t\ ]*[:alpha:]+
! 240: */
! 241:
! 242: rp = mandoc_calloc(1, sizeof(struct tbl_row));
! 243: if (tbl->last) {
! 244: tbl->last->next = rp;
! 245: tbl->last = rp;
! 246: } else
! 247: tbl->last = tbl->first = rp;
! 248:
! 249: cell:
! 250: while (isspace((unsigned char)p[*pos]))
! 251: (*pos)++;
! 252:
! 253: /* Safely exit layout context. */
! 254:
! 255: if ('.' == p[*pos]) {
! 256: tbl->part = TBL_PART_DATA;
! 257: if (NULL == tbl->first)
! 258: TBL_MSG(tbl, MANDOCERR_TBLNOLAYOUT, ln, *pos);
! 259: (*pos)++;
! 260: return;
! 261: }
! 262:
! 263: /* End (and possibly restart) a row. */
! 264:
! 265: if (',' == p[*pos]) {
! 266: (*pos)++;
! 267: goto row;
! 268: } else if ('\0' == p[*pos])
! 269: return;
! 270:
! 271: if ( ! cell(tbl, rp, ln, p, pos))
! 272: return;
! 273:
! 274: goto cell;
! 275: /* NOTREACHED */
! 276: }
! 277:
! 278:
! 279: int
! 280: tbl_layout(struct tbl *tbl, int ln, const char *p)
! 281: {
! 282: int pos;
! 283:
! 284: pos = 0;
! 285: row(tbl, ln, p, &pos);
! 286:
! 287: /* Always succeed. */
! 288: return(1);
! 289: }
CVSweb