/*
 * esa4.c
 * Code and listing.
 */
#include <stdio.h>
#include "esa.h"

/*
 * Output a byte to the code buffer.
 * Also update `.'.
 */
codeb(b)
{
	if(cptr < &cbuf[CODEMAX])
		*cptr++ = b&0377;
	else
		err('z');
	if(pass && !nflag) {
		if(crec>=CRSIZE || cadr+crec!=dot->s_value) {
			cflush();
			cadr = dot->s_value;
		}
		crbf[crec++] = b;
	}
	++dot->s_value;
}

/*
 * Output a word (low byte first) to the code
 * buffer.
 */
codew(w)
{
	codeb(w);
	codeb(w>>8);
}

/*
 * Put an error into the error buffer.
 * If this error type is already there
 * just return.
 * Otherwise add it to the end.
 * It is a fatal error for the error
 * buffer to overflow.
 */
err(c)
{
	register char *p;

	p = ebuf;
	while(p < eptr)
		if(*p++ == c)
			return;
	if(p >= &ebuf[ERRMAX])
		error("Ebuf overflow\n");
	*p++ = c;
	eptr = p;
}

/*
 * Output the code collected in the code buffer
 * and the source line to the listing.
 * This routine is only called if the `-l' option
 * is present.
 * Note the great trouble caused by the signs on
 * the bytes being extended.
 */
outlisting()
{
	register int nbytes;
	register char *cp;
	int w1, w2, w3;

	if(listmode == NLIST)
		return;
	for(cp=eptr; cp<&ebuf[ERRMAX]; *cp++=' ')
		;
	if(listmode == SLIST)
		fprintf(lst, "%.10s      ", ebuf);
	else
		fprintf(lst, "%.10s %04x ", ebuf, listaddr);
	if(listmode == ALIST) {
		fprintf(lst, "%9s%6d %s\n", "", lineno, sbuf);
	} else {
		nbytes = cptr-cbuf;
		w1 = cbuf[0] & 0377;
		w2 = cbuf[1] & 0377;
		w3 = cbuf[2] & 0377;
		switch(nbytes) {

		case 0:
			fprintf(lst, "%9s", "");
			break;

		case 1:
			fprintf(lst, "%02x%7s", w1, "");
			break;

		case 2:
			fprintf(lst, "%02x %02x%4s", w1, w2, "");
			break;

		default:
			fprintf(lst, "%02x %02x %02x ", w1, w2, w3);
		}
		fprintf(lst, "%6d %s\n", lineno, sbuf);
		cp = &cbuf[3];
		while((nbytes -= 3) > 0) {
			fprintf(lst, "%16s", "");
			switch(nbytes) {

			case 1:
				w1 = cp[0] & 0377;
				fprintf(lst, "%02x\n", w1);
				break;

			case 2:
				w1 = cp[0] & 0377;
				w2 = cp[1] & 0377;
				fprintf(lst, "%02x %02x\n", w1, w2);
				break;

			default:
				w1 = cp[0] & 0377;
				w2 = cp[1] & 0377;
				w3 = cp[2] & 0377;
				fprintf(lst, "%02x %02x %02x\n", w1, w2, w3);
			}
			cp += 3;
		}
	}
}

/*
 * Output errors to the terminal.
 */
outerrors()
{
	register char *p;

	p = ebuf;
	while(p < eptr)
		printf("%c %04d\n", *p++, lineno);
}

/*
 * Flush the code buffer.
 */
cflush()
{
	register int i, c, csum;

	if(crec == 0)
		return;
	fprintf(esb, "%02x%02x %02x ", (cadr>>8)&0377, cadr&0377, crec);
	csum = 0;
	for(i=0; i<crec; ++i) {
		c = crbf[i]&0377;
		csum += c;
		fprintf(esb, "%02x", c);
	}
	fprintf(esb, " %02x%02x\n", csum&0377, (csum>>8)&0377);
	crec = 0;
}
