/*
 * mr.c
 *
 * Mindrape.  This will hurt.
 *
 * (C) 2002 Kyle Donaldson <gile@gilex.net>
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#define MR_Y_LIMIT	64
#define MR_X_LIMIT	64
#define MR_Z_LIMIT	64
#define MR_LIMIT	(MR_Y_LIMIT * MR_X_LIMIT)
#define MR_POSI		((mr_pos_y * MR_Y_LIMIT) + mr_pos_x)

static int mr_ptr[MR_Z_LIMIT][MR_LIMIT];
static int mr_pos_y;
static int mr_pos_x;
static int mr_pos_z;
static char * mr_file;
static int mr_fpos;
static int mr_flen;

int mr_interpret (char);

static int mr_loop (void)
{
	register int end;
	register int bc = 0;
	for (end = mr_fpos; end < mr_flen; end++) {
		if (mr_file[end] == '{')
			bc++;
		else if (mr_file[end] == '}')
			bc--;
		if (bc == 0)
			break;
	}
	mr_fpos++;
	if (bc != 0) {
		fprintf(stderr, "mr: Unmatched '{' character (byte %d).\n", mr_fpos);
		return -1;
	}
	if (mr_ptr[mr_pos_z][MR_POSI] == 0) {
		mr_fpos = end;
		return 0;
	}
	do {
		bc = mr_fpos;
		while (mr_fpos < end) {
			if (mr_interpret(mr_file[mr_fpos]) != 0)
				break;
			mr_fpos++;
		}
		mr_fpos = bc;
	} while (mr_ptr[mr_pos_z][MR_POSI] != 0);
	mr_fpos = end;
	return 0;
}

int mr_interpret (char tch)
{
	char ch;
	register int i;
	register int len;
	switch (tch) {
		case 'L':
			mr_pos_x--;
			if (mr_pos_x < 0)
				mr_pos_x = (MR_X_LIMIT - 1);
			break;
		case 'R':
			mr_pos_x++;
			if (mr_pos_x >= MR_X_LIMIT)
				mr_pos_x = 0;
			break;
		case 'U':
			mr_pos_y--;
			if (mr_pos_y < 0)
				mr_pos_y = (MR_Y_LIMIT - 1);
			break;
		case 'D':
			mr_pos_y++;
			if (mr_pos_y >= MR_Y_LIMIT)
				mr_pos_y = 0;
			break;
		case 'B':
			mr_pos_z--;
			if (mr_pos_z < 0)
				mr_pos_z = (MR_Z_LIMIT - 1);
			break;
		case 'F':
			mr_pos_z++;
			if (mr_pos_z >= MR_Z_LIMIT)
				mr_pos_z = 0;
			break;
		case '+': mr_ptr[mr_pos_z][MR_POSI]++; break;
		case '-': mr_ptr[mr_pos_z][MR_POSI]--; break;
		case '{': return mr_loop(); break;
		case '}': fprintf(stderr, "mr: Unmatched '}' character (byte %d).\n", mr_fpos);
		case '>': putc(mr_ptr[mr_pos_z][MR_POSI], stdout); fflush(stdout); break;
		case '|': printf("%d", mr_ptr[mr_pos_z][MR_POSI] ); fflush(stdout); break;
		case '<':
			ch = getchar();
			if (ch == EOF)
				mr_ptr[mr_pos_z][MR_POSI] = 0;
			mr_ptr[mr_pos_z][MR_POSI] = ch;
			break;
	}
	return 0;
}

int main (int argc, char ** argv)
{
	register int i;
	register int p;
	FILE * fd;
	struct stat sb;
	mr_pos_x = 0;
	mr_pos_y = 0;
	mr_pos_z = 0;
	mr_fpos = 0;
	for (p = 0; p < MR_Z_LIMIT; p++)
		for (i = 0; i < MR_LIMIT; i++)
			mr_ptr[p][i] = 0;
	if (argc < 2) {
		fprintf(stderr, "Usage: %s file\n", argv[0]);
		exit(1);
	}
	fd = fopen(argv[1], "r");
	if (!fd) {
		fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
		exit(1);
	}
	stat(argv[1], &sb);
	mr_flen = sb.st_size;
	mr_file = malloc(mr_flen + 1);
	if (!mr_file) {
		fprintf(stderr, "mr: Out of memory loading file.\n");
		exit(1);
	}
	read(fileno(fd), mr_file, mr_flen);
	for (mr_fpos = 0; mr_fpos < mr_flen; mr_fpos++)
		mr_interpret(mr_file[mr_fpos]);
	fclose(fd);
	exit(0);
}

