/*
 *      fatal --- fatal error handler
 */
fatal(str)
char    *str;
{
	printf("%s\n",str);
	exit(-1);
}

/*
 *      error --- error in a line
 *                      print line number and error
 */
error(str)
char    *str;
{
	if(N_files > 1)
		printf("%s,",Argv[Cfn]);
	printf("\nError:   line:%d    %s\n", Line_num, str);
	printf("%s\n", Line);
	Err_count++;
}
/*
 *      warn --- trivial error in a line
 *                      print line number and error
 */
warn(str)
char    *str;
{
	if(N_files > 1)
		printf("%s,",Argv[Cfn]);
	printf("\nWarning: line:%d    %s\n", Line_num, str);
	printf("%s\n", Line);
}


/*
 *      delim --- check if character is a delimiter
 */
delim(c)
char    c;
{
	if( any(c," \t\n"))
		return(YES);
	return(NO);
}

/*
 *      skip_white --- move pointer to next non-whitespace char
 */
char *skip_white(ptr)
char    *ptr;
{
	while(*ptr==BLANK || *ptr==TAB)
		ptr++;
	return(ptr);
}

/*
 *      eword --- emit a word to code file
 */
eword(wd)
int     wd;
{
	emit(hibyte(wd));
	emit(lobyte(wd));
}

/*
 *      emit --- emit a byte to code file
 */
emit(byte)
{
	if (Debug) printf("Emit       %04x[%02x]\n", Pc, byte);

	if(Pass==1)
	{
		Pc++;
		return(YES);
	}

	if(P_total < P_LIMIT)
		P_bytes[P_total++] = byte;

	E_bytes[E_total++] = byte;
	Pc++;

	if(E_total == E_LIMIT) f_record();
}

/*
 *      f_record --- flush one line out in Motorola S or Intel Hex format
 *			or binary
 */
f_record()
{
	int i, chksum;
	int mapadr;

	if(Pass == 1) return;

	if(E_total==0)
	{
		E_pc = Pc;
		return;
	}

	chksum =  E_total;    /* total bytes in this record */
	chksum += lobyte(E_pc);
	chksum += E_pc>>8;

	/* record header preamble */
	if (Hexfil)
	{
		fprintf(Objfil,":");
		hexout(E_total);        /* byte count  */
	}
	else if (!Binfil) 		/* S record file */
	{
		chksum += 3;

		fprintf(Objfil,"S1");
		hexout(E_total+3);      /* byte count +3 */
	}

	if (Binfil)
	{
	    mapadr = E_pc;
	    for(i=0;i<E_total;i++) Memmap[mapadr++]=lobyte(E_bytes[i]);
	}
	else
	{
	    hexout(E_pc>>8);        	/* high byte of PC */
	    hexout(lobyte(E_pc));		/* low byte of PC */

	    if (Hexfil) hexout(0);		/* Output 00 */

	    for(i=0;i<E_total;i++)
	    {
		chksum += lobyte(E_bytes[i]);
		hexout(lobyte(E_bytes[i]));	/* data byte */
	    }

	    /* ones or twos complement checksum then output it */

	    chksum =~ chksum;
	    if (Hexfil) chksum++;

	    hexout(lobyte(chksum));

	    fprintf(Objfil,"\n");
	}
	E_pc = Pc;
	E_total = 0;
}

char    *hexstr = { "0123456789ABCDEF" } ;

hexout(byte)
int     byte;
{
	char hi,lo;

	byte = lobyte(byte);
	fprintf(Objfil,"%c%c",hexstr[byte>>4],hexstr[byte&017]);
}

/*
 * Init the memory image.
 */
imageinit()
{
	int i;
	for (i=0; i<=65535; i++) Memmap[i] = 0;
}

/*
 * Terminate the output file.
 */
finish_outfile ()
{
	int i;

	if (Binfil)	/* dump the binary bytes to the object file */
	{
		for (i=0; i<=65535; i++) fputc(Memmap[i], Objfil);
	}
	else if (Hexfil) fprintf(Objfil,":00000001FF\n");
	else fprintf(Objfil,"S9030000FC\n");
	fclose (Objfil);
}

/*
 *      print_line --- pretty print input line
 */
print_line()
{
	int     i;
	register char *ptr;

        printf ("%04d ",Line_num);

	if(P_total || P_force)
		printf("%04x",Old_pc);
	else
		printf("    ");

	for(i=0;i<P_total && i<6;i++)
		printf(" %02x",lobyte(P_bytes[i]));

	for(;i<6;i++) printf("   ");

	printf("  ");

	if(Cflag)
	{
		if(Cycles)
			printf("[%2d ] ",Cycles);
		else
			printf("      ");
	}
	ptr = Line;

	while( *ptr != '\n' )   /* just echo the line back out */
		putchar(*ptr++);

	for(;i<P_total;i++)
	{
		if( i%6 == 0 )
			printf("\n    ");
		printf(" %02x",lobyte(P_bytes[i]));
	}
	printf("\n");
}

/*
 *      any --- does str contain c?
 */
any(c,str)
char    c;
char    *str;
{
	while(*str != EOS)
		if(*str++ == c)
			return(YES);
	return(NO);
}

/*
 *      mapdn --- convert A-Z to a-z
 */
char mapdn(c)
char c;
{
	if( c >= 'A' && c <= 'Z')
		return(c+040);
	return(c);
}

/*
 *      lobyte --- return low byte of an int
 */
lobyte(i)
int i;
{
	return(i&0xFF);
}
/*
 *      hibyte --- return high byte of an int
 */
hibyte(i)
int i;
{
	return((i>>8)&0xFF);
}

/*
 *      head --- is str2 the head of str1?
 */
head(str1,str2)
char *str1,*str2;
{
	while( *str1 != EOS && *str2 != EOS){
		if( *str1 != *str2 )break;
		str1++;
		str2++;
		}
	if(*str1 == *str2)return(YES);
	if(*str2==EOS)
		if( any(*str1," \t\n,+-];*") )return(YES);
	return(NO);
}

/*
 *      alpha --- is character a legal letter
 */
alpha(c)
char c;
{
	if( c<= 'z' && c>= 'a' )return(YES);
	if( c<= 'Z' && c>= 'A' )return(YES);
	if( c== '_' )return(YES);
	if( c== '.' )return(YES);
	return(NO);
}
/*
 *      alphan --- is character a legal letter or digit
 */
alphan(c)
char c;
{
	if( alpha(c) )return(YES);
	if( c<= '9' && c>= '0' )return(YES);
	if( c == '$' )return(YES);      /* allow imbedded $ */
	return(NO);
}

/*
 *	white --- is character whitespace?
 */
white(c)
char c;
{
	if( c == TAB || c == BLANK || c == '\n' )return(YES);
	return(NO);
}

/*
 *	alloc --- allocate memory
 */
char *
alloc(nbytes)
int nbytes;
{
	char *malloc();

	return(malloc(nbytes));
}
