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