| /* t4.c: read table specification */ |
| # include "t.h" |
| int oncol; |
| |
| void |
| getspec(void) |
| { |
| int icol, i; |
| |
| qcol = findcol() + 1;/* must allow one extra for line at right */ |
| garray(qcol); |
| sep[-1] = -1; |
| for (icol = 0; icol < qcol; icol++) { |
| sep[icol] = -1; |
| evenup[icol] = 0; |
| cll[icol][0] = 0; |
| for (i = 0; i < MAXHEAD; i++) { |
| csize[icol][i][0] = 0; |
| vsize[icol][i][0] = 0; |
| font[icol][i][0] = lefline[icol][i] = 0; |
| flags[icol][i] = 0; |
| style[icol][i] = 'l'; |
| } |
| } |
| for (i = 0; i < MAXHEAD; i++) |
| lefline[qcol][i] = 0; /* fixes sample55 looping */ |
| nclin = ncol = 0; |
| oncol = 0; |
| left1flg = rightl = 0; |
| readspec(); |
| Bprint(&tabout, ".rm"); |
| for (i = 0; i < ncol; i++) |
| Bprint(&tabout, " %2s", reg(i, CRIGHT)); |
| Bprint(&tabout, "\n"); |
| } |
| |
| |
| void |
| readspec(void) |
| { |
| int icol, c, sawchar, stopc, i; |
| char sn[10], *snp, *temp; |
| |
| sawchar = icol = 0; |
| while (c = get1char()) { |
| switch (c) { |
| default: |
| if (c != tab) { |
| char buf[64]; |
| sprint(buf, "bad table specification character %c", c); |
| error(buf); |
| } |
| case ' ': /* note this is also case tab */ |
| continue; |
| case '\n': |
| if (sawchar == 0) |
| continue; |
| case ',': |
| case '.': /* end of table specification */ |
| ncol = max(ncol, icol); |
| if (lefline[ncol][nclin] > 0) { |
| ncol++; |
| rightl++; |
| }; |
| if (sawchar) |
| nclin++; |
| if (nclin >= MAXHEAD) |
| error("too many lines in specification"); |
| icol = 0; |
| if (ncol == 0 || nclin == 0) |
| error("no specification"); |
| if (c == '.') { |
| while ((c = get1char()) && c != '\n') |
| if (c != ' ' && c != '\t') |
| error("dot not last character on format line"); |
| /* fix up sep - default is 3 except at edge */ |
| for (icol = 0; icol < ncol; icol++) |
| if (sep[icol] < 0) |
| sep[icol] = icol + 1 < ncol ? 3 : 2; |
| if (oncol == 0) |
| oncol = ncol; |
| else if (oncol + 2 < ncol) |
| error("tried to widen table in T&, not allowed"); |
| return; |
| } |
| sawchar = 0; |
| continue; |
| case 'C': |
| case 'S': |
| case 'R': |
| case 'N': |
| case 'L': |
| case 'A': |
| c += ('a' - 'A'); |
| case '_': |
| if (c == '_') |
| c = '-'; |
| case '=': |
| case '-': |
| case '^': |
| case 'c': |
| case 's': |
| case 'n': |
| case 'r': |
| case 'l': |
| case 'a': |
| style[icol][nclin] = c; |
| if (c == 's' && icol <= 0) |
| error("first column can not be S-type"); |
| if (c == 's' && style[icol-1][nclin] == 'a') { |
| Bprint(&tabout, ".tm warning: can't span a-type cols, changed to l\n"); |
| style[icol-1][nclin] = 'l'; |
| } |
| if (c == 's' && style[icol-1][nclin] == 'n') { |
| Bprint(&tabout, ".tm warning: can't span n-type cols, changed to c\n"); |
| style[icol-1][nclin] = 'c'; |
| } |
| icol++; |
| if (c == '^' && nclin <= 0) |
| error("first row can not contain vertical span"); |
| if (icol > qcol) |
| error("too many columns in table"); |
| sawchar = 1; |
| continue; |
| case 'b': |
| case 'i': |
| c += 'A' - 'a'; |
| case 'B': |
| case 'I': |
| if (icol == 0) |
| continue; |
| snp = font[icol-1][nclin]; |
| snp[0] = (c == 'I' ? '2' : '3'); |
| snp[1] = 0; |
| continue; |
| case 't': |
| case 'T': |
| if (icol > 0) |
| flags[icol-1][nclin] |= CTOP; |
| continue; |
| case 'd': |
| case 'D': |
| if (icol > 0) |
| flags[icol-1][nclin] |= CDOWN; |
| continue; |
| case 'f': |
| case 'F': |
| if (icol == 0) |
| continue; |
| snp = font[icol-1][nclin]; |
| snp[0] = snp[1] = stopc = 0; |
| for (i = 0; i < 2; i++) { |
| c = get1char(); |
| if (i == 0 && c == '(') { |
| stopc = ')'; |
| c = get1char(); |
| } |
| if (c == 0) |
| break; |
| if (c == stopc) { |
| stopc = 0; |
| break; |
| } |
| if (stopc == 0) |
| if (c == ' ' || c == tab ) |
| break; |
| if (c == '\n' || c == '|') { |
| un1getc(c); |
| break; |
| } |
| snp[i] = c; |
| if (c >= '0' && c <= '9') |
| break; |
| } |
| if (stopc) |
| if (get1char() != stopc) |
| error("Nonterminated font name"); |
| continue; |
| case 'P': |
| case 'p': |
| if (icol <= 0) |
| continue; |
| temp = snp = csize[icol-1][nclin]; |
| while (c = get1char()) { |
| if (c == ' ' || c == tab || c == '\n') |
| break; |
| if (c == '-' || c == '+') |
| if (snp > temp) |
| break; |
| else |
| *snp++ = c; |
| else if (digit(c)) |
| *snp++ = c; |
| else |
| break; |
| if (snp - temp > 4) |
| error("point size too large"); |
| } |
| *snp = 0; |
| if (atoi(temp) > 36) |
| error("point size unreasonable"); |
| un1getc (c); |
| continue; |
| case 'V': |
| case 'v': |
| if (icol <= 0) |
| continue; |
| temp = snp = vsize[icol-1][nclin]; |
| while (c = get1char()) { |
| if (c == ' ' || c == tab || c == '\n') |
| break; |
| if (c == '-' || c == '+') |
| if (snp > temp) |
| break; |
| else |
| *snp++ = c; |
| else if (digit(c)) |
| *snp++ = c; |
| else |
| break; |
| if (snp - temp > 4) |
| error("vertical spacing value too large"); |
| } |
| *snp = 0; |
| un1getc(c); |
| continue; |
| case 'w': |
| case 'W': |
| snp = cll [icol-1]; |
| /* Dale Smith didn't like this check - possible to have two text blocks |
| of different widths now .... |
| if (*snp) |
| { |
| Bprint(&tabout, "Ignored second width specification"); |
| continue; |
| } |
| /* end commented out code ... */ |
| stopc = 0; |
| while (c = get1char()) { |
| if (snp == cll[icol-1] && c == '(') { |
| stopc = ')'; |
| continue; |
| } |
| if ( !stopc && (c > '9' || c < '0')) |
| break; |
| if (stopc && c == stopc) |
| break; |
| *snp++ = c; |
| } |
| *snp = 0; |
| if (snp - cll[icol-1] > CLLEN) |
| error ("column width too long"); |
| if (!stopc) |
| un1getc(c); |
| continue; |
| case 'e': |
| case 'E': |
| if (icol < 1) |
| continue; |
| evenup[icol-1] = 1; |
| evenflg = 1; |
| continue; |
| case 'z': |
| case 'Z': /* zero width-ignre width this item */ |
| if (icol < 1) |
| continue; |
| flags[icol-1][nclin] |= ZEROW; |
| continue; |
| case 'u': |
| case 'U': /* half line up */ |
| if (icol < 1) |
| continue; |
| flags[icol-1][nclin] |= HALFUP; |
| continue; |
| case '0': |
| case '1': |
| case '2': |
| case '3': |
| case '4': |
| case '5': |
| case '6': |
| case '7': |
| case '8': |
| case '9': |
| sn[0] = c; |
| snp = sn + 1; |
| while (digit(*snp++ = c = get1char())) |
| ; |
| un1getc(c); |
| sep[icol-1] = max(sep[icol-1], numb(sn)); |
| continue; |
| case '|': |
| lefline[icol][nclin]++; |
| if (icol == 0) |
| left1flg = 1; |
| continue; |
| } |
| } |
| error("EOF reading table specification"); |
| } |
| |
| |
| int |
| findcol(void) |
| { |
| # define FLNLIM 200 |
| /* this counts the number of columns and then puts the line back*/ |
| char *s, line[FLNLIM+2], *p; |
| int c, n = 0, inpar = 0; |
| |
| while ((c = get1char()) != 0 && c == ' ') |
| ; |
| if (c != '\n') |
| un1getc(c); |
| for (s = line; *s = c = get1char(); s++) { |
| if (c == ')') |
| inpar = 0; |
| if (inpar) |
| continue; |
| if (c == '\n' || c == 0 || c == '.' || c == ',') |
| break; |
| else if (c == '(') |
| inpar = 1; |
| else if (s >= line + FLNLIM) |
| error("too long spec line"); |
| } |
| for (p = line; p < s; p++) |
| switch (*p) { |
| case 'l': |
| case 'r': |
| case 'c': |
| case 'n': |
| case 'a': |
| case 's': |
| case 'L': |
| case 'R': |
| case 'C': |
| case 'N': |
| case 'A': |
| case 'S': |
| case '-': |
| case '=': |
| case '_': |
| n++; |
| } |
| while (p >= line) |
| un1getc(*p--); |
| return(n); |
| } |
| |
| |
| void |
| garray(int qcol) |
| { |
| style = (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int)); |
| evenup = (int *) getcore(qcol, sizeof(int)); |
| lefline = (int (*)[]) getcore(MAXHEAD * (qcol + 1), sizeof (int)); /*+1 for sample55 loop - others may need it too*/ |
| font = (char (*)[][2]) getcore(MAXHEAD * qcol, 2); |
| csize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4); |
| vsize = (char (*)[MAXHEAD][4]) getcore(MAXHEAD * qcol, 4); |
| flags = (int (*)[]) getcore(MAXHEAD * qcol, sizeof(int)); |
| cll = (char (*)[])getcore(qcol, CLLEN); |
| sep = (int *) getcore(qcol + 1, sizeof(int)); |
| sep++; /* sep[-1] must be legal */ |
| used = (int *) getcore(qcol + 1, sizeof(int)); |
| lused = (int *) getcore(qcol + 1, sizeof(int)); |
| rused = (int *) getcore(qcol + 1, sizeof(int)); |
| doubled = (int *) getcore(qcol + 1, sizeof(int)); |
| acase = (int *) getcore(qcol + 1, sizeof(int)); |
| topat = (int *) getcore(qcol + 1, sizeof(int)); |
| } |
| |
| |
| char * |
| getcore(int a, int b) |
| { |
| char *x; |
| x = calloc(a, b); |
| if (x == 0) |
| error("Couldn't get memory"); |
| return(x); |
| } |
| |
| |
| void |
| freearr(void) |
| { |
| free(style); |
| free(evenup); |
| free(lefline); |
| free(flags); |
| free(font); |
| free(csize); |
| free(vsize); |
| free(cll); |
| free(--sep); /* netnews says this should be --sep because incremented earlier! */ |
| free(used); |
| free(lused); |
| free(rused); |
| free(doubled); |
| free(acase); |
| free(topat); |
| } |
| |
| |