
#include <stdio.h>

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>

void syntax() {
	printf("Error\n");
}

char *buf;
int bufsize, bufpos, hasalnum;

void addbuf(char c) {
	if (bufpos >= bufsize) {
		bufsize += 4096;
		buf = (char*) realloc(buf, bufsize);
	}
	buf[bufpos++] = c;
	if (isalnum(c)) hasalnum = 1;
}

void clearbuf() {
	bufpos = 0;
	hasalnum = 0;
}

void printbuf() {
	if (bufpos <= 2 || !hasalnum) return;
	addbuf(0);
	printf("%s\n", buf);
}

char ebcdic[256] = 
	"          " "[.<(+!"
	"&         " "] *);^"
	"-/        " " ,%_>?"
	"         `" ":#@'=\""
	" abcdefghi" "      "
	" jklmnopqr" "      "
	"  stuvwxyz" "      "
	"          " " |    "
	" ABCDEFGHI" "      "
	" JKLMNOPQR" "      "
	"  STUVWXYZ" "      "
	"0123456789" "      ";

char toasc(char c) {
	char r = ebcdic[(unsigned char) c];
	if (r == ' ' && c != 0) return 0;
	return r;
}

int main(int argc, char** argv) {
	if (argc < 2) {
		syntax();
		return -1;
	}
	int fd = open(argv[1], O_RDONLY);
	if (fd < 0) {
		syntax();
		return -2;
	}
	struct stat s;
	if (fstat(fd, &s) < 0) {
		syntax();
		return -3;
	}
	size_t mmap_len = s.st_size;
	char *data = (char*) mmap(0, mmap_len, PROT_READ, MAP_PRIVATE, fd, 0);
	if ((int) data == -1) {
		syntax();
		return -4;
	}
	
	int bits = 0;
	char value = 0;
#define readbit(bit) do { if (bits < 8) bits++; value = (0x7f & (value >> 1)) | (bit << 7); } while(0)
	for (off_t i = 0; i < s.st_size; i++) {
		switch (data[i]) {
			case 'I':
				readbit(0);
				break;
			case 'C':
				readbit(1);
				break;
			case 'F':
				readbit(0);
				break;
			case 'P':
				if (bits == 8) {
					value = toasc(value);
					if (value)
						addbuf(value);
					else
						bits = 0;
				}
				if (bits != 8 && bufpos > 0) {
					printbuf();
					clearbuf();
				}
				bits = 0;
				value = 0;
				break;
			default:
				break;
		}
	}
	if (bufpos > 0) {
		printbuf();
		clearbuf();
	}

	for (off_t i = 0; i < s.st_size; i++) {
		switch (data[i]) {
			case 'I':
				while (++i < s.st_size) {
					switch (data[i]) {
						case 'C':
							if (bits == 8) {
								value = toasc(value);
								if (value) {
									addbuf(value);
									break;
								}
							}
						case 'I':
						case 'F':
						case 'P':
							if (bufpos > 0) {
								printbuf();
								clearbuf();
							}
							bits = 0;
							value = 0;
							break;
						default:
							continue;
					}
					break;
				}
				break;
			case 'C':
				readbit(0);
				break;
			case 'F':
				readbit(1);
				break;
			case 'P':
				readbit(0);
				break;
			default:
				break;
		}
	}
	munmap(data, mmap_len);
	return 0;
}

