#include <alef.h>
#include <libg.h>

intern byte*
skip(byte *s)
{
	while(*s==' ' || *s=='\n' || *s=='\t')
		s++;
	return s;
}

Font*
rdfontfile(byte *name, int ldepth)
{
	Font *fnt;
	Cachefont *c;
	int fd, i;
	byte *buf, *s, *t;
	Dir dir;
	uint min, max;
	byte *gbuf;
	int offset;

	fd = open(name, OREAD);
	if(fd < 0)
		return nil;

	rescue {
		close(fd);
		return nil;
	}
	if(dirfstat(fd, &dir) < 0)
    		raise;

	buf = malloc(dir.length+1);
	if(buf == nil)
		raise;

	buf[dir.length] = 0;
	i = read(fd, buf, dir.length);
	close(fd);

	rescue {
		free(buf);
		return nil;
	}
	if(i != dir.length)
    		raise;

	close(fd);
	s = buf;
	fnt = malloc(sizeof(Font));
	if(fnt == nil)
    		raise;

	fnt->name = strdup(name);
	fnt->ncache = NFCACHE+NFLOOK;
	fnt->nsubf = NFSUBF;
	fnt->cache = malloc(fnt->ncache * sizeof(fnt->cache[0]));
	fnt->subf = malloc(fnt->nsubf * sizeof(fnt->subf[0]));
	if(fnt->name==nil || fnt->cache==nil || fnt->subf==nil)
		raise Err2;

	rescue Err2 {
		free(fnt->name);
		free(fnt->cache);
		free(fnt->subf);
		free(fnt->sub);
		free(fnt);
		raise;
	}

	fnt->height = strtoi(s, &s, 0);
	s = skip(s);
	fnt->ascent = strtoi(s, &s, 0);
	s = skip(s);
	if(fnt->height<=0 || fnt->ascent<=0)
		raise Err2;
	fnt->width = 0;
	fnt->ldepth = ldepth;

	gbuf = bneed(7);
	gbuf[0] = 'n';
	gbuf[1] = fnt->height;
	gbuf[2] = fnt->ascent;
	BPSHORT(gbuf+3, ldepth);
	BPSHORT(gbuf+5, fnt->ncache);
	if(!bwrite())
		raise Err2;
	if(read(bitbltfd, gbuf, 3)!=3 || gbuf[0]!='N')
		raise Err2;

	fnt->id = gbuf[1] | (gbuf[2]<<8);
	fnt->nsub = 0;
	fnt->sub = nil;

	fnt->age = 1;
	do{
		min = strtoi(s, &s, 0);
		s = skip(s);
		max = strtoi(s, &s, 0);
		s = skip(s);
		rescue {
			ffree(fnt);
			return nil;
		}

		if(*s==0 || min>=65536 || max>=65536 || min>max)
			raise;

		t = s;
		offset = strtoi(s, &t, 0);
		if(t>s && (*t==' ' || *t=='\t' || *t=='\n'))
			s = skip(t);
		else
			offset = 0;

		fnt->sub = realloc(fnt->sub, (fnt->nsub+1)*sizeof(Cachefont*));
		if(fnt->sub == nil){
			/* realloc manual says fnt->sub may have
			 * been destroyed */
			fnt->nsub = 0;
			raise;
		}
		c = malloc(sizeof(Cachefont));
		if(c == nil)
			raise;
		fnt->sub[fnt->nsub] = c;
		c->min = min;
		c->max = max;
		c->offset = offset;
		t = s;
		while(*s && *s!=' ' && *s!='\n' && *s!='\t')
			s++;
		*s++ = 0;
		c->abs = 0;
		c->name = strdup(t);
		if(c->name == nil){
			free(c);
			raise;
		}
		s = skip(s);
		fnt->nsub++;
	}while(*s);
	free(buf);
	return fnt;
}

void
ffree(Font *f)
{
	int i;
	Cachefont *c;
	byte *b;

	for(i=0; i<f->nsub; i++){
		c = f->sub[i];
		free(c->name);
		free(c);
	}
	for(i=0; i<f->nsubf; i++)
		if(f->subf[i].f)
			subffree(f->subf[i].f);
	free(f->cache);
	free(f->subf);
	free(f->sub);
	if(f->id >= 0){
		b = bneed(3);
		b[0] = 'h';
		BPSHORT(b+1, f->id);
	}
	free(f);
}
