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