/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 *
 */

#include        "ass00.h"
#include        "assex.h"
#include        <em_path.h>

#ifndef NORCSID
static char rcs_id[] = "$Id$" ;
#endif

/*
 * this file contains several library routines.
 */

zero(area,length) char *area; unsigned length ; {
	register char *p;
	register n;
	/*
	 * Clear area of length bytes.
	 */
	if ((n=length)==0)
		return;
	p = area;
	do *p++=0; while (--n);
}

/* VARARGS1 */
static void pr_error(string1,a1,a2,a3,a4) char *string1 ; {
	/*
	 * diagnostic output
	 */
	fprintf(stderr,"%s: ",progname);
	if (curfile) {
		fprintf(stderr,"file %s",curfile);
		if (archmode)
			fprintf(stderr," (%.14s)",archhdr.ar_name);
		fprintf(stderr,": ");
	}
	if ( pstate.s_curpro ) {
		fprintf(stderr,"proc %s, ",pstate.s_curpro->p_name);
	}
	fprintf(stderr,"line %d: ",line_num);
	fprintf(stderr,string1,a1,a2,a3,a4);
	fprintf(stderr,"\n");
}

/* VARARGS1 */
void error(string1,a1,a2,a3,a4) char *string1 ; {
	pr_error(string1,a1,a2,a3,a4) ;
	nerrors++ ;
}

/* VARARGS1 */
void werror(string1,a1,a2,a3,a4) char *string1 ; {
	if ( wflag ) return ;
	pr_error(string1,a1,a2,a3,a4) ;
}

fatal(s) char *s; {
	/*
	 * handle fatal errors
	 */
	error("Fatal error: %s",s);
	dump(0);
	exit(-1);
}

#ifndef CPM
FILE *frewind(f) FILE *f ; {
	/* Rewind a file open for writing and open it for reading */
	/* Assumption, file descriptor is r/w */
	register FILE *tmp ;
	tmp=fdopen(dup(fileno(f)),"r");
	fclose(f);
	rewind(tmp);
	return tmp ;
}
#endif

int xgetc(af) register FILE *af; {
	register int nextc;
	/*
	 * read next character; fatal if there isn't one
	 */
	nextc=fgetc(af) ;
	if ( feof(af) )
			fatal("unexpected end of file");
	return nextc ;
}

xputc(c,af) register FILE *af; {
	/* output one character and scream if it gives an error */
	fputc(c,af) ;
	if ( ferror(af) ) fatal("write error") ;
}


putblk(stream,from,amount)
	register FILE *stream; register char *from ; register int amount ; {

	for ( ; amount-- ; from++ ) {
		fputc(*from,stream) ;
		if ( ferror(stream) ) fatal("write error") ;
	}
}

int getblk(stream,from,amount)
	register FILE *stream; register char *from ; register int amount ; {

	for ( ; amount-- ; from++ ) {
		*from = fgetc(stream) ;
		if ( feof(stream) ) return 1 ;
	}
	return 0 ;
}

xput16(w,f) FILE *f; {
	/*
	 * two times xputc
	 */
	xputc(w,f);
	xputc(w>>8,f);
}

xputarb(l,w,f) int l ; cons_t w ; FILE *f ; {
	while ( l-- ) {
		xputc( int_cast w,f) ;
		w >>=8 ;
	}
}

put8(n) {
	xputc(n,tfile);
	textoff++;
}

put16(n) {
	/*
	 * note reversed order of bytes.
	 * this is done for faster interpretation.
	 */
	xputc(n>>8,tfile);
	xputc(n&0377,tfile);
	textoff += 2;
}

put32(n) cons_t n ; {
	put16( int_cast (n>>16)) ;
	put16( int_cast n) ;
}

put64(n) cons_t n ; {
	fatal("put64 called") ;
}

int xget8() {
	/*
	 * Read one byte from ifile.
	 */
	if (libeof && inpoff >= libeof)
		return EOF ;
	inpoff++;
	return fgetc(ifile) ;
}

unsigned get8() {
	register int nextc;
	/*
	 * Read one byte from ifile.
	 */
	nextc=xget8();
	if ( nextc==EOF ) {
		if (libeof)
			fatal("Tried to read past end of arentry\n");
		else
			fatal("end of file on input");
	}
	return nextc ;
}

cons_t xgetarb(l,f) int l; FILE *f ; {
	cons_t val ;
	register int shift ;
	int c;

	shift=0 ; val=0 ;
	while ( l-- ) {
		val += ((cons_t)(c = ctrunc(xgetc(f))))<<shift ;
		shift += 8 ;
	}
	if (c == 0377 && shift > 8 && ((shift>>3)&1)) {
		while (shift < 8*sizeof(cons_t)) {
			val += ((cons_t)c)<<shift ;
			shift += 8;
		}
	}
	return val ;
}

ext8(b) {
	/*
	 * Handle one byte of data.
	 */
	++dataoff;
	xputc(b,dfile);
}

extword(w) cons_t w ; {
	/* Assemble the word constant w.
	 * NOTE: The bytes are written low to high.
	 */
	register i ;
	for ( i=wordsize ; i-- ; ) {
		ext8( int_cast w) ;
		w >>= 8 ;
	}
}

extarb(size,value) int size ; long value ; {
	/* Assemble the 'size' constant value.
	 * The bytes are again written low to high.
	 */
	register i ;
	for ( i=size ; i-- ; ) {
		ext8( int_cast value ) ;
		value >>=8 ;
	}
}

extadr(a) cons_t a ; {
	/* Assemble the word constant a.
	 * NOTE: The bytes are written low to high.
	 */
	register i ;
	for ( i=ptrsize ; i-- ; ) {
		ext8( int_cast a) ;
		a >>= 8 ;
	}
}

xputa(a,f) cons_t a ; FILE *f ; {
	/* Assemble the pointer constant a.
	 * NOTE: The bytes are written low to high.
	 */
	register i ;
	for ( i=ptrsize ; i-- ; ) {
		xputc( int_cast a,f) ;
		a >>= 8 ;
	}
}

cons_t xgeta(f) FILE *f ; {
	/* Read the pointer constant a.
	 * NOTE: The bytes were written low to high.
	 */
	register i, shift ;
	cons_t val ;
	val = 0 ; shift=0 ;
	for ( i=ptrsize ; i-- ; ) {
		val += ((cons_t)xgetc(f))<<shift ;
		shift += 8 ;
	}
	return val ;
}

int icount(size) {
	int amount ;
	amount=(dataoff-lastoff)/size ;
	if ( amount>MAXBYTE) fatal("Descriptor overflow");
	return amount ;
}

setmode(mode) {

	if (datamode==mode) {   /* in right mode already */
		switch ( datamode ) {
		case DATA_CONST:
			if ( (dataoff-lastoff)/wordsize < MAXBYTE ) return ;
			break ;
		case DATA_BYTES:
			if ( dataoff-lastoff < MAXBYTE ) return ;
			break ;
		case DATA_IPTR:
		case DATA_DPTR:
			if ( (dataoff-lastoff)/ptrsize < MAXBYTE ) return ;
			break ;
		case DATA_ICON:
		case DATA_FCON:
		case DATA_UCON:
		case DATA_BSS:
			break ;
		default:
			return ;
		}
		setmode(DATA_NUL) ; /* flush current descriptor */
		setmode(mode) ;
		return;
	}
	switch(datamode) {              /* terminate current mode */
	case DATA_NUL:
		break;                  /* nothing to terminate */
	case DATA_CONST:
		lastheader->r_val.rel_i=icount(wordsize) ;
		lastheader->r_typ = RELHEAD;
		datablocks++;
		break;
	case DATA_BYTES:
		lastheader->r_val.rel_i=icount(1) ;
		lastheader->r_typ = RELHEAD;
		datablocks++;
		break;
	case DATA_DPTR:
	case DATA_IPTR:
		lastheader->r_val.rel_i=icount(ptrsize) ;
		lastheader->r_typ = RELHEAD;
		datablocks++;
		break;
	default:
		datablocks++;
		break;
	}
	datamode=mode;
	switch(datamode) {
	case DATA_NUL:
		break;
	case DATA_CONST:
		ext8(HEADCONST);
		lastheader=data_reloc( chp_cast 0,dataoff,RELNULL);
		ext8(0);
		lastoff=dataoff;
		break;
	case DATA_BYTES:
		ext8(HEADBYTE);
		lastheader=data_reloc( chp_cast 0,dataoff,RELNULL);
		ext8(0);
		lastoff=dataoff;
		break;
	case DATA_IPTR:
		ext8(HEADIPTR);
		lastheader=data_reloc( chp_cast 0,dataoff,RELNULL);
		ext8(0);
		lastoff=dataoff;
		break;
	case DATA_DPTR:
		ext8(HEADDPTR);
		lastheader=data_reloc( chp_cast 0,dataoff,RELNULL);
		ext8(0);
		lastoff=dataoff;
		break;
	case DATA_ICON:
		ext8(HEADICON) ;
		ext8( int_cast consiz) ;
		break;
	case DATA_FCON:
		ext8(HEADFCON) ;
		ext8( int_cast consiz) ;
		break;
	case DATA_UCON:
		ext8(HEADUCON) ;
		ext8( int_cast consiz) ;
		break;
	case DATA_REP:
		ext8(HEADREP) ;
		break ;
	case DATA_BSS:
		ext8(HEADBSS) ;
		break;
	default:
		fatal("Unknown mode in setmode") ;
	}
}

#ifndef CPM
int tmpfil() {
	register char *fname, *cpname ;
	static char sfname[] = "tmp.00000";
	register fildes,pid;
	static char name[80] = TMP_DIR ;
	int count;
	/*
	 * This procedure returns a file-descriptor of a temporary
	 * file valid for reading and writing.
	 * After closing the tmpfil-descriptor the file is lost
	 * Calling this routine frees the program from generating uniqe names.
	 */
	fname = sfname+4;
	count = 10;
	pid = getpid();
	while (pid!=0) {
		*fname++ = (pid&07) + '0';
		pid >>= 3;
	}
	*fname = 0;
	for ( fname=name ; *fname ; fname++ ) ;
	cpname=sfname ;
	while ( *fname++ = *cpname++ ) ;
	do {
		fname = name;
		if ((fildes = creat(fname, 0600)) < 0)
			if ((fildes = creat(fname=sfname, 0600)) < 0)
				return(-1);
		if (close(fildes) < 0)
			;
	} while((fildes = open(fname, 2)) < 0 && count--);
	if (unlink(fname) < 0)
		;
	return(fildes);
}
#endif
