444 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			444 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "f2c.h"
 | |
| #include "fio.h"
 | |
| #include "lio.h"
 | |
| 
 | |
| #define MAX_NL_CACHE 3	/* maximum number of namelist hash tables to cache */
 | |
| #define MAXDIM 20	/* maximum number of subscripts */
 | |
| 
 | |
|  extern char *malloc(), *memset();
 | |
| 
 | |
|  struct dimen {
 | |
| 	ftnlen extent;
 | |
| 	ftnlen curval;
 | |
| 	ftnlen delta;
 | |
| 	ftnlen stride;
 | |
| 	};
 | |
|  typedef struct dimen dimen;
 | |
| 
 | |
|  struct hashentry {
 | |
| 	struct hashentry *next;
 | |
| 	char *name;
 | |
| 	Vardesc *vd;
 | |
| 	};
 | |
|  typedef struct hashentry hashentry;
 | |
| 
 | |
|  struct hashtab {
 | |
| 	struct hashtab *next;
 | |
| 	Namelist *nl;
 | |
| 	int htsize;
 | |
| 	hashentry *tab[1];
 | |
| 	};
 | |
|  typedef struct hashtab hashtab;
 | |
| 
 | |
|  static hashtab *nl_cache;
 | |
|  static n_nlcache;
 | |
|  static hashentry **zot;
 | |
|  extern ftnlen typesize[];
 | |
| 
 | |
|  extern flag lquit;
 | |
|  extern int lcount;
 | |
|  extern int (*l_getc)(), (*l_ungetc)(), t_getc(), ungetc();
 | |
| 
 | |
|  static Vardesc *
 | |
| hash(ht, s)
 | |
|  hashtab *ht;
 | |
|  register char *s;
 | |
| {
 | |
| 	register int c, x;
 | |
| 	register hashentry *h;
 | |
| 	char *s0 = s;
 | |
| 
 | |
| 	for(x = 0; c = *s++; x = x & 0x4000 ? ((x << 1) & 0x7fff) + 1 : x << 1)
 | |
| 		x += c;
 | |
| 	for(h = *(zot = ht->tab + x % ht->htsize); h; h = h->next)
 | |
| 		if (!strcmp(s0, h->name))
 | |
| 			return h->vd;
 | |
| 	return 0;
 | |
| 	}
 | |
| 
 | |
|  hashtab *
 | |
| mk_hashtab(nl)
 | |
|  Namelist *nl;
 | |
| {
 | |
| 	int nht, nv;
 | |
| 	hashtab *ht;
 | |
| 	Vardesc *v, **vd, **vde;
 | |
| 	hashentry *he;
 | |
| 
 | |
| 	hashtab **x, **x0, *y;
 | |
| 	for(x = &nl_cache; y = *x; x0 = x, x = &y->next)
 | |
| 		if (nl == y->nl)
 | |
| 			return y;
 | |
| 	if (n_nlcache >= MAX_NL_CACHE) {
 | |
| 		/* discard least recently used namelist hash table */
 | |
| 		y = *x0;
 | |
| 		free((char *)y->next);
 | |
| 		y->next = 0;
 | |
| 		}
 | |
| 	else
 | |
| 		n_nlcache++;
 | |
| 	nv = nl->nvars;
 | |
| 	if (nv >= 0x4000)
 | |
| 		nht = 0x7fff;
 | |
| 	else {
 | |
| 		for(nht = 1; nht < nv; nht <<= 1);
 | |
| 		nht += nht - 1;
 | |
| 		}
 | |
| 	ht = (hashtab *)malloc(sizeof(hashtab) + (nht-1)*sizeof(hashentry *)
 | |
| 				+ nv*sizeof(hashentry));
 | |
| 	if (!ht)
 | |
| 		return 0;
 | |
| 	he = (hashentry *)&ht->tab[nht];
 | |
| 	ht->nl = nl;
 | |
| 	ht->htsize = nht;
 | |
| 	ht->next = nl_cache;
 | |
| 	nl_cache = ht;
 | |
| 	memset((char *)ht->tab, 0, nht*sizeof(hashentry *));
 | |
| 	vd = nl->vars;
 | |
| 	vde = vd + nv;
 | |
| 	while(vd < vde) {
 | |
| 		v = *vd++;
 | |
| 		if (!hash(ht, v->name)) {
 | |
| 			he->next = *zot;
 | |
| 			*zot = he;
 | |
| 			he->name = v->name;
 | |
| 			he->vd = v;
 | |
| 			he++;
 | |
| 			}
 | |
| 		}
 | |
| 	return ht;
 | |
| 	}
 | |
| 
 | |
| static char Alpha[256], Alphanum[256];
 | |
| 
 | |
|  static void
 | |
| nl_init() {
 | |
| 	register char *s;
 | |
| 	register int c;
 | |
| 
 | |
| 	if(!init)
 | |
| 		f_init();
 | |
| 	for(s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; c = *s++; )
 | |
| 		Alpha[c]
 | |
| 		= Alphanum[c]
 | |
| 		= Alpha[c + 'a' - 'A']
 | |
| 		= Alphanum[c + 'a' - 'A']
 | |
| 		= c;
 | |
| 	for(s = "0123456789_"; c = *s++; )
 | |
| 		Alphanum[c] = c;
 | |
| 	}
 | |
| 
 | |
| #define GETC(x) (x=(*l_getc)())
 | |
| #define Ungetc(x,y) (*l_ungetc)(x,y)
 | |
| 
 | |
|  static int
 | |
| getname(s, slen)
 | |
|  register char *s;
 | |
|  int slen;
 | |
| {
 | |
| 	register char *se = s + slen - 1;
 | |
| 	register int ch;
 | |
| 
 | |
| 	GETC(ch);
 | |
| 	if (!(*s++ = Alpha[ch & 0xff])) {
 | |
| 		if (ch != EOF)
 | |
| 			ch = 115;
 | |
| 		err(elist->cierr, ch, "namelist read");
 | |
| 		}
 | |
| 	while(*s = Alphanum[GETC(ch) & 0xff])
 | |
| 		if (s < se)
 | |
| 			s++;
 | |
| 	if (ch == EOF)
 | |
| 		err(elist->cierr, ch == EOF ? -1 : 115, "namelist read");
 | |
| 	if (ch > ' ')
 | |
| 		Ungetc(ch,cf);
 | |
| 	return *s = 0;
 | |
| 	}
 | |
| 
 | |
|  static int
 | |
| getnum(chp, val)
 | |
|  int *chp;
 | |
|  ftnlen *val;
 | |
| {
 | |
| 	register int ch, sign;
 | |
| 	register ftnlen x;
 | |
| 
 | |
| 	while(GETC(ch) <= ' ' && ch >= 0);
 | |
| 	if (ch == '-') {
 | |
| 		sign = 1;
 | |
| 		GETC(ch);
 | |
| 		}
 | |
| 	else {
 | |
| 		sign = 0;
 | |
| 		if (ch == '+')
 | |
| 			GETC(ch);
 | |
| 		}
 | |
| 	x = ch - '0';
 | |
| 	if (x < 0 || x > 9)
 | |
| 		return 115;
 | |
| 	while(GETC(ch) >= '0' && ch <= '9')
 | |
| 		x = 10*x + ch - '0';
 | |
| 	while(ch <= ' ' && ch >= 0)
 | |
| 		GETC(ch);
 | |
| 	if (ch == EOF)
 | |
| 		return EOF;
 | |
| 	*val = sign ? -x : x;
 | |
| 	*chp = ch;
 | |
| 	return 0;
 | |
| 	}
 | |
| 
 | |
|  static int
 | |
| getdimen(chp, d, delta, extent, x1)
 | |
|  int *chp;
 | |
|  dimen *d;
 | |
|  ftnlen delta, extent, *x1;
 | |
| {
 | |
| 	register int k;
 | |
| 	ftnlen x2, x3;
 | |
| 
 | |
| 	if (k = getnum(chp, x1))
 | |
| 		return k;
 | |
| 	x3 = 1;
 | |
| 	if (*chp == ':') {
 | |
| 		if (k = getnum(chp, &x2))
 | |
| 			return k;
 | |
| 		x2 -= *x1;
 | |
| 		if (*chp == ':') {
 | |
| 			if (k = getnum(chp, &x3))
 | |
| 				return k;
 | |
| 			if (!x3)
 | |
| 				return 123;
 | |
| 			x2 /= x3;
 | |
| 			}
 | |
| 		if (x2 < 0 || x2 >= extent)
 | |
| 			return 123;
 | |
| 		d->extent = x2 + 1;
 | |
| 		}
 | |
| 	else
 | |
| 		d->extent = 1;
 | |
| 	d->curval = 0;
 | |
| 	d->delta = delta;
 | |
| 	d->stride = x3;
 | |
| 	return 0;
 | |
| 	}
 | |
| 
 | |
|  static char where0[] = "namelist read start ";
 | |
| 
 | |
| x_rsne(a)
 | |
|  cilist *a;
 | |
| {
 | |
| 	int ch, got1, k, n, nd;
 | |
| 	Namelist *nl;
 | |
| 	static char where[] = "namelist read";
 | |
| 	char buf[64];
 | |
| 	hashtab *ht;
 | |
| 	Vardesc *v;
 | |
| 	dimen *dn, *dn0, *dn1;
 | |
| 	ftnlen *dims, *dims1;
 | |
| 	ftnlen b, b0, b1, ex, no, no1, nomax, size, span;
 | |
| 	ftnint type;
 | |
| 	char *vaddr;
 | |
| 	long iva, ivae;
 | |
| 	dimen dimens[MAXDIM], substr;
 | |
| 
 | |
| 	if (!Alpha['a'])
 | |
| 		nl_init();
 | |
| 	reading=1;
 | |
| 	formatted=1;
 | |
| 	lquit = 0;
 | |
| 	lcount = 0;
 | |
| 	got1 = 0;
 | |
| 	for(;;) switch(GETC(ch)) {
 | |
| 		case EOF:
 | |
| 			err(a->ciend,(EOF),where0);
 | |
| 		case '&':
 | |
| 		case '$':
 | |
| 			goto have_amp;
 | |
| 		default:
 | |
| 			if (ch <= ' ' && ch >= 0)
 | |
| 				continue;
 | |
| 			err(a->cierr, 115, where0);
 | |
| 		}
 | |
|  have_amp:
 | |
| 	if (ch = getname(buf,sizeof(buf)))
 | |
| 		return ch;
 | |
| 	nl = (Namelist *)a->cifmt;
 | |
| 	if (strcmp(buf, nl->name))
 | |
| 		err(a->cierr, 118, where0);
 | |
| 	ht = mk_hashtab(nl);
 | |
| 	if (!ht)
 | |
| 		err(elist->cierr, 113, where0);
 | |
| 	for(;;) {
 | |
| 		for(;;) switch(GETC(ch)) {
 | |
| 			case EOF:
 | |
| 				if (got1)
 | |
| 					return 0;
 | |
| 				err(a->ciend,(EOF),where0);
 | |
| 			case '/':
 | |
| 			case '$':
 | |
| 				return 0;
 | |
| 			default:
 | |
| 				if (ch <= ' ' && ch >= 0 || ch == ',')
 | |
| 					continue;
 | |
| 				Ungetc(ch,cf);
 | |
| 				if (ch = getname(buf,sizeof(buf)))
 | |
| 					return ch;
 | |
| 				goto havename;
 | |
| 			}
 | |
|  havename:
 | |
| 		v = hash(ht,buf);
 | |
| 		if (!v)
 | |
| 			err(a->cierr, 119, where);
 | |
| 		while(GETC(ch) <= ' ' && ch >= 0);
 | |
| 		vaddr = v->addr;
 | |
| 		type = v->type;
 | |
| 		if (type < 0) {
 | |
| 			size = -type;
 | |
| 			type = TYCHAR;
 | |
| 			}
 | |
| 		else
 | |
| 			size = typesize[type];
 | |
| 		ivae = size;
 | |
| 		iva = 0;
 | |
| 		if (ch == '(' /*)*/ ) {
 | |
| 			dn = dimens;
 | |
| 			if (!(dims = v->dims)) {
 | |
| 				if (type != TYCHAR)
 | |
| 					err(a->cierr, 122, where);
 | |
| 				if (k = getdimen(&ch, dn, (ftnlen)size,
 | |
| 						(ftnlen)size, &b))
 | |
| 					err(a->cierr, k, where);
 | |
| 				if (ch != ')')
 | |
| 					err(a->cierr, 115, where);
 | |
| 				b1 = dn->extent;
 | |
| 				if (--b < 0 || b + b1 > size)
 | |
| 					return 124;
 | |
| 				iva += b;
 | |
| 				size = b1;
 | |
| 				while(GETC(ch) <= ' ' && ch >= 0);
 | |
| 				goto scalar;
 | |
| 				}
 | |
| 			nd = dims[0];
 | |
| 			nomax = span = dims[1];
 | |
| 			ivae = iva + size*nomax;
 | |
| 			if (k = getdimen(&ch, dn, size, nomax, &b))
 | |
| 				err(a->cierr, k, where);
 | |
| 			no = dn->extent;
 | |
| 			b0 = dims[2];
 | |
| 			dims1 = dims += 3;
 | |
| 			ex = 1;
 | |
| 			for(n = 1; n++ < nd; dims++) {
 | |
| 				if (ch != ',')
 | |
| 					err(a->cierr, 115, where);
 | |
| 				dn1 = dn + 1;
 | |
| 				span /= *dims;
 | |
| 				if (k = getdimen(&ch, dn1, dn->delta**dims,
 | |
| 						span, &b1))
 | |
| 					err(a->cierr, k, where);
 | |
| 				ex *= *dims;
 | |
| 				b += b1*ex;
 | |
| 				no *= dn1->extent;
 | |
| 				dn = dn1;
 | |
| 				}
 | |
| 			if (ch != ')')
 | |
| 				err(a->cierr, 115, where);
 | |
| 			b -= b0;
 | |
| 			if (b < 0 || b >= nomax)
 | |
| 				err(a->cierr, 125, where);
 | |
| 			iva += size * b;
 | |
| 			dims = dims1;
 | |
| 			while(GETC(ch) <= ' ' && ch >= 0);
 | |
| 			no1 = 1;
 | |
| 			dn0 = dimens;
 | |
| 			if (type == TYCHAR && ch == '(' /*)*/) {
 | |
| 				if (k = getdimen(&ch, &substr, size, size, &b))
 | |
| 					err(a->cierr, k, where);
 | |
| 				if (ch != ')')
 | |
| 					err(a->cierr, 115, where);
 | |
| 				b1 = substr.extent;
 | |
| 				if (--b < 0 || b + b1 > size)
 | |
| 					return 124;
 | |
| 				iva += b;
 | |
| 				b0 = size;
 | |
| 				size = b1;
 | |
| 				while(GETC(ch) <= ' ' && ch >= 0);
 | |
| 				if (b1 < b0)
 | |
| 					goto delta_adj;
 | |
| 				}
 | |
| 			for(; dn0 < dn; dn0++) {
 | |
| 				if (dn0->extent != *dims++ || dn0->stride != 1)
 | |
| 					break;
 | |
| 				no1 *= dn0->extent;
 | |
| 				}
 | |
| 			if (dn0 == dimens && dimens[0].stride == 1) {
 | |
| 				no1 = dimens[0].extent;
 | |
| 				dn0++;
 | |
| 				}
 | |
|  delta_adj:
 | |
| 			ex = 0;
 | |
| 			for(dn1 = dn0; dn1 <= dn; dn1++)
 | |
| 				ex += (dn1->extent-1)
 | |
| 					* (dn1->delta *= dn1->stride);
 | |
| 			for(dn1 = dn; dn1 > dn0; dn1--) {
 | |
| 				ex -= (dn1->extent - 1) * dn1->delta;
 | |
| 				dn1->delta -= ex;
 | |
| 				}
 | |
| 			}
 | |
| 		else if (dims = v->dims) {
 | |
| 			no = no1 = dims[1];
 | |
| 			ivae = iva + no*size;
 | |
| 			}
 | |
| 		else
 | |
|  scalar:
 | |
| 			no = no1 = 1;
 | |
| 		if (ch != '=')
 | |
| 			err(a->cierr, 115, where);
 | |
| 		got1 = 1;
 | |
| 	 readloop:
 | |
| 		for(;;) {
 | |
| 			if (iva >= ivae || iva < 0)
 | |
| 				goto mustend;
 | |
| 			else if (iva + no1*size > ivae) {
 | |
| 				no1 = (ivae - iva)/size;
 | |
| 				l_read(&no1, vaddr + iva, size, type);
 | |
|  mustend:
 | |
| 				if (GETC(ch) == '/' || ch == '$')
 | |
| 					lquit = 1;
 | |
| 				else
 | |
| 					err(a->cierr, 125, where);
 | |
| 				}
 | |
| 			else
 | |
| 				l_read(&no1, vaddr + iva, size, type);
 | |
| 			if (lquit)
 | |
| 				return 0;
 | |
| 			if ((no -= no1) <= 0)
 | |
| 				break;
 | |
| 			for(dn1 = dn0; dn1 <= dn; dn1++) {
 | |
| 				if (++dn1->curval < dn1->extent) {
 | |
| 					iva += dn1->delta;
 | |
| 					goto readloop;
 | |
| 					}
 | |
| 				dn1->curval = 0;
 | |
| 				}
 | |
| 			break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
|  integer
 | |
| s_rsne(a)
 | |
|  cilist *a;
 | |
| {
 | |
| 	int n;
 | |
| 	extern integer e_rsle();
 | |
| 	external=1;
 | |
| 	if(n = c_le(a))
 | |
| 		return n;
 | |
| 	if(curunit->uwrt && nowreading(curunit))
 | |
| 		err(a->cierr,errno,where0);
 | |
| 	l_getc = t_getc;
 | |
| 	l_ungetc = ungetc;
 | |
| 	if (n = x_rsne(a))
 | |
| 		return n;
 | |
| 	return e_rsle();
 | |
| 	}
 |