/* $Header$ */
/* EM CODE OUTPUT ROUTINES */

#define CMODE 0644
#define MAX_ARG_CNT 32

#include	"em.h"
#include	<system.h>
#include	"arith.h"
#include	"label.h"

/*
	putbyte(), C_open() and C_close() are the basic routines for
	respectively write on, open and close the output file.
	The put_*() functions serve as formatting functions of the
	various EM language constructs.
	See "Description of a Machine Architecture for use with
	Block Structured Languages" par. 11.2 for the meaning of these
	names.
*/

/* supply a kind of buffered output */
#define	flush(x)	sys_write(ofp, &obuf[0], x)

static char obuf[BUFSIZ];
static char *opp = &obuf[0];
File *ofp = 0;

putbyte(b)	/* shouldn't putbyte() be a macro ??? (EB)	*/
	int b;
{
	if (opp >= &obuf[BUFSIZ]) { /* flush if buffer overflows */
		if (flush(BUFSIZ) == 0)
			sys_stop(S_ABORT);
		opp = &obuf[0];
	}
	*opp++ = (char) b;
}

C_init(wsize, psize)
	arith wsize, psize;
{}

C_open(nm)	/* open file for compact code output	*/
	char *nm;
{
	if (nm == 0)
		ofp = STDOUT;	/* standard output	*/
	else
	if (sys_open(nm, OP_WRITE, &ofp) == 0)
		return 0;
	return 1;
}

C_close()
{
	if (flush(opp - &obuf[0]) == 0)
		sys_stop(S_ABORT);
	opp = obuf;	/* reset opp	*/
	if (ofp != STDOUT)
		sys_close(ofp);
	ofp = 0;
}

C_busy()
{
	return ofp != 0; /* true if code is being generated */
}

/***    the compact code generating routines	***/
#define	fit16i(x)	((x) >= (long)0xFFFF8000 && (x) <= (long)0x00007FFF)
#define	fit8u(x)	((x) <= 0xFF)		/* x is already unsigned */

put_ilb(l)
	label l;
{
	if (fit8u(l))	{
		put8(sp_ilb1);
		put8((int)l);
	}
	else	{
		put8(sp_ilb2);
		put16(l);
	}
}

put_dlb(l)
	label l;
{
	if (fit8u(l))	{
		put8(sp_dlb1);
		put8((int)l);
	}
	else	{
		put8(sp_dlb2);
		put16(l);
	}
}

put_cst(l)
	arith l;
{
	if (l >= (arith) -sp_zcst0 && l < (arith) (sp_ncst0 - sp_zcst0)) {
		/*	we can convert 'l' to an int because its value
			can be stored in a byte.
		*/
		put8((int) l + (sp_zcst0 + sp_fcst0));
	}
	else
	if (fit16i(l)) { /* the cast from long to int causes no trouble here */
		put8(sp_cst2);
		put16((int) l);
	}
	else	{
		put8(sp_cst4);
		put32(l);
	}
}

put_doff(l, v)
	label l;
	arith v;
{
	if (v == 0)
		put_dlb(l);
	else	{
		put8(sp_doff);
		put_dlb(l);
		put_cst(v);
	}
}

put_noff(s, v)
	char *s;
	arith v;
{
	if (v == 0)
		put_dnam(s);
	else	{
		put8(sp_doff);
		put_dnam(s);
		put_cst(v);
	}
}

put_dnam(s)
	char *s;
{
	put8(sp_dnam);
	put_str(s);
}

put_pnam(s)
	char *s;
{
	put8(sp_pnam);
	put_str(s);
}

#ifdef	____
put_fcon(s, sz)
	char *s;
	arith sz;
{
	put8(sp_fcon);
	put_cst(sz);
	put_str(s);
}
#endif	____

put_wcon(sp, v, sz)	/* sp_icon, sp_ucon or sp_fcon with int repr	*/
	int sp;
	char *v;
	arith sz;
{
	/* how 'bout signextension int --> long ???	*/
	put8(sp);
	put_cst(sz);
	put_str(v);
}

put_str(s)
	char *s;
{
	register int len;

	put_cst((arith) (len = strlen(s)));
	while (--len >= 0)
		put8(*s++);
}

put_cstr(s)
	char *s;
{
	register int len = prepare_string(s);

	put8(sp_scon);
	put_cst((arith) len);
	while (--len >= 0)
		put8(*s++);
}