/*  yabfi -- yet another brainfuck interpreter
 * 
 *  Copyright (C) 2004 Sascha Wilde
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *------------------------------------------------------------------------- 
 * 
 * this is a simple BF interpreter, does what one would expect...
 * 
 *-------------------------------------------------------------------------
 * $Id: yabfi.c,v 1.2 2004/06/14 17:13:44 wilde Exp $ */

#define MEMSIZE 30000

#include <err.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>

int
main(int argc,char** argv)
{
  int c, lc, fd;
  static struct stat fd_stat;
  char *src, *srcmin, *srcmax;
  unsigned char *p, *pmin, *pmax;

  if ( 2 != argc )
    err (1,"Usage: %s BF-SOURCE\n", argv[0]);

  if ((fd = open(argv[1], O_RDONLY)) == -1)
    err (1,"Cant open file: %s\n", argv[0]);

  (void) fstat (fd, &fd_stat);
  if ((src = srcmin = (char*) mmap (0, (size_t) fd_stat.st_size, 
				    PROT_READ, MAP_PRIVATE, fd, 0)) == (void*) -1)
    {
      close (fd);
      err (1, NULL);
    }
  close (fd);

  srcmax = srcmin + (fd_stat.st_size - 1);

  p = pmin = (unsigned char*) calloc(MEMSIZE, 1);
  pmax = pmin + (MEMSIZE - 1);

  while (src <= srcmax )
    {
      switch (*src)
	{
 	case '>': p++; 
 	  break; 
 	case '<': p--; 
 	  break; 
 	case '+': ++*p; 
 	  break; 
 	case '-': --*p; 
 	  break; 
	case '.': putchar(*p);
	  break;
	case ',': c = getchar();
	  if (c == EOF)
	    *p = 0;
	  else
	    *p = c;
	  break;
	case '[':
	  lc = 0;
	  if (*p == 0)
	    while ((*++src != ']') || (lc != 0))
	      if (*src == '[') 
		++lc;
	      else if (*src == ']')
		--lc;
	  break;
	case ']':
	  lc = 0;	
	  if (*p != 0)
	    while ((*--src != '[') || (lc != 0))
	      if (*src == ']') 
		++lc;
	      else if (*src == '[')
		--lc;
	  break;
	}
      if ((p < pmin) || (p > pmax))
	errx (2, "Range error in BF code!");
      ++src;
    }
  free (p);
}
