#include <stdlib.h>
#include <stdio.h>

/*

b2a.c  file

U.S.TTY/ITA2 to ASCII program. Reads from input file, outputs to stdout. Does only U.S. U.S.TTY/ITA2.
Automatically downshifts to LTRS case upon receipt of a space or CR.

IMPORTANT NOTE: It appears that Teletype reperfs internally flip end for end the bits in
combinations 1 through 26; table2[] below reflects this. table1[] is "straight" U.S.TTY/ITA2 to
ASCII.

Written for Borland C, but probably any C compiler will work.

Tom Jennings
mru 12 Nov 1998

*/

#define FIGS 27
#define LTRS 31

/* ASCII characters */

#define UU 127	/* untranslatable character */
#define NUL 0
#define LF 10
#define CR 13
#define BEL 7

/* U.S.TTY/ITA2 characters */

#define BCR 8
#define BSP 4

/* This table does the translation; it contains 64ASCII characters in U.S.TTY/ITA2 order. The table
is indexed by [U.S.TTY/ITA2 char + state]; state is set to 0 (first 32 chars, FIGS code set) or 32
(last 32 characters, LTRS code set) when a FIGS or LTRS character is dectected in the character
stream. */

char table1[] = {
/* LTRS */ 	NUL, 'E',  LF, 'A', ' ', 'S', 'I', 'U',  CR, 'D', 'R', 'J', 'N', 'F', 'C', 'K', 
		'T', 'Z', 'L', 'W', 'H', 'Y', 'P', 'Q', 'O', 'B', 'G',  UU, 'M', 'X', 'V', UU,
/* FIGS */  	NUL, '3',  LF, '-', ' ', BEL, '8', '7', CR, '$', '4', '\'', ',', '!', ':', '(', 
		'5', '"', ')', '2', '#', '6', '0', '1', '9', '?', '&',  UU, '.', '/', ';', UU };


/* Same as above but with printable characters' bits flipped! */

char table2[] = {
/* LTRS */ 	NUL, 'T',  LF, 'O', ' ', 'H', 'N', 'M',  CR, 'L', 'R', 'G', 'I', 'P', 'C', 'V', 
		'E', 'Z', 'D', 'B', 'S', 'Y', 'F', 'X', 'A', 'W', 'J',  UU, 'U', 'Q', 'K', UU,

/* FIGS */  	NUL, '5',  LF, '9', ' ', '#', ',', '.', CR, ')', '4', '&', '8', '0', ':', ';', 
		'5', '"', '$', '?', BEL, '6', '!', '/', '-', '2', '\'',  UU, '7', '1', '(', UU };

char state= 0;					/* assume initial LTRS state */
FILE *fi;					/* input file */
FILE *fo;					/* output file */
char fn[256];					/* outptu filename */

void b2a(int);
void mf(char *, char *, char *);


int
main(argc, argv)
int argc;
char *argv[];
{
int c;

	if (argc < 2) {
		fprintf (stderr, "b2a -- U.S.TTY/ITA2 to ASCII. 'b2a file.txt' converts U.S.TTY/ITA2 file to ASCII\n");
		fprintf (stderr, "and outputs to stdout. Tom Jennings tomj@wps.com\n");
		return(1);
	}
	if ((fi= fopen(argv[1], "rb")) == NULL) {	/* MODE = READ-ONLY, BINARY! */
		printf ("File %s doesn't exist!\n", argv[1]);
		exit(1);
	}
	mf(argv[1],fn,".asc");				/* make output file file.ASC */
	if ((fo= fopen(fn, "wb")) == NULL) {		/* MODE = WRITE, BINARY */
		fprintf (stderr, "Can't create file %s!\n", fn);
		fclose(fi);
		exit(2);
	}
	while ((c= fgetc(fi)) != EOF)			/* for each character in the input file, */
		b2a(c);					/* convert, output each char, */
	fclose(fi); fclose(fo);
	return(0);
}

/* Make a filename with specified extention. */

void
mf(in, out, ext)
char *in, *out, *ext;
{
	while (*out= *in++) {				/* copy filename characters */
		if (*out == '.') break;			/* up til the dot, if any */
		++out;
	}
	while (*out++= *ext++);				/* tack on extention */
}


/* Convert a U.S.TTY/ITA2 character to ASCII and output. This maintains the tiny state machine
that remembers the case. */

void
b2a(c)
int c;
{
	switch (c) {
		case FIGS: state= 32; return;		/* subsequent characters from FIGS case */
		case LTRS: state= 0; return;		/* subsequent characters from letters */

		case BSP: state= 0; goto def;		/* case shift down */
		case BCR: state= 0; 			/* case shift down */
def:;		default: c= table2[c + state]; 		/* lookup U.S.TTY/ITA2 character, */
			if (c == UU) break;		/* ignore intranslatable */
			if (fputc(c, fo) == EOF) {
				fprintf(stderr, "ERROR: Can't write to file %s! (disk full?)\n", fn);
				fclose(fi); fclose(fo); exit(3);
			}
			break;
	}
}

