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