#include "sam.h"

#define	NSYSFILE	3
#define	NOFILE		128

void
checkqid(File *f)
{
	int i, w;
	File *g;

	w = whichmenu(f);
	for(i=1; i<file.nused; i++){
		g = file.filepptr[i];
		if(w == i)
			continue;
		if(f->dev==g->dev && f->qidpath==g->qidpath)
			warn_SS(Wdupfile, &f->name, &g->name);
	}
}

void
writef(File *f)
{
	Posn n;
	char *name;
	int i, samename, newfile;
	ulong dev;
	uvlong qid;
	long mtime, appendonly, length;

	newfile = 0;
	samename = Strcmp(&genstr, &f->name) == 0;
	name = Strtoc(&f->name);
	i = statfile(name, &dev, &qid, &mtime, 0, 0);
	if(i == -1)
		newfile++;
	else if(samename &&
	        (f->dev!=dev || f->qidpath!=qid || f->mtime<mtime)){
		f->dev = dev;
		f->qidpath = qid;
		f->mtime = mtime;
		warn_S(Wdate, &genstr);
		return;
	}
	if(genc)
		free(genc);
	genc = Strtoc(&genstr);
	if((io=create(genc, 1, 0666L)) < 0)
		error_s(Ecreate, genc);
	dprint("%s: ", genc);
	if(statfd(io, 0, 0, 0, &length, &appendonly) > 0 && appendonly && length>0)
		error(Eappend);
	n = writeio(f);
	if(f->name.s[0]==0 || samename){
		if(addr.r.p1==0 && addr.r.p2==f->nc)
			f->cleanseq = f->seq;
		state(f, f->cleanseq==f->seq? Clean : Dirty);
	}
	if(newfile)
		dprint("(new file) ");
	if(addr.r.p2>0 && filereadc(f, addr.r.p2-1)!='\n')
		warn(Wnotnewline);
	closeio(n);
	if(f->name.s[0]==0 || samename){
		if(statfile(name, &dev, &qid, &mtime, 0, 0) > 0){
			f->dev = dev;
			f->qidpath = qid;
			f->mtime = mtime;
			checkqid(f);
		}
	}
}

Posn
readio(File *f, int *nulls, int setdate, int toterm)
{
	int n, b, w;
	Rune *r;
	Posn nt;
	Posn p = addr.r.p2;
	ulong dev;
	uvlong qid;
	long mtime;
	char buf[BLOCKSIZE+1], *s;

	*nulls = FALSE;
	b = 0;
	if(f->unread){
		nt = bufload(f, 0, io, nulls);
		if(toterm)
			raspload(f);
	}else
		for(nt = 0; (n = read(io, buf+b, BLOCKSIZE-b))>0; nt+=(r-genbuf)){
			n += b;
			b = 0;
			r = genbuf;
			s = buf;
			while(n > 0){
				if((*r = *(uchar*)s) < Runeself){
					if(*r)
						r++;
					else
						*nulls = TRUE;
					--n;
					s++;
					continue;
				}
				if(fullrune(s, n)){
					w = chartorune(r, s);
					if(*r)
						r++;
					else
						*nulls = TRUE;
					n -= w;
					s += w;
					continue;
				}
				b = n;
				memmove(buf, s, b);
				break;
			}
			loginsert(f, p, genbuf, r-genbuf);
		}
	if(b)
		*nulls = TRUE;
	if(*nulls)
		warn(Wnulls);
	if(setdate){
		if(statfd(io, &dev, &qid, &mtime, 0, 0) > 0){
			f->dev = dev;
			f->qidpath = qid;
			f->mtime = mtime;
			checkqid(f);
		}
	}
	return nt;
}

Posn
writeio(File *f)
{
	int m, n;
	Posn p = addr.r.p1;
	char *c;

	while(p < addr.r.p2){
		if(addr.r.p2-p>BLOCKSIZE)
			n = BLOCKSIZE;
		else
			n = addr.r.p2-p;
		bufread(f, p, genbuf, n);
		c = Strtoc(tmprstr(genbuf, n));
		m = strlen(c);
		if(Write(io, c, m) != m){
			free(c);
			if(p > 0)
				p += n;
			break;
		}
		free(c);
		p += n;
	}
	return p-addr.r.p1;
}
void
closeio(Posn p)
{
	close(io);
	io = 0;
	if(p >= 0)
		dprint("#%lud\n", p);
}
