/*
********************************************************************************
File: bin2hex.c


Tab size:               4
Max line length:        80
Programmer:             Volker Kuhlmann


DESCRIPTION:

Converts binary input on stdin into hex output on stdout.

One (optional) argument:
  *) The first character will be printed for all characters in the
     range 0x00-0x1f and 0x80-0x9f, default = ' '.
  *) The second character (if != 0x00) will be printed for all
     characters in the range 0x80-0xff (this overrides the above), 
     default: 0x00.
  *) The third character will be printed for each 0x7f, default: ' '.
  *) If the fourth character is present, it selects a different output 
     format (hex only).

Compiles with UNIX gcc: gcc -O -o bin2hex bin2hex.c -I../include

Volker Kuhlmann


HISTORY:

1.3   09 Feb 1997	Ported to MSDOS. Fixed some bad things.
1.22  07 Feb 1997
1.2   30 May 1996
1.1   19 Mar 1995
1.0   25 Feb 1995

********************************************************************************
*/


#include <stdio.h>

#include "chelp.h"


string buffer[16];
char ctrldispchar  = ' ';       /* displayed for all 0x00-0x1f, 0x80-0x9f */
char ctrl8dispchar = '\0';      /* displayed for all 0x80-0xff if != \0 */
char deldispchar   = ' ';       /* displayed for 0x7f */

int outputformat = 0;


char conv_char(const unsigned char c);
void write_buffer(const byte num);
void hexascii_output (void);
void hex_output (void);
void parse_command_line (int argc, char *argv[]);


/*
	Convert one ASCII character - or leave it
*/
char conv_char(const unsigned char c)
{
	if ((c BITAND 0x80)  AND  (ctrl8dispchar != '\0'))
		return(ctrl8dispchar);
	if ((c BITAND 0x7f) >= 0x20)
		if (c == 0x7f)
			return(deldispchar);
		else
			return(c);
	else
		return(ctrldispchar);
}


/*
	ASCII output of up to 16, or up to num, characters in ASCII
*/
void write_buffer(const byte num)
{
byte i;

	for (i = 0; i < num; i++)
	{
		putchar(conv_char(buffer[i]));
		if (((i BITAND 0x3) == 0x3)  AND  (i < 15))
			putchar('|');
	}
	printf("\n");
}


/*
	Create a 2-column output, hex left and ascii right
*/
void hexascii_output (void)
{
byte b, num = 0;
int i;

	/* loop through the input */
	while ((i = getchar())  !=  EOF)
	{
		b = (byte)i;
		printf("%.2X ", b);
		buffer[num] = (char)b;
		if ((++num BITAND 0x03) == 0)
			putchar(' ');
		if ((num BITAND 0x0f) == 0)
		{
			putchar(' ');
			write_buffer(num);
			num = 0;
		}
	}
	/* Print ASCII part for last (possibly incomplete) line. 
	   Need not care for num == 0 because line is either empty 
	   or complete. */
	if (num > 0)
	{
		b = (16 - num) * 3  +  4 - (num / 4)  +  1;
		for (i = 0; i < b; i++)  putchar(' ');
		write_buffer(num);
	}
}


/*
	Create hex output only; no spaces, no line feeds
*/
void hex_output (void)
{
int i;

	/* loop through the input */
	while ((i = getchar())  !=  EOF)
		printf("%.2X", (byte)i);
}


/*
	Parse command line.

	If present, of first arg the characters become:
		1st -> ctrldispchar
		2nd -> ctrl8dispchar
		3rd -> deldispchar
	If 4th character exists, it selects different output format (hex only).
*/
void parse_command_line (int argc, char *argv[])
{
char *argptr;

	if (argc > 1)
		{
		argptr = argv[1];
		if (argptr[0] != 0x00)
		{
			ctrldispchar = argptr[0];
			if (argptr[1] != 0x00)
			{
				ctrl8dispchar = argptr[1];
				if (argptr[2] != 0x00)
					{
					deldispchar = argptr[2];
					if (argptr[3] != 0x00)
						outputformat = 1;
					}
			}
		}
		}
}


int main (int argc, char *argv[])
{
	parse_command_line(argc, argv);
	if (outputformat)
		hex_output();
	else
		hexascii_output();

	return 0;
}


/* EOF bin2hex.c */
/****************************************************************************/

