static char rcsid[] = "$Header:struct.c 12.0$";
#include "defs"

offsets(s)
register ptr s;
{
register ptr p, q;
ptr t;
ptr prevp;
int n;
int size, align, mask, nelt;
double rshift;

((struct typeblock *)s)->stralign = 1;
((struct typeblock *)s)->strsize = 0;
((struct typeblock *)s)->basetypes = 0;
prevp = 0;
rshift = 0;

for(p = ((struct typeblock *)s)->strdesc ; p ; p = ((struct dimblock *)p)->nextp)
	{
	q = ((struct chain *)p)->datap;
	if(((struct varblock *)q)->vclass != 0)
		dclerr("attempt to give storage class to mos",
			((struct stentry *)q)->namep);
	else  ((struct varblock *)q)->vclass = CLMOS;
	if(((struct varblock *)q)->vtype == TYUNDEFINED)
		impldecl(q);

	sizalign(q, &size, &align, &mask);
	((struct typeblock *)s)->strsize = evenoff(((struct typeblock *)s)->strsize, align);
	((struct exprblock *)q)->voffset = mkint(((struct typeblock *)s)->strsize);
	/* sloppy formula */
	nelt = 1;
	if(t = ((struct varblock *)q)->vdim)
	    for(t = ((struct chain *)t)->datap ; t ; t = ((struct dimblock *)t)->nextp)
		{
		if(((struct dimblock *)t)->upperb == 0) continue;
		n = conval(((struct dimblock *)t)->upperb);
		if(((struct dimblock *)t)->lowerb)
			n -= conval(((struct dimblock *)t)->lowerb)-1;
		nelt *= n;
		}
	if(((struct varblock *)q)->vtype==TYFIELD && ((struct varblock *)q)->vdim==0 &&
	     (n=conval(((struct fieldspec *)((struct varblock *)q)->vtypep)->frange))*rshift<=fieldmax && rshift>0)
		{
		((struct fieldspec *)((struct varblock *)prevp)->vtypep)->fanymore = 1;
		((struct fieldspec *)((struct varblock *)q)->vtypep)->frshift = mkint( (int) rshift );
		rshift *= n;
		cfree(((struct exprblock *)q)->voffset);
		((struct exprblock *)q)->voffset = mkint(((struct typeblock *)s)->strsize - tailor.ftnsize[FTNINT]);
		}
	else	{
		if(((struct varblock *)q)->vdim!=0 && ((struct varblock *)q)->vtype==TYFIELD)
			((struct varblock *)q)->vtype = TYINT;
		rshift = (((struct varblock *)q)->vtype==TYFIELD ? n : 0);
		((struct typeblock *)s)->strsize +=  nelt * evenoff(size,align);
		((struct typeblock *)s)->stralign = lcm(((struct typeblock *)s)->stralign, align);
		((struct typeblock *)s)->basetypes |= mask;
		}
	prevp = q;
	}
}


lcm(a,b)
int a,b;
{
int ab, c;

if( (ab = a*b) == 0) return(0);

while(b)
	{
	c = a%b;
	a = b;
	b = c;
	}

return(ab/a);
}





sizalign(p, s, a, m)
register ptr p;
int *s;
int *a;
int *m;
{
register int k, t;

if(((struct headbits *)p)->tag == TERROR)
	return;
if(((struct headbits *)p)->tag!=TNAME && ((struct headbits *)p)->tag!=TTEMP && ((struct headbits *)p)->tag!=TFTNBLOCK)
	badtag("sizalign", ((struct headbits *)p)->tag);
switch(t = ((struct varblock *)p)->vtype)
	{
	case TYFIELD:
	case TYINT:
	case TYREAL:
	case TYLREAL:
	case TYCOMPLEX:
	case TYLOG:
		k = eflftn[t];
		*s = tailor.ftnsize[k];
		*a = tailor.ftnalign[k];
		*m = ftnmask[k];
		return;

	case TYLCOMPLEX:
		if(tailor.lngcxtype)
			{
			k = FTNDCOMPLEX;
			*s = tailor.ftnsize[FTNDCOMPLEX];
			}
		else
			{
			k = FTNDOUBLE;
			*s = 2*tailor.ftnsize[k];
			}
		*a = tailor.ftnalign[k];
		*m = ftnmask[k];
		return;

	case TYSTRUCT:
		*s = ((struct typeblock *)((struct varblock *)p)->vtypep)->strsize;
		*a = ((struct typeblock *)((struct varblock *)p)->vtypep)->stralign;
		*m = ((struct typeblock *)((struct varblock *)p)->vtypep)->basetypes;
		return;

	case TYCHAR:
		*s = tailor.ftnsize[FTNINT] *
			ceil(conval(((struct varblock *)p)->vtypep), tailor.ftnchwd);
		*a = tailor.ftnalign[FTNINT];
		*m = ftnmask[FTNINT];
		return;

	case TYSUBR:
		*s = 1;
		*a = 1;
		*m = 1;
		dclerr("subroutine name as variable", ((struct stentry *)((struct varblock *)p)->sthead)->namep);
		return;

	default:
		fatal1("sizalign: invalid type %d", t);
	}
}



evenoff(a,b)	/* round a up to a multiple of b */
int a,b;
{
return(b * ceil(a,b));
}


ceil(a,b)
int a,b;
{
return( (a+b-1)/b );
}




ptr esizeof(type, typep, dim)
register int type;
register ptr typep;
ptr dim;
{
register int k;

switch(type)
	{
	case TYFIELD:
	case TYINT:
	case TYREAL:
	case TYLREAL:
	case TYCOMPLEX:
	case TYLCOMPLEX:
	case TYLOG:
		k = tailor.ftnsize[ eflftn[type] ];
		break;

	case TYSTRUCT:
		k = ((struct typeblock *)typep)->strsize;
		break;

	case TYCHAR:
		k = tailor.ftnsize[FTNINT] * ceil(conval(typep), tailor.ftnchwd);
		break;

	default:
		exprerr("invalid sizeof", "");
		k = 0;
	}
/* debug version.  should multiply by dimension */
return( mkint(k) );
}



ptr elenof(type, typep, dim)
register int type;
register ptr typep;
ptr dim;
{
if(type == TYCHAR)
	return( mkint( conval(typep) ) );
exprerr("invalid lengthof", "");
return( mkint(0) );
/* debug version.  should multiply by dimension */
}
