/*	@(#)t4.c	2.1		*/
 /* t4.c: read table specification */
# include "t..c"
int oncol;
getspec()
{
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';
		}
	}
nclin=ncol=0;
oncol =0;
left1flg=rightl=0;
readspec();
fprintf(tabout, ".rm");
for(i=0; i<ncol; i++)
	fprintf(tabout, " %2s", reg(i, CRIGHT));
fprintf(tabout, "\n");
}
readspec()
{
int icol, c, sawchar, stopc, i;
char sn[10], *snp, *temp;
sawchar=icol=0;
while (c=get1char())
	{
	switch(c)
		{
		default:
			if (c != tab)
			error("bad table specification character");
		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')
				{
				fprintf(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')
				{
				fprintf(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'){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)
				{
				fprintf(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");
}
findcol()
{
# 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())!=EOF && c == ' ')
	;
if (c!='\n')
	un1getc(c);
for(s=line; *s = c = get1char(); s++)
	{
	if (c==')') inpar=0;
	if (inpar) continue;
	if (c=='\n' || c == EOF || 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 (c= *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);
}
garray(qcol)
{
char * getcore();
style =  (int (*)[]) getcore(MAXHEAD*qcol, sizeof(int));
evenup = (int *) getcore(qcol, sizeof(int));
lefline = (int (*)[]) getcore(MAXHEAD*qcol, sizeof (int));
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, sizeof(int));
lused = (int *) getcore(qcol, sizeof(int));
rused = (int *) getcore(qcol, sizeof(int));
doubled = (int *) getcore(qcol, sizeof(int));
acase = (int *) getcore(qcol, sizeof(int));
topat = (int *) getcore(qcol, sizeof(int));
}
char *
getcore(a,b)
{
char *x, *calloc();
x = calloc(a,b);
if (x==0) 
	error("Couldn't get memory");
return(x);
}
freearr()
{
cfree(style);
cfree(evenup);
cfree(lefline);
cfree(flags);
cfree(font);
cfree(csize);
cfree(vsize);
cfree(cll);
cfree(sep);
cfree(used);
cfree(lused);
cfree(rused);
cfree(doubled);
cfree(acase);
cfree(topat);
}
