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