xref: /plan9-contrib/sys/src/cmd/tbl/t4.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 /* t4.c: read table specification */
2 # include "t.h"
3 int	oncol;
4 
5 void
6 getspec(void)
7 {
8 	int	icol, i;
9 
10 	qcol = findcol() + 1;/* must allow one extra for line at right */
11 	garray(qcol);
12 	sep[-1] = -1;
13 	for (icol = 0; icol < qcol; icol++) {
14 		sep[icol] = -1;
15 		evenup[icol] = 0;
16 		cll[icol][0] = 0;
17 		for (i = 0; i < MAXHEAD; i++) {
18 			csize[icol][i][0] = 0;
19 			vsize[icol][i][0] = 0;
20 			font[icol][i][0] = lefline[icol][i] = 0;
21 			flags[icol][i] = 0;
22 			style[icol][i] = 'l';
23 		}
24 	}
25 	for (i = 0; i < MAXHEAD; i++)
26 		lefline[qcol][i] = 0;	/* fixes sample55 looping */
27 	nclin = ncol = 0;
28 	oncol = 0;
29 	left1flg = rightl = 0;
30 	readspec();
31 	Bprint(&tabout, ".rm");
32 	for (i = 0; i < ncol; i++)
33 		Bprint(&tabout, " %2s", reg(i, CRIGHT));
34 	Bprint(&tabout, "\n");
35 }
36 
37 
38 void
39 readspec(void)
40 {
41 	int	icol, c, sawchar, stopc, i;
42 	char	sn[10], *snp, *temp;
43 
44 	sawchar = icol = 0;
45 	while (c = get1char()) {
46 		switch (c) {
47 		default:
48 			if (c != tab)
49 				error("bad table specification character");
50 		case ' ': /* note this is also case tab */
51 			continue;
52 		case '\n':
53 			if (sawchar == 0)
54 				continue;
55 		case ',':
56 		case '.': /* end of table specification */
57 			ncol = max(ncol, icol);
58 			if (lefline[ncol][nclin] > 0) {
59 				ncol++;
60 				rightl++;
61 			};
62 			if (sawchar)
63 				nclin++;
64 			if (nclin >= MAXHEAD)
65 				error("too many lines in specification");
66 			icol = 0;
67 			if (ncol == 0 || nclin == 0)
68 				error("no specification");
69 			if (c == '.') {
70 				while ((c = get1char()) && c != '\n')
71 					if (c != ' ' && c != '\t')
72 						error("dot not last character on format line");
73 				/* fix up sep - default is 3 except at edge */
74 				for (icol = 0; icol < ncol; icol++)
75 					if (sep[icol] < 0)
76 						sep[icol] =  icol + 1 < ncol ? 3 : 2;
77 				if (oncol == 0)
78 					oncol = ncol;
79 				else if (oncol + 2 < ncol)
80 					error("tried to widen table in T&, not allowed");
81 				return;
82 			}
83 			sawchar = 0;
84 			continue;
85 		case 'C':
86 		case 'S':
87 		case 'R':
88 		case 'N':
89 		case 'L':
90 		case 'A':
91 			c += ('a' - 'A');
92 		case '_':
93 			if (c == '_')
94 				c = '-';
95 		case '=':
96 		case '-':
97 		case '^':
98 		case 'c':
99 		case 's':
100 		case 'n':
101 		case 'r':
102 		case 'l':
103 		case 'a':
104 			style[icol][nclin] = c;
105 			if (c == 's' && icol <= 0)
106 				error("first column can not be S-type");
107 			if (c == 's' && style[icol-1][nclin] == 'a') {
108 				Bprint(&tabout, ".tm warning: can't span a-type cols, changed to l\n");
109 				style[icol-1][nclin] = 'l';
110 			}
111 			if (c == 's' && style[icol-1][nclin] == 'n') {
112 				Bprint(&tabout, ".tm warning: can't span n-type cols, changed to c\n");
113 				style[icol-1][nclin] = 'c';
114 			}
115 			icol++;
116 			if (c == '^' && nclin <= 0)
117 				error("first row can not contain vertical span");
118 			if (icol > qcol)
119 				error("too many columns in table");
120 			sawchar = 1;
121 			continue;
122 		case 'b':
123 		case 'i':
124 			c += 'A' - 'a';
125 		case 'B':
126 		case 'I':
127 			if (icol == 0)
128 				continue;
129 			snp = font[icol-1][nclin];
130 			snp[0] = (c == 'I' ? '2' : '3');
131 			snp[1] = 0;
132 			continue;
133 		case 't':
134 		case 'T':
135 			if (icol > 0)
136 				flags[icol-1][nclin] |= CTOP;
137 			continue;
138 		case 'd':
139 		case 'D':
140 			if (icol > 0)
141 				flags[icol-1][nclin] |= CDOWN;
142 			continue;
143 		case 'f':
144 		case 'F':
145 			if (icol == 0)
146 				continue;
147 			snp = font[icol-1][nclin];
148 			snp[0] = snp[1] = stopc = 0;
149 			for (i = 0; i < 2; i++) {
150 				c = get1char();
151 				if (i == 0 && c == '(') {
152 					stopc = ')';
153 					c = get1char();
154 				}
155 				if (c == 0)
156 					break;
157 				if (c == stopc) {
158 					stopc = 0;
159 					break;
160 				}
161 				if (stopc == 0)
162 					if (c == ' ' || c == tab )
163 						break;
164 				if (c == '\n' || c == '|') {
165 					un1getc(c);
166 					break;
167 				}
168 				snp[i] = c;
169 				if (c >= '0' && c <= '9')
170 					break;
171 			}
172 			if (stopc)
173 				if (get1char() != stopc)
174 					error("Nonterminated font name");
175 			continue;
176 		case 'P':
177 		case 'p':
178 			if (icol <= 0)
179 				continue;
180 			temp = snp = csize[icol-1][nclin];
181 			while (c = get1char()) {
182 				if (c == ' ' || c == tab || c == '\n')
183 					break;
184 				if (c == '-' || c == '+')
185 					if (snp > temp)
186 						break;
187 					else
188 						*snp++ = c;
189 				else if (digit(c))
190 					*snp++ = c;
191 				else
192 					break;
193 				if (snp - temp > 4)
194 					error("point size too large");
195 			}
196 			*snp = 0;
197 			if (atoi(temp) > 36)
198 				error("point size unreasonable");
199 			un1getc (c);
200 			continue;
201 		case 'V':
202 		case 'v':
203 			if (icol <= 0)
204 				continue;
205 			temp = snp = vsize[icol-1][nclin];
206 			while (c = get1char()) {
207 				if (c == ' ' || c == tab || c == '\n')
208 					break;
209 				if (c == '-' || c == '+')
210 					if (snp > temp)
211 						break;
212 					else
213 						*snp++ = c;
214 				else if (digit(c))
215 					*snp++ = c;
216 				else
217 					break;
218 				if (snp - temp > 4)
219 					error("vertical spacing value too large");
220 			}
221 			*snp = 0;
222 			un1getc(c);
223 			continue;
224 		case 'w':
225 		case 'W':
226 			snp = cll [icol-1];
227 			/* Dale Smith didn't like this check - possible to have two text blocks
228 		   of different widths now ....
229 			if (*snp)
230 				{
231 				Bprint(&tabout, "Ignored second width specification");
232 				continue;
233 				}
234 		/* end commented out code ... */
235 			stopc = 0;
236 			while (c = get1char()) {
237 				if (snp == cll[icol-1] && c == '(') {
238 					stopc = ')';
239 					continue;
240 				}
241 				if ( !stopc && (c > '9' || c < '0'))
242 					break;
243 				if (stopc && c == stopc)
244 					break;
245 				*snp++ = c;
246 			}
247 			*snp = 0;
248 			if (snp - cll[icol-1] > CLLEN)
249 				error ("column width too long");
250 			if (!stopc)
251 				un1getc(c);
252 			continue;
253 		case 'e':
254 		case 'E':
255 			if (icol < 1)
256 				continue;
257 			evenup[icol-1] = 1;
258 			evenflg = 1;
259 			continue;
260 		case 'z':
261 		case 'Z': /* zero width-ignre width this item */
262 			if (icol < 1)
263 				continue;
264 			flags[icol-1][nclin] |= ZEROW;
265 			continue;
266 		case 'u':
267 		case 'U': /* half line up */
268 			if (icol < 1)
269 				continue;
270 			flags[icol-1][nclin] |= HALFUP;
271 			continue;
272 		case '0':
273 		case '1':
274 		case '2':
275 		case '3':
276 		case '4':
277 		case '5':
278 		case '6':
279 		case '7':
280 		case '8':
281 		case '9':
282 			sn[0] = c;
283 			snp = sn + 1;
284 			while (digit(*snp++ = c = get1char()))
285 				;
286 			un1getc(c);
287 			sep[icol-1] = max(sep[icol-1], numb(sn));
288 			continue;
289 		case '|':
290 			lefline[icol][nclin]++;
291 			if (icol == 0)
292 				left1flg = 1;
293 			continue;
294 		}
295 	}
296 	error("EOF reading table specification");
297 }
298 
299 
300 int
301 findcol(void)
302 {
303 # define FLNLIM 200
304 	/* this counts the number of columns and then puts the line back*/
305 	char	*s, line[FLNLIM+2], *p;
306 	int	c, n = 0, inpar = 0;
307 
308 	while ((c = get1char()) != 0 && c == ' ')
309 		;
310 	if (c != '\n')
311 		un1getc(c);
312 	for (s = line; *s = c = get1char(); s++) {
313 		if (c == ')')
314 			inpar = 0;
315 		if (inpar)
316 			continue;
317 		if (c == '\n' || c == 0 || c == '.' || c == ',')
318 			break;
319 		else if (c == '(')
320 			inpar = 1;
321 		else if (s >= line + FLNLIM)
322 			error("too long spec line");
323 	}
324 	for (p = line; p < s; p++)
325 		switch (*p) {
326 		case 'l':
327 		case 'r':
328 		case 'c':
329 		case 'n':
330 		case 'a':
331 		case 's':
332 		case 'L':
333 		case 'R':
334 		case 'C':
335 		case 'N':
336 		case 'A':
337 		case 'S':
338 		case '-':
339 		case '=':
340 		case '_':
341 			n++;
342 		}
343 	while (p >= line)
344 		un1getc(*p--);
345 	return(n);
346 }
347 
348 
349 void
350 garray(int qcol)
351 {
352 	style =  (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int));
353 	evenup = (int *) getcore(qcol, sizeof(int));
354 	lefline = (int (*)[]) getcore(MAXHEAD * (qcol + 1), sizeof (int)); /*+1 for sample55 loop - others may need it too*/
355 	font = (char (*)[][2]) getcore(MAXHEAD * qcol, 2);
356 	csize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4);
357 	vsize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4);
358 	flags =  (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int));
359 	cll = (char (*)[])getcore(qcol, CLLEN);
360 	sep = (int *) getcore(qcol + 1, sizeof(int));
361 	sep++; /* sep[-1] must be legal */
362 	used = (int *) getcore(qcol + 1, sizeof(int));
363 	lused = (int *) getcore(qcol + 1, sizeof(int));
364 	rused = (int *) getcore(qcol + 1, sizeof(int));
365 	doubled = (int *) getcore(qcol + 1, sizeof(int));
366 	acase = (int *) getcore(qcol + 1, sizeof(int));
367 	topat = (int *) getcore(qcol + 1, sizeof(int));
368 }
369 
370 
371 char	*
372 getcore(int a, int b)
373 {
374 	char	*x;
375 	x = calloc(a, b);
376 	if (x == 0)
377 		error("Couldn't get memory");
378 	return(x);
379 }
380 
381 
382 void
383 freearr(void)
384 {
385 	free(style);
386 	free(evenup);
387 	free(lefline);
388 	free(flags);
389 	free(font);
390 	free(csize);
391 	free(vsize);
392 	free(cll);
393 	free(--sep);	/* netnews says this should be --sep because incremented earlier! */
394 	free(used);
395 	free(lused);
396 	free(rused);
397 	free(doubled);
398 	free(acase);
399 	free(topat);
400 }
401 
402 
403