/* hexsum.c: quick&dirty to sum a file of %02x numbers */
/* these files are a standard way of interchanging 8-bit wide
 * data down 7-bit wide lines with noise (eg MVS,VM,TOPS-10).
 * each byte is 2 hex digits. any whitespace may occur around
 * bytes, but must not occur between the 2 hex digits (hits?)
 * of a byte.
 * this currently prints the sum of the bytes in hex
 */

#include <stdio.h>
#define FALSE 0

FILE *	winge;		/* where to show errors			*/
long	sum;		/* accumulate checksum here		*/
int	line;		/* 0-org current line number		*/
int	got1st;		/* boolean: TRUE==seen 1st of 2 hits	*/
int	hexbyte;	/* build up a byte value here		*/

main()
{
int	c;		/* a character				*/

	winge = stderr;
	line = 0;
	sum = 0;
	got1st = FALSE;
	while	((c=getchar())>=0)
	{
		if	(!iswhite(c))
		{	hexacc(c);
		}else{	if	(got1st)
			{	fprintf(winge,"whitespace within hexadecimal digits of byte");
				panic();
			};
		};
		if	(c=='\n')
		{	line++;
		};
	};
	if	(got1st)
	{	fprintf(winge,"odd number of hex digits");
		panic();
	};
	printf("%lx\n",sum);
}

hexacc(c)
int	c;
{
int	h;

	if	((h=hexconv(c))>=0)
	{	if	(got1st)
		{	hexbyte = (hexbyte<<4) | h;
			sum += hexbyte;
		}else{	hexbyte = h;
		};
		got1st = ! got1st;
	}else{	fprintf(winge,"char=%xx invalid",c);
		panic();
	};
}

panic()
{
	fprintf(winge,"\n\7line=%d.\n",line);
	exit(42);
};

int	hexconv(c)
int	c;
{
	c = tolower(c);
	if	(isdigit(c))
	{	c = c - '0';
	}else{	if	(c>='a' && c<='f')
		{	c = c-'a' + 10;
		}else{	c = -1;
		};
	};
	return(c);
}

iswhite(c)
int	c;
{
int	r;
char * index();

	r=index(" \t\n\r\b\f",c);
	return(r);
}

int	isdigit(c)
int	c;
{
int	r;
char * index();

	r=index("0123456789",c);
	return(r);
}

int	tolower(c)
int	c;
{
	if	(c<='Z' && c>='A')
	{	c = c-'Z'+'z';
	};
	return(c);
}

char * index(s,c)
char	*s;
char	c;
{
	while	(*s)
	{	if	( (*s++)==c )
		{	return(--s);
		};
	};
	return(0);
}

