]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tbl/t4.c
fix ref822 again: remove uniqarray(), fix case with many entries in 'n'.
[plan9front.git] / sys / src / cmd / tbl / t4.c
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                                 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
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
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    *
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
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