Anonymous avatar Anonymous committed ad7fdac

Initial import of FBBI 1.0-2011.1003 sources.

Comments (0)

Files changed (27)

Empty file added.

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!-- encoding: UTF-8 -->
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>FBBI: The Flaming Bovine Befunge-98 Interpreter</title>
+  <!-- begin html doc dynamic markup -->
+  <script type="text/javascript" src="/contrib/jquery-1.4.1.min.js"></script>
+  <script type="text/javascript" src="/scripts/documentation.js"></script>
+  <link rel="stylesheet" type="text/css" href="/stylesheet/catseye.css" />
+  <link rel="stylesheet" type="text/css" href="/stylesheet/index.css" />
+  <link rel="stylesheet" type="text/css" href="/stylesheet/infopage.css" />
+  <!-- end html doc dynamic markup -->
+</head>
+<body>
+
+<h1>FBBI: The Flaming Bovine Befunge-98 Interpreter</h1>
+
+<p>Version 1.0.  Copyright ©1998-2011 Cat's Eye Technologies.  All rights reserved.</p>
+
+<h2>Introduction</h2>
+
+<p><dfn>FBBI</dfn> is an interpreter for the Befunge-98 language
+as defined by the <a href="http://catseye.tc/projects/funge98/">Funge-98 Final Specification</a>,
+written in 100% ANSI C, and placed under a BSD-style license.</p>
+
+<h3>Funge-98 Interpreter Information</h3>
+
+<p>FBBI's handprint is 0x46424249 ('FBBI').  FBBI v1.0 implements the fingerprints
+<a href="http://catseye.tc/projects/funge98/library/NULL.html">0x4e554c4c NULL</a>
+and <a href="http://catseye.tc/projects/funge98/library/ROMA.html">0x524f4d41 ROMA</a>.</p>
+
+<h3>Usage</h3>
+
+<p>See the header comment of <code><a href="../src/fbbi.c">fbbi.c</a></code> for
+definitive information about usage.</p>
+
+<h3>History</h3>
+
+<p>This is version 1.0 of the Flaming Bovine Befunge-98 Interpreter.
+See the header comment of <code><a href="../src/fbbi.c">fbbi.c</a></code> for
+definitive version history information.</p>
+
+<h3>Conformancy and Implementation Notes</h3>
+
+<p>Due to the nature of reality, this list may not be complete.</p>
+
+<ul>
+<li>Modulo the lovely ambiguities in the Funge-98 Final Specification, this version of FBBI appears to conform to it.</li>
+<li>Perhaps more materially, this version of FBBI substantially passes the <a class="external" href="http://users.tkk.fi/~mniemenm/befunge/mycology.html">Mycology</a>
+    test suite.  See the header comment of <code><a href="../src/fbbi.c">fbbi.c</a></code> for detailed information.</li>
+<li>Because FBBI is written in ANSI C, end-of-line sequences which consist of a single CR
+    may not be readable on MS-DOS machines.  FBBI's strict ANSI policy can be undefined
+    in <code>config.h</code>, in which case it should compile to use binary file mode under MS-DOS.</li>
+<li>The stack stack, and each stack, is of a user-specified size, not dynamic.</li>
+<li><code>A-Z</code> semantic stacks are limited to 26 overloads each.</li>
+<li><code>h</code>, <code>l</code>, and <code>m</code> are all Trefunge-specific, and thus are not implemented
+    in FBBI, because FBBI only implements Befunge-98.</li>
+<li>FBBI does not implement Concurrent Funge, so <code>t</code> is not implemented either.</li>
+<li>The C source code for the interpreter should be 100% ANSI C (except where noted above
+in regards to CR as a sole end-of-line marker on MS-DOS systems.)</li>
+<li>Compliation of this version of FBBI has been tested only under gcc 4.4.5 on Ubuntu 10.10.</li>
+</ul>
+
+<h3>Included Befunge-98 Example Programs</h3>
+
+<ul>
+<li>
+  <code>eg/binary.b98</code>
+  <p>Tests to see if reading a file in, binary-mode, actually works.</p>
+</li>
+<li>
+  <code>eg/finger.b98</code>
+  <p>Demonstrates NULL and ROMA fingerprints with <code>(</code> and <code>)</code>.</p>
+</li>
+<li>
+  <code>eg/hello.b98</code>
+  <p>Demonstrates SGML-style spaces in stringmode.</p>
+</li>
+<li>
+  <code>eg/randdna.b98</code>
+  <p>Perfect for synthesizing random organisms!</p>
+</li>
+<li>
+  <code>eg/script.b98</code>
+  <p>Demonstrates FBBI's -script command line option.</p>
+</li>
+<li>
+  <code>eg/cgi.b98.cgi</code>
+  <p>Another Befunge-98 script; this one should run as a CGI.</p>
+</li>
+<li>
+  <code>eg/trim-out.b98</code>
+  <p>Tests to see if writing a files strips trailing spaces and newlines.</p>
+</li>
+<li>
+  <code>eg/under.b98</code>
+  <p>Test for <code>u</code> and storage offset.</p>
+</li>
+</ul>
+
+<h3>Acknowledgements</h3>
+
+<p>Thanks to Sam Holden for providing the initial version of the Makefile.</p>
+
+<p>Thanks to Jeffrey Lee for providing his bug-fixing patches.</p>
+
+<p>Thanks to all those on the Befunge and/or Esolang mailing lists for their bug reports, the fixes for which made their way into patches.</p>
+
+<p>Thanks to Matti Niemenmaa for writing the Mycology Befunge-98 test suite.</p>
+
+</body>
+</html>
+>>>>>>>>>>551100"txt.f"ov
+abcdefghij              1
+bcdefghija              1
+cdefghijba              1
+defghijabc              0
+efghijabcd              "
+fghijabcde              t
+ghijabcdef              x
+hijabcdefg              t
+ijabcdefgh              .
+jabcdefghi              f
+abcdefghij              "
+vi                      <
+>000p>00g1g.00g1+:00p5a*-#v_@
+     ^                    <
+# Tests to see if reading a file in, binary-mode, actually works.
+#!/home/pangea/users/cats-eye/bin/fbbi -script /home/pangea/users/cats-eye/www/funge/fbbi/cgi.b98.cgi
+                            v
+v"Content-type: text/html"aa<
+>:#,_                                            v
+                                                v?v
+v"<H1>Nothing happens here.</H1>"               <
+ v"<H1>Hello, funger!</H1>"                      <
+  v"<H1>This space intentionally left blank.</H1>"<
+>>>:#,_                                          v
+v" a peek at the <a href=cgi.b98.txt>source</a>."<
+<v"Try <a href=cgi.b98.cgi>reloading</a> this page. Or take"
+>>>:#,_                                          @
+
+v ; demonstration of fingerprints. ;
+  ; correct results should be: '0 1000 !' ;
+
+  ; normally M does nothing. ;
+
+>#vM'?,v
+v.<    <
+
+  ; but, in the context of ROMA: ;
+
+>"AMOR"4( >#vM  >.)v
+            >'?,^
+v                  <
+
+  ; and in overlapping contexts (NULL in ROMA): ;
+
+>"AMOR"4( "LLUN"4( >#vM'?,> ) ) @
+                     > '!,^
+'H,25*"!dlrow      ,olle">:#,_q
+>>#v?v
+^,A' <
+ ^ C'
+    T
+ ^ <<
+    G
+    '
+
+#/fbbi/dos/fbbi.exe -script /fbbi/eg/script.b98
+# Hey, check this out.
+# if you execute fbbi.exe with the -script option,
+# all the inital lines that begin with # are skipped
+# over.  They're *still* loaded into Funge-Space,
+# they're just not executed.
+vv            <
+# this one is, though.
+@<            
+v
+>a"!olleH"6k, ^
+>>>>>>>>>>551110"txt.o"o@
+ bcdef
+ cd
+ d
+ 
+ 
+
+# Tests to see if writing a files strips trailing spaces and newlines.
+      12345  3{... 2u .. 2u .. 0} v
+v                               ,a<
+>  0{ 12345  3{... 2u .. 2u .. 0} v
+v                               ,a<
+>     24 02-u 0} 00g,   a,        @
+
+# Test for u and storage offset.  Should print:
+5 4 3 0 0 1 2 
+5 4 3 5 2 1 2 
+{
+# Thanks to Sam Holden for providing the original version of this Makefile.
+
+CC?=gcc
+BIN?=../bin/fbbi
+DEBUGFLAGS?=
+#DEBUGFLAGS?=-DFBBI_DEBUG -DDEBUG_STACK
+CFLAGS?=-ansi -pedantic -g -Wall -O $(DEBUGFLAGS)
+OBJECTS= \
+	bf98spc.o  \
+	f98fp.o    \
+	f98i.o     \
+	f98ip.o    \
+	f98stack.o \
+	fbbi.o     \
+	fp/NULL.o  \
+	fp/ROMA.o  \
+
+all: fbbi
+
+fbbi: $(OBJECTS)
+	$(CC) -o$(BIN) $(OBJECTS)
+
+strip: $(BIN)
+	strip $(BIN)
+
+clean:
+	rm -f *.o
+	rm -f fp/*.o
+/*
+   bf98spc.c v1.0 May 2011 Chris Pressey
+   Dynamic Befunge-Space ANSI C Functions - source.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+   Why use this package?
+   - It's ANSI C
+   - You need to store a large, dynamically allocated,
+       Cartesian 2D space with 32-bit addressing and 32-bit cell data
+   - You don't care about dynamic 1D, 3D etc spaces.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bf98spc.h"
+
+/* internal functions */
+
+keytree * find_keytree(keytree * k, signed long int key_x, signed long int key_y, int * found)
+{
+  int compare = 0;
+  keytree * l = k;
+
+  *found = 0;
+
+  if (l != NULL)
+  {
+    while (1)
+    {
+      compare = (l->key_x == key_x ? l->key_y - key_y : l->key_x - key_x);
+      if (compare > 0)
+      {
+	if (l->right != NULL)
+	{
+	  l = l->right;
+	} else
+	{
+	  return l;
+	}
+      } else
+      if (compare < 0)
+      {
+	if (l->left != NULL)
+	{
+	  l = l->left;
+	} else
+	{
+          /* This space intentionally left blank. */
+	  return l;
+	}
+      } else
+      {
+	*found = 1;
+	return l;
+      }
+    }
+  } else
+  {
+    return NULL;
+  }
+  return l;
+}
+
+void destroy_keytree (keytree * k)
+{
+  if (k != NULL)
+  {
+    destroy_keytree (k->left);
+    k->left = NULL;
+    destroy_keytree (k->right);
+    k->right = NULL;
+    free(k->data);
+    free(k);
+  }
+}
+
+/* exported functions */
+
+signed long int bfspace_fetch (bfspace * p, signed long int x, signed long int y)
+{
+  keytree * k;
+  int found;
+
+  k = find_keytree(p->root, (x >> SNIPPET_BITS), (y >> SNIPPET_BITS), &found);
+  if (found)
+  {
+    if (k != NULL)
+    {
+      x = (x & SNIPPET_MASK);
+      y = (y & SNIPPET_MASK);
+      return k->data->space[(x << SNIPPET_BITS) + y];
+    } else
+    {
+      return 32;
+    }
+  } else
+  {
+    /* Hello, sailor! */
+    return 32;
+  }
+}
+
+int bfspace_store (bfspace * p, signed long int x, signed long int y, signed long int data)
+{
+  keytree * n;
+  keytree * k;
+  int found, i;
+
+  n = (keytree *)malloc(sizeof(keytree));
+  n->left = NULL;
+  n->right = NULL;
+  n->key_x = x >> SNIPPET_BITS;
+  n->key_y = y >> SNIPPET_BITS;
+
+  k = p->root;
+  if (k == NULL)
+  {
+    /* add as root. */
+    p->root = n;
+    n->data = (snippet *)malloc(sizeof(snippet));
+    for (i = 0; i < (SNIPPET_SIZE*SNIPPET_SIZE); i++)
+    {
+      n->data->space[i] = 32;
+    }
+    if (x > p->max_x) p->max_x = x;
+    if (x < p->min_x) p->min_x = x;
+    if (y > p->max_y) p->max_y = y;
+    if (y < p->min_y) p->min_y = y;
+    x = (x & SNIPPET_MASK);
+    y = (y & SNIPPET_MASK);
+    n->data->space[(short)(x << SNIPPET_BITS) + (short)(y)] = data;
+    return 1;
+  } else
+  {
+    k = find_keytree(k, n->key_x, n->key_y, &found);
+    if (found)
+    {
+      if (k != NULL)
+      {
+	if (x > p->max_x) p->max_x = x;
+	if (x < p->min_x) p->min_x = x;
+	if (y > p->max_y) p->max_y = y;
+	if (y < p->min_y) p->min_y = y;
+	x = (x & SNIPPET_MASK);
+	y = (y & SNIPPET_MASK);
+	k->data->space[(short)(x << SNIPPET_BITS) + (short)(y)] = data;
+	free (n);
+	return 1;
+      } else
+      {
+	return 0;
+      }
+    } else
+    {
+      if (((k->key_x == n->key_x ? k->key_y - n->key_y : k->key_x - n->key_x) < 0) && (k->left == NULL))
+      {
+	k->left = n;
+      } else
+      if (((k->key_x == n->key_x ? k->key_y - n->key_y : k->key_x - n->key_x) > 0) && (k->right == NULL))
+      {
+	k->right = n;
+      } else
+      {
+	/* we'd be really, really screwed, but luckily this never seems to happen */
+	return 0;
+      }
+      n->data = (snippet *)malloc(sizeof(snippet));
+      for (i = 0; i < (SNIPPET_SIZE*SNIPPET_SIZE); i++)
+      {
+	n->data->space[i] = 32;
+      }
+      if (x > p->max_x) p->max_x = x;
+      if (x < p->min_x) p->min_x = x;
+      if (y > p->max_y) p->max_y = y;
+      if (y < p->min_y) p->min_y = y;
+      x = (x & SNIPPET_MASK);
+      y = (y & SNIPPET_MASK);
+      n->data->space[(short)(x << SNIPPET_BITS) + (short)(y)] = data;
+      return 1;
+    }
+  }
+}
+
+int bfspace_inbounds (bfspace * p, signed long int x, signed long int y)
+{
+  /* "You can't tell a squid." -- Old Canadian saying */
+  return ((x <= p->max_x) && (x >= p->min_x) &&
+	  (y <= p->max_y) && (y >= p->min_y));
+}
+
+/* might as well pass a NULL for p, nothing is done with it */
+bfspace * bfspace_alloc (bfspace * p)
+{
+  bfspace * n;
+  n = (bfspace *)malloc(sizeof(bfspace));
+  n->root = NULL;
+  n->max_x = -MAXLONG;
+  n->min_x = MAXLONG;
+  n->max_y = -MAXLONG;
+  n->min_y = MAXLONG;
+  p = p;
+  return n;
+}
+
+void bfspace_free (bfspace * p)
+{
+  destroy_keytree(p->root);
+  free(p);
+}
+
+int bfspace_fread (bfspace * p, FILE * f,
+                   signed long int x, signed long int y,
+                   signed long int * w, signed long int * h,
+                   unsigned long int flags)
+{
+  signed long int col = x;
+  signed long int row = y;
+  signed long int a = 0;
+
+  /* Efficiency at any cost! */
+
+  *w = 0;  *h = 0;
+
+  while (!feof (f))
+  {
+    a = (long) 0 | fgetc(f);
+    if ( ((a == (long)0x0a) || (a == (long)0x0d)) &&
+         ((flags & (long)0x01) != (long)0x01) )
+    {
+      if (a == (long)'\x0d')
+      {
+        /* next char might be \x0a, and if so, suck it up too. */
+        a = (long) 0 | fgetc(f);
+        if (a != (long)'\x0a') ungetc(a, f);
+      }
+      col = x;
+      row++;  if ((row-y) > *h) *h = (row-y);
+    } else
+    {
+      if (!feof(f))
+      {
+        if (a != ' ')
+        {
+	  if (!(bfspace_store(p, col++, row, a))) return 0;
+          if ((col-x) > *w) *w = (col-x);
+        } else
+        {
+          col++;
+        }
+      }
+    }
+  }
+  (*h)++; /* bugfix 2003.0726 correct number of lines (= newlines + 1) */
+  return 1;
+}
+
+int bfspace_fwrite (bfspace * p, FILE * f, signed long int x, signed long int y,
+			signed long int w, signed long int h, unsigned long int flags)
+{
+  signed long int col = x;
+  signed long int row = y;
+  signed long int a = 0;
+
+  signed long spccnt = 0;
+  signed long i = 0;
+
+  while ((row-y) < h)
+  {
+    a = bfspace_fetch(p, col++, row);
+    spccnt=0;
+    while (a == ((long)0|' ') && (col-x) <= w)
+    {
+      spccnt++;
+      a = bfspace_fetch(p, col++, row);
+    }
+    /* begin bugfix 2003.0722: compressed vs non-compressed text output */
+    if ((col-x) > w)                        /* if we are past the right edge */
+    {
+      if ((flags & (long)0x1) == (long)0x1) /* and we are compressing text */
+      {
+	/* print nothing */
+      } else
+      {
+	/* print spaces only */
+        for(i=0;i<spccnt;i++) fputc(' ', f);
+      }
+    } else
+    {
+      /* print spaces, then character */
+      for(i=0;i<spccnt;i++) fputc(' ', f);
+      fputc((char)a, f);
+    }
+    /* end bugfix 2003.0722 */
+    if (col-x > w)
+    {
+      col = x;
+      row++;
+      fputc('\n', f);
+    }
+  }
+  return 1;
+}
+/*
+   bf98spc.h for bf98spc.c v1.0 May 2011 Chris Pressey
+   Dynamic Befunge-Space ANSI C Functions - header.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef _BF98SPC_H_
+#define _BF98SPC_H_
+
+#ifndef _WIN32
+  #ifndef __FreeBSD__
+    #include <values.h>
+  #endif
+#endif
+
+#ifndef MAXLONG
+  #define MAXLONG ((long)0x7fffffff)
+#endif
+
+/* The engine allocates the playfield in chunks of
+   2^SNIPPET_BITS x 2^SNIPPET_BITS.  4 seems to be a good
+   value (16x16x4=1024=1kbyte.)  Although you'll want to
+   take this down if storage is unusually sparse,
+   and bump it up if it's unusually compact. */
+
+#define SNIPPET_BITS 4
+
+#define SNIPPET_SIZE (1 << SNIPPET_BITS)
+#define SNIPPET_MASK (SNIPPET_SIZE - 1)
+
+/* internal storage definition of a 'snippet' (nxn chunk of space). */
+typedef struct Snippet
+{
+  signed long int space[SNIPPET_SIZE * SNIPPET_SIZE];
+} snippet;
+
+/* internal storage definition of a key tree node or leaf. */
+/* each node points to a single snippet of the playfield */
+typedef struct KeyTree
+{
+  signed long int key_x;
+  signed long int key_y;
+  snippet * data;
+  struct KeyTree * left;  /* xys less than xy */
+  struct KeyTree * right; /* xys greater than xy */
+} keytree;
+
+typedef struct BefungeSpace
+{
+  signed long int max_x, max_y, min_x, min_y;
+  keytree * root;
+} bfspace;
+
+extern bfspace *     bfspace_alloc (bfspace * p);
+extern signed long int bfspace_fetch (bfspace * p, signed long int x, signed long int y);
+extern int             bfspace_store (bfspace * p, signed long int x, signed long int y, signed long int data);
+extern int             bfspace_inbounds (bfspace * p, signed long int x, signed long int y);
+extern void            bfspace_free  (bfspace * p);
+extern int             bfspace_fread (bfspace * p, FILE * f, signed long int x, signed long int y,
+                        signed long int * w, signed long int * h, unsigned long int flags);
+extern int	       bfspace_fwrite (bfspace * p, FILE * f, signed long int x, signed long int y,
+			signed long int w, signed long int h, unsigned long int flags);
+
+#endif  /* _BF98SPC_H_ not defined */
+/*
+   config.h for fbbi.c v1.0 May 2011 Chris Pressey
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef _FBBI_CONFIG_H_
+#define _FBBI_CONFIG_H_
+
+/* Change these to your taste and recompile FBBI */
+
+#define DEFAULT_STACK_SIZE        2048   /* cells */
+#define DEFAULT_STACKSTACK_SIZE   256    /* stacks */
+
+/* Comment this line to violate ANSI C and try to compile */
+/* the platform-specific features of FBBI (such as CR EOLs */
+/* under MS-DOS. */
+
+#define FBBI_ANSI
+
+/* Remove these comments to compile FBBI with gobs upon gobs */
+/* of diagnostic output - not generally useful unless it crashes */
+/* on your system. */
+
+/* #define FBBI_DEBUG */
+
+#endif /* _FBBI_CONFIG_H_ not defined */
+/*
+   f98fp.c for fbbi.c v1.0 May 2011 Chris Pressey
+   Funge-98 Fingerprints - source.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <stdio.h>
+
+#include "fbbi.h"
+#include "bf98spc.h"
+#include "f98ip.h"
+#include "f98i.h"
+#include "f98fp.h"
+#include "fp/index.h"
+
+cell get_fingerprint(ip * i)
+{
+  i->b = 0;
+  i->a = ip_pop(i);
+  for(;i->a > 0;i->a--)
+  {
+    i->b <<= 8;
+    i->b += ip_pop(i);
+  }
+  return i->b;
+}
+
+#ifndef FBBI_MINIMAL
+
+void save_semantics(ip * i, char c) /* save the semantics of instruction c */
+{
+  if ((c >= 'A') && (c <= 'Z')) /* bugfix 2003.0726 Ensure semantics are saved */
+    i->fingins[c-'A'][++i->finglev[c-'A']] = instable[c-' '];
+}
+
+void restore_semantics(ip * i, char c) /* restore the last saved semantics of c */
+{
+  if ((c >= 'A') && (c <= 'Z') && (i->finglev[c-'A'] > 0))
+    instable[c-' '] = i->fingins[c-'A'][i->finglev[c-'A']--];
+}
+
+void bind_semantics(ip * i, char c, void (*b)(ip *)) /* bind c to b() */
+{
+  instable[c-' '] = b;
+  i = i;
+}
+
+void overload_semantics(ip * i, char c, void (*b)(ip *)) /* save c, bind c to b() */
+{
+  save_semantics(i, c);
+  bind_semantics(i, c, b);
+}
+
+int fingerprint_semantics(ip * i, cell fp, int load)
+{
+  int k=0;
+  if (fp==0) return 0;
+  while(1)
+  {
+    if (library[k].fingerprint == fp)
+    {
+      library[k].semantics(i, load);
+      return 1;
+    }
+    if (!library[k++].fingerprint) break;
+  }
+  return 0;
+}
+
+#endif
+/*
+   f98fp.h for f98fp.c v1.0 May 2011 Chris Pressey
+   Funge-98 Fingerprints - header.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef _F98FP_H_
+#define _F98FP_H_
+
+extern cell get_fingerprint(ip * i);
+
+#ifndef FBBI_MINIMAL
+
+/* save the semantics of instruction c */
+extern void save_semantics(ip * i, char c);
+
+/* restore the last saved semantics of c */
+extern void restore_semantics(ip * i, char c);
+
+/* bind c to b() */
+extern void bind_semantics(ip * i, char c, void (*b)(ip *));
+
+/* save c, bind c to b() */
+extern void overload_semantics(ip * i, char c, void (*b)(ip *));
+
+/* load a fingerprint */
+extern int  fingerprint_semantics(ip * i, cell fp, int load);
+
+#endif
+
+#endif /* _F98FP_H_ not defined */
+/*
+   f98i.c for fbbi.c v1.0 May 2011 Chris Pressey
+   Funge-98 Instructions - source.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "fbbi.h"
+#include "bf98spc.h"
+#include "f98ip.h"
+#include "f98i.h"
+#include "f98fp.h"
+
+extern char ** environ;
+extern char ** global_argv;
+extern int global_argc;
+extern int fungeprog_arg;
+
+/*-- INSTRUCTIONS */
+
+void fi_space  (ip * i) { i = i; /* THIS NEVER HAPPENS */ }
+void fi_nop    (ip * i) { fi_space(i); }
+void fi_reverse(ip * i) { NEG(i->dx); NEG(i->dy); }
+
+void fi_die    (ip * i) { i->hm = 1; i->ec = 0; }
+void fi_quit   (ip * i) { i->hm = 1; i->ec = ip_pop(i); }
+
+void fi_digit  (ip * i) { ip_push(i, i->ir - '0'); }
+void fi_hexdig (ip * i) { ip_push(i, i->ir - 'a' + 10); }
+
+void fi_north  (ip * i) { DELTA(i,0,-1); }
+void fi_south  (ip * i) { DELTA(i,0,1); }
+void fi_east   (ip * i) { DELTA(i,1,0); }
+void fi_west   (ip * i) { DELTA(i,-1,0); }
+
+void fi_vertif (ip * i)
+{
+  i->dx = 0;
+  if (ip_pop(i) != 0)
+    i->dy = -1; else
+    i->dy = 1;
+}
+void fi_horzif (ip * i)
+{
+  i->dy = 0;
+  if (ip_pop(i) != 0)
+    i->dx = -1; else
+    i->dx = 1;
+}
+void fi_add    (ip * i) { ip_push(i, ip_pop(i) + ip_pop(i)); }
+void fi_sub    (ip * i) { GET_ab(i); ip_push(i, i->b - i->a); }
+void fi_mul    (ip * i) { ip_push(i, ip_pop(i) * ip_pop(i)); }
+void fi_div    (ip * i) { GET_ab(i); if (i->a != 0) ip_push(i, i->b / i->a); else ip_push(i, 0); }
+void fi_mod    (ip * i) { GET_ab(i); if (i->a != 0) ip_push(i, i->b % i->a); else ip_push(i, 0); }
+void fi_swap   (ip * i) { GET_ab(i); ip_push(i, i->a); ip_push(i, i->b); }
+void fi_string (ip * i) { i->sm = !i->sm; }
+void fi_odec   (ip * i)
+{
+  i->b = 0;
+  #ifndef FBBI_MINIMAL
+  if (trace)
+    i->b = printf ("***** Decimal: %ld\n", ip_pop(i)); else
+  #endif
+    i->b = printf ("%ld ", ip_pop(i));
+  fflush (stdout);
+  if (i->b == EOF) ip_reverse(i);
+}
+
+void fi_ochar  (ip * i)
+{
+  GET_a(i);
+  i->b = 0;
+  #ifndef FBBI_MINIMAL
+  if (trace)
+    i->b = printf ("***** Character: 0x%08lx ('%c')\n", i->a, PRINT(i->a)); else
+  #endif
+    i->b = printf ("%c", (char)i->a);
+  fflush (stdout);
+  if (i->b == EOF) ip_reverse(i);
+}
+
+void fi_dup    (ip * i) { GET_a(i); ip_push(i, i->a); ip_push(i, i->a);  }
+void fi_not    (ip * i) { if (ip_pop(i) != 0) ip_push(i, 0); else ip_push(i, 1); }
+void fi_greater(ip * i) { GET_a(i); if (ip_pop(i) > i->a) ip_push(i, 1); else ip_push(i, 0); }
+void fi_ramp   (ip * i) { ip_march(i); }
+void fi_char   (ip * i) { ip_march(i); ip_push(i, bfspace_fetch(i->bs, i->x, i->y)); }
+void fi_store  (ip * i) { ip_march(i); bfspace_store(i->bs, i->x, i->y, ip_pop(i)); }
+void fi_pop    (ip * i) { GET_a(i); }
+void fi_away   (ip * i)
+{
+  DELTA(i,0,1);
+  switch ((rand() / 32) % 4)
+  {
+    case 0: DELTA(i,1,0); break;
+    case 1: DELTA(i,-1,0); break;
+    case 2: i->dy=-1;
+  }
+}
+
+void fi_idec   (ip * i)
+{
+  fflush(stdin);
+  do
+  {
+    i->a = (long)0|fgetc(stdin);
+    if ((i->a >= '0') && (i->a <= '9')) ungetc(i->a, stdin);
+  } while ((i->a < '0') || (i->a > '9'));
+
+  if(scanf ("%ld", &i->a) != EOF)
+  {
+    ip_push(i, i->a);
+  } else
+  {
+    ip_reverse(i);
+  }
+}
+
+void fi_ichar  (ip * i)
+{
+  fflush(stdin);
+  i->a = (long)0 | fgetc(stdin);
+  if (i->a != ((long)0 | EOF))
+  {
+    ip_push(i, i->a);
+  } else
+  {
+    ip_reverse(i);
+  }
+}
+
+void fi_get    (ip * i) { GET_a(i); ip_push(i, bfspace_fetch(i->bs, ip_pop(i)+i->sx, i->a+i->sy)); }
+void fi_put    (ip * i) { GET_ab(i); bfspace_store(i->bs, i->b+i->sx, i->a+i->sy, ip_pop(i)); }
+
+void fi_skip   (ip * i) { i = i; /* THIS NEVER HAPPENS */ }
+
+void fi_rleft  (ip * i) { i->a = i->dy; i->dy = -1 * i->dx; i->dx = i->a; }
+void fi_rright (ip * i) { i->a = i->dx; i->dx = -1 * i->dy; i->dy = i->a; }
+void fi_jump   (ip * i) { GET_a(i); i->x += i->dx * i->a; i->y += i->dy * i->a; }
+void fi_clear  (ip * i) { ip_clearstack(i); }
+void fi_compare(ip * i)
+{
+  GET_ab(i);
+  if (i->a > i->b)
+     fi_rleft(i); else
+    if (i->a < i->b)
+      fi_rright(i);
+}
+void fi_delta  (ip * i) { i->dy = ip_pop(i); i->dx = ip_pop(i); }
+void fi_under  (ip * i)
+{
+  cell f;
+  GET_a(i);
+  if (ip_stacks_measure(i) <= 1)
+  {
+    ip_reverse(i);
+  } else if (i->a > 0)
+  {
+    for (i->b = 0; i-> b < i->a; i->b++)
+    {
+      f = ip_pop_soss(i);
+      ip_push(i, f);
+    }
+  } else if (i->a < 0)
+  {
+    for (i->b=0;i->b > i->a;i->b--)
+    {
+      ip_push_soss(i, ip_pop(i));
+    }
+  }
+}
+void fi_begin (ip * i)
+{
+  GET_a(i);
+  /* Regardless of sign of popped value, push new stack on SS */
+  if (!ip_allocstack(i))
+  {
+    ip_reverse(i);
+    return;
+  }
+  if (i->a<0)
+  {
+    /* Negative argument to { pushes |n| 0s onto the SOSS */
+    while(i->a < 0)
+    {
+      ip_push_soss(i, 0);
+      i->a++;
+    }
+  } else if (i->a > 0) ip_transfer(i, i->a);
+  ip_push_soss(i, i->sx);
+  ip_push_soss(i, i->sy);
+  i->sx = i->x + i->dx;
+  i->sy = i->y + i->dy;
+  /*printf("$$$ EXECUTING 'BEGIN': assigned storage offset %ld, %ld\n", i->sx, i->sy);*/
+}
+
+void fi_end   (ip * i)
+{
+  /* check if there *is* a SOSS very first */
+  if (ip_stacks_measure(i) <= 1)
+  {
+    ip_reverse(i);
+    return;
+  }
+  GET_a(i);
+  if (i->a<0)
+  {
+    /* Negative argument to } destroys top |n| values on the SOSS. */
+    if(ip_stacks_measure(i) > 1)
+    {
+      while(i->a < 0)
+      {
+        ip_pop_soss(i);
+        i->a++;
+      }
+    }
+  }
+  /* bugfix 2003.0722: } should still attempt to pop the TOSS */
+  i->sy = ip_pop_soss(i);
+  i->sx = ip_pop_soss(i);
+  if (i->a > 0) ip_transfer(i, -1 * i->a);
+  ip_freestack(i);
+  /*printf("$$$ EXECUTING 'END': restored storage offset %ld, %ld\n", i->sx, i->sy);*/
+}
+
+void fi_in    (ip * i)
+{
+  cell c, d, flags;
+  FILE *f; char s[256];
+
+  ip_pop_string(i, s);
+  flags = ip_pop(i);
+  GET_ab(i);
+
+  if((f=fopen(s, "r"))!=NULL)
+  {
+    bfspace_fread(i->bs, f, i->b+i->sx, i->a+i->sy, &c, &d, flags);
+    fclose(f);
+    ip_push(i, c);
+    ip_push(i, d);
+    ip_push(i, i->b);
+    ip_push(i, i->a);
+  } else ip_reverse(i);
+}
+
+void fi_out   (ip * i)
+{
+  FILE *f; char s[256];
+  cell zx, zy, flags;
+  ip_pop_string(i, s);
+  flags = ip_pop(i);
+  GET_ab(i);
+
+  zy = ip_pop(i);
+  zx = ip_pop(i);
+
+  if((f=fopen(s, "w"))!=NULL)
+  {
+    bfspace_fwrite(i->bs, f, i->b+i->sx, i->a+i->sy,
+                   zx, zy, flags);
+    fclose(f);
+  } else ip_reverse(i);
+}
+void fi_exec  (ip * i)
+{
+  char s[256];
+  ip_pop_string(i, s);
+  ip_push(i, system(s));
+}
+void fi_unimp (ip * i)
+{
+  #ifndef FBBI_MINIMAL
+  if(warn)
+    fprintf(stderr, "fbbi warning: unimplemented 0x%08lx at (%ld,%ld)\n",
+                    i->ir, i->x, i->y);
+  #endif
+  fi_reverse(i);
+}
+void fi_nonb93 (ip * i)
+{
+  #ifndef FBBI_MINIMAL
+  if(warn)
+    fprintf(stderr, "fbbi warning: non-Befunge-93 instruction 0x%08lx at (%ld,%ld)\n",
+                    i->ir, i->x, i->y);
+  #endif
+  /* fi_reverse(i); not in b93 compat mode! */
+}
+
+
+void fi_iterate(ip * i)
+{
+  cell c, sx, sy;
+  c = ip_pop(i);
+  sx = i->x;
+  sy = i->y;
+  ip_move(i);
+  i->ir = bfspace_fetch(i->bs, i->x, i->y);
+  if (c <= 0)
+    return;
+  i->x = sx;
+  i->y = sy;
+  if ((i->ir < 32) || (i->ir > 126))
+  {
+    fi_unimp(i);
+    return;
+  }
+  for(;c;c--)
+    instable[(char)i->ir-32](i);
+}
+
+void fi_pushsem(ip * i)
+{
+  i->a = get_fingerprint(i);
+#ifndef FBBI_MINIMAL
+  if (fingerprint_semantics(i, i->a, 1))
+  {
+    ip_push(i, i->a);
+    ip_push(i, 1);
+  } else
+#endif
+  fi_reverse(i);
+}
+
+void fi_popsem(ip * i)
+{
+  i->a = get_fingerprint(i);
+#ifndef FBBI_MINIMAL
+  if (!fingerprint_semantics(i, i->a, 0))
+#endif
+    fi_reverse(i);
+}
+
+void fi_sysinfo(ip * i)
+{
+  time_t t;
+  struct tm * lt;
+  cell sscs;
+
+  t = time(NULL);
+  lt = localtime(&t);
+  GET_a(i);
+  sscs = ip_stack_measure(i);
+
+  ip_push(i, 0);              /* environment double */
+  ip_push(i, 0);              /* terminator */
+  /*
+  for(i->b=0;environ[i->b]!=NULL&&strlen(environ[i->b])>0;i->b++)
+    ip_push_string(i, environ[i->b]);
+  */
+
+  ip_push(i, 0);              /* arguments double */
+  ip_push(i, 0);              /* terminator */
+  for(i->b=global_argc-1;i->b>=fungeprog_arg;i->b--)
+    ip_push_string(i, global_argv[i->b]);
+
+  for(i->b=-1 * ip_stacks_measure(i) + 1;i->b < 0;i->b++)        /* size of each stack under current */
+     ip_push(i, ip_stack_measure_offset(i, i->b));
+  ip_push(i, sscs);
+  ip_push(i, ip_stacks_measure(i));    /* size of stack stack */
+  ip_push(i,
+        ((long)lt->tm_hour << 16)
+      | ((long)lt->tm_min << 8)
+      | ((long)lt->tm_sec)); /* hour/min/sec */
+  ip_push(i,
+        ((long)lt->tm_year << 16)
+      | ((long)lt->tm_mon << 8)
+      | ((long)lt->tm_mday)); /* year/month/day */
+
+  ip_push(i, i->bs->max_x - i->bs->min_x);  /* largest */
+  ip_push(i, i->bs->max_y - i->bs->min_y);
+
+  ip_push(i, i->bs->min_x);                 /* smallest */
+  ip_push(i, i->bs->min_y);
+
+  ip_push(i, i->sx);            /* offset */
+  ip_push(i, i->sy);
+  ip_push(i, i->dx);            /* delta */
+  ip_push(i, i->dy);
+  ip_push(i, i->x);             /* position */
+  ip_push(i, i->y);
+  ip_push(i, 42);            /* unique Team ID */
+  ip_push(i, 42);            /* unique IP ID */
+  ip_push(i, 2);             /* scalars per vector */
+#ifdef __MSDOS__
+  ip_push(i, (long)0|'\\');  /* MS-DOS paradigm */
+#else
+  ip_push(i, (long)0|'/');   /* probably.  Mac users will have 2 suffer 4 now :-> */
+#endif
+  ip_push(i, 1);             /* C system() paradigm */
+  ip_push(i, FBBI_VERSION_MAJOR * 100 + FBBI_VERSION_MINOR);
+  ip_push(i, 0x46424249);    /* handprint */
+  ip_push(i, sizeof(cell));  /* bytes per cell */
+  ip_push(i, 0x0000000e);    /* flags */
+
+  if (i->a > 0)
+  {
+    i->a = ip_stack_peek(i, i->a-1);
+    while (ip_stack_measure(i) > sscs) ip_pop(i);
+    ip_push(i, i->a);
+  }
+}
+
+/*-- INSTRUCTION TABLE */
+
+void (*instable[96])(ip *) =
+{
+  /* 32-63 */
+  fi_space,  fi_not,    fi_string, fi_ramp,   fi_pop,    fi_mod,    fi_idec,   fi_char,
+  fi_pushsem,fi_popsem, fi_mul,    fi_add,    fi_ochar,  fi_sub,    fi_odec,   fi_div,
+  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,
+  fi_digit,  fi_digit,  fi_dup,    fi_skip,   fi_west,   fi_exec,   fi_east,   fi_away,
+
+  /* 64-95 */
+  fi_die,    fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,
+  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,
+  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,  fi_unimp,
+  fi_unimp,  fi_unimp,  fi_unimp,  fi_rleft,  fi_swap,   fi_rright, fi_north,  fi_horzif,
+
+  /* 96-127 */
+  fi_greater,fi_hexdig, fi_hexdig, fi_hexdig, fi_hexdig, fi_hexdig, fi_hexdig, fi_get,
+  fi_unimp,  fi_in,     fi_jump,   fi_iterate,fi_unimp,  fi_unimp,  fi_clear,  fi_out,
+  fi_put,    fi_quit,   fi_reverse,fi_store,  fi_unimp,  fi_under,  fi_south,  fi_compare,
+  fi_delta,  fi_sysinfo,fi_nop,    fi_begin,  fi_vertif, fi_end,    fi_ichar,  fi_unimp
+};
+
+void (*b93instable[96])(ip *) =
+{
+  /* 32-63 */
+  fi_space,  fi_not,    fi_string, fi_ramp,   fi_pop,    fi_mod,    fi_idec,   fi_nonb93,
+  fi_nonb93, fi_nonb93, fi_mul,    fi_add,    fi_ochar,  fi_sub,    fi_odec,   fi_div,
+  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,  fi_digit,
+  fi_digit,  fi_digit,  fi_dup,    fi_nonb93, fi_west,   fi_nonb93, fi_east,   fi_away,
+
+  /* 64-95 */
+  fi_die,    fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93,
+  fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93,
+  fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93,
+  fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_swap,   fi_nonb93, fi_north,  fi_horzif,
+
+  /* 96-127 */
+  fi_greater,fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_get,
+  fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93,
+  fi_put,    fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_south,  fi_nonb93,
+  fi_nonb93, fi_nonb93, fi_nonb93, fi_nonb93, fi_vertif, fi_nonb93, fi_ichar,  fi_nonb93
+};
+/*
+   f98i.h for f98i.c v1.0 May 2011 Chris Pressey
+   Funge-98 Instructions - header.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef _F98I_H_
+#define _F98I_H_
+
+extern void    (*instable[96])(ip *);
+extern void (*b93instable[96])(ip *);
+
+extern void fi_unimp(ip * i);
+
+#endif /* _F98I_H_ not defined */
+
+/*
+   f98ip.c for fbbi.c v1.0 May 2011 Chris Pressey
+   FBBI's Funge-98 Instruction Pointer - source.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "fbbi.h"
+#include "bf98spc.h"
+#include "f98stack.h"
+#include "f98ip.h"
+
+ip * ip_alloc(bfspace * bs, int ssize, int sssize)
+{
+  int k, j;
+  ip * i;
+  stack *initial_stack;
+  i = (ip *)malloc(sizeof(ip));
+  if (i != NULL)
+  {
+    i->sm=i->pm=i->hm=0; /* initfields */ i->dx=1;
+    i->ir=i->y=i->dy=i->sx=i->sy=i->a=i->b=0;i->x=-1;
+    i->bs = bs; i->ssize = ssize; i->sssize = sssize;
+    i->s2 = malloc(sizeof(stack));
+    if (i->s2 == NULL) return NULL;
+    stack_init(i->s2, sssize, sizeof(stack));
+    initial_stack = stack_push_placeholder(i->s2);
+    if (initial_stack == NULL) return NULL;
+    stack_init(initial_stack, ssize, sizeof(cell));
+    for (k=0;k<26;k++)
+    {
+      i->finglev[k] = 0;
+      for (j=0;j<26;j++) i->fingins[k][j] = NULL;
+    }
+  }
+  return i;
+}
+
+void ip_free(ip * i)
+{
+  stack * x;
+  while(stack_measure(i->s2))
+  {
+    x = stack_pop(i->s2);
+    if (x != NULL) stack_release(x);
+  }
+  DEBUG("Freeing the stack stack");
+  stack_release(i->s2);
+  free(i->s2);
+  DEBUG("Freeing the ip struct");
+  free(i);
+}
+
+void ip_reverse(ip * i)
+{
+  NEG(i->dx);  NEG(i->dy);
+}
+
+void ip_march(ip * i)
+{
+  i->x += i->dx;
+  i->y += i->dy;
+}
+
+void ip_backtrack(ip * i)
+{
+  ip_reverse(i);
+  while (!bfspace_inbounds(i->bs, i->x, i->y))
+    ip_march(i); /* bugfix 2003.0726 March back until inside fungespace to cope with edge-of-space #, j, etc. */
+
+  while (bfspace_inbounds(i->bs, i->x, i->y))
+    ip_march(i);
+
+  ip_reverse(i);
+  ip_march(i);
+}
+
+void ip_advance(ip * i)
+{
+  ip_march(i);
+  if (!bfspace_inbounds(i->bs, i->x, i->y))
+    ip_backtrack(i);
+}
+
+void ip_skipto(ip * i, cell target)
+{
+  ip_advance(i);
+  while (bfspace_fetch(i->bs, i->x, i->y) != target)
+  {
+    ip_advance(i);
+    #ifndef FBBI_MINIMAL
+    if (!fast) printf(" \b");
+    #endif
+  }
+}
+
+void ip_move(ip * i)
+{
+  cell c;
+  ip_advance(i);
+  c = bfspace_fetch(i->bs, i->x, i->y);
+  while (c == (cell)';' || c == (cell)' ')
+  {
+    if (c == (cell)';')
+    {
+      if (i->sm) return;      
+      ip_skipto(i, (cell)';');
+      ip_advance(i);
+    }
+    else while (bfspace_fetch(i->bs, i->x, i->y) == (cell)' ')
+    {
+  #ifndef FBBI_MINIMAL
+      if (((i->sm) && (i->pm == 0)) || (b93))
+  #else
+      if ((i->sm) && (i->pm == 0))
+  #endif
+      {
+  #ifndef FBBI_MINIMAL
+        if (!b93)
+  #endif
+          i->pm = 1;
+        return;
+      }
+      ip_advance(i);
+  #ifndef FBBI_MINIMAL
+      if (!fast) printf(" \b");
+  #endif
+      if ((bfspace_fetch(i->bs, i->x, i->y) == (cell)';') && (!i->sm))
+      {
+        ip_skipto(i, (cell)';'); ip_advance(i);
+      }
+    }
+    c = bfspace_fetch(i->bs, i->x, i->y);
+  }
+  i->pm = 0;
+}
+
+/* might return NULL */
+stack * ip_stack(ip * i)
+{
+  return (stack *)stack_read(i->s2, 0);
+}
+
+cell ip_pop(ip * i)
+{
+  cell * x;
+  stack * s = (stack *)ip_stack(i);
+  if (s != NULL)
+  {
+    x = (cell *)stack_pop(s);
+    if (x != NULL) return *x; else return (cell)0;
+  } else return (cell)0;
+}
+
+int ip_push(ip * i, cell x)
+{
+  stack * s = (stack *)stack_read(i->s2, 0);
+
+  if (s != NULL)
+  {
+    stack_push(s, &x); 
+    return 1;
+  } else return 0;
+}
+
+int ip_clearstack(ip * i)
+{
+  stack * s = ip_stack(i);
+  if (s != NULL)
+  {
+    stack_clear(s); 
+    return 1;
+  } else return 0;
+}
+
+cell ip_pop_soss(ip * i)
+{
+  cell *x;
+  stack *soss = (stack *)stack_read(i->s2, 1);
+  x = stack_pop(soss);
+  if (x != NULL) return *(cell *)x; else return 0;
+}
+
+void ip_push_soss(ip * i, cell value)
+{
+  stack *soss = (stack *)stack_read(i->s2, 1);
+  stack_push(soss, &value);
+}
+
+int ip_allocstack(ip * i)
+{
+  stack * u;
+  u = stack_push_placeholder(i->s2);
+  if (u == NULL) return 0;
+  return stack_init(u, i->ssize, sizeof(cell));
+}
+
+void ip_freestack(ip * i)
+{
+  stack * x = stack_pop(i->s2);
+  if (x != NULL) stack_release(x);
+}
+
+int ip_transfer(ip * i, int val)
+{
+  cell zero = (long)0;
+  return stack_stack_transfer(i->s2, val, &zero);
+}
+
+void ip_pop_string(ip * i, char * s)
+{
+  stack_pop_string(stack_stack_top(i->s2), s);
+}
+
+void ip_push_string(ip * i, char * s)
+{
+  stack_push_string(stack_stack_top(i->s2), s);
+}
+
+int ip_stack_measure(ip * i)
+{
+  return stack_measure(stack_stack_top(i->s2));
+}
+
+int ip_stacks_measure(ip * i)
+{
+  return stack_measure(i->s2);
+}
+
+int ip_stack_measure_offset(ip * i, int offset)
+{
+  stack * s = stack_read(i->s2, offset);
+  if (s != NULL) return stack_measure(s); else return 0;
+}
+
+cell ip_stack_peek(ip * i, int offset)
+{
+  cell * x;
+  stack * s = stack_stack_top(i->s2);
+  if (s != NULL)
+  {
+    x = stack_read(s, offset);
+    if (x != NULL) return *(cell *)x; else return 0;
+  } else return 0;
+}
+
+cell ip_stack_peek_peek(ip * i, int o1, int o2)
+{
+  cell * x;
+  stack * s = (stack *)stack_read(i->s2, o1);
+  if (s != NULL)
+  {
+    x = stack_read(s, o2);
+    if (x != NULL) return *(cell *)x; else return (cell)0;
+  } else return 0;
+}
+
+void stack_dump (stack * s)
+{
+  cell *x; int o;
+  printf("Size %d: (Top: ", stack_measure(s));
+  for (o = 0; o < stack_measure(s); o++) {
+      x = stack_read(s, o);
+      printf("%ld ", *x);
+  }
+  printf(")\n");
+}
+/*
+   f98ip.h for f98ip.c v1.0 May 2011 Chris Pressey
+   FBBI's Funge-98 Instruction Pointer - header.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef _F98IP_H_
+#define _F98IP_H_
+
+#include "f98stack.h"
+
+typedef struct InstructionPointer
+{
+  cell ir;      /* instruction register */
+  cell x, y;    /* position */
+  cell dx, dy;  /* delta */
+  cell sx, sy;  /* offset */
+  cell a, b;    /* scratch storage */
+  cell ec;      /* error code */
+  flag sm;      /*-- stringmode */
+  flag pm;      /*-- spacemode */
+  flag hm;      /*-- haltmode */
+  bfspace * bs; /* befunge-space */
+  stack * s2;   /* stack-stack */
+  void (*fingins[26][26])(struct InstructionPointer *);
+  int finglev[26]; /* fingerprints */
+  int ssize;
+  int sssize;
+} ip;
+
+extern ip * ip_alloc(bfspace * bs, int ssize, int sssize);
+extern void ip_free(ip * i);
+extern void ip_reverse(ip * i);
+extern void ip_march(ip * i);
+extern void ip_backtrack(ip * i);
+extern void ip_advance(ip * i);
+extern void ip_move(ip * i);
+
+stack * ip_stack(ip * i);
+cell ip_pop(ip * i);
+int ip_push(ip * i, cell x);
+
+int ip_clearstack(ip * i);
+cell ip_pop_soss(ip * i);
+void ip_push_soss(ip * i, cell value);
+int ip_allocstack(ip * i);
+void ip_freestack(ip * i);
+int ip_transfer(ip * i, int val);
+void ip_pop_string(ip * i, char * s);
+void ip_push_string(ip * i, char * s);
+int ip_stack_measure(ip * i);
+int ip_stacks_measure(ip * i);
+int ip_stack_measure_offset(ip * i, int offset);
+cell ip_stack_peek(ip * i, int offset);
+cell ip_stack_peek_peek(ip * i, int o1, int o2);
+
+/* Display a stack, from top to bottom, on stdout */
+extern void         stack_dump(stack * s);
+
+#endif /* _F98IP_H_ not defined */
+/*
+   f98stack.c for fbbi.c v1.0 May 2011 Chris Pressey
+   Stack ANSI C Functions - source.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+   Why use this package?
+   - It's ANSI C
+   - You need to store one or more stack stacks,
+     as defined in Funge-98 (http://www.catseye.mb.ca/projects/funge98-+)
+
+   Changes in v0.98:
+   - FSS_DATATYPE is replaced with void * and dc (size in bytes)
+   - stack stack is built upon stack with stack * as the cell type
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <stdio.h>
+
+#include "f98stack.h"
+
+/* Given the number of cells (sc) and bytes per cell (dc), configure a */
+/* stack object and allocate the memory used for its backing store.  Note */
+/* will only allocate the memory for the backing store of */
+/* the stack -- it is up to the caller to allocate the actual */
+/* struct Stack that manages the backing store.  (This allows */
+/* the caller to choose to place it on e.g. another stack.) */
+/* Returns 1 if the memory was successfully allocated, 0 otherwise. */
+int stack_init(stack * u, long int sc, long int dc)
+{
+  if (u == NULL) return 0;
+  u->mem = malloc(sc * dc);
+  if (u->mem == NULL) return 0;
+  u->sp = -1;
+  u->sc = sc;
+  u->dc = dc;
+  SDEBUG("Successful Init", u);
+  return 1;
+}
+
+/* Given a pointer to a stack, remove and return the top cell */
+void * stack_pop(stack * s)
+{
+  SDEBUG("Before Pop", s);
+  if (s->sp >= 0)
+  {
+    return ((char *)s->mem + (s->sp-- * s->dc));
+  } else return NULL;
+}
+
+/* Given a pointer to a stack and a value, place it on the */
+/* top of the stack */
+int stack_push(stack * s, void * val)
+{
+  SDEBUG("Before Push", s);
+  if(s->sp < s->sc-1)
+  {
+    memcpy(((char *)s->mem + (++s->sp * s->dc)), val, s->dc);
+    SDEBUG("Successful Push", s);
+    return 1;
+  } else return 0;
+}
+
+/* Push a dummy value onto the top of the stack and return a */
+/* pointer to it for further manipulation.  Returns NULL if no */
+/* more space available on stack. */
+void * stack_push_placeholder(stack * s)
+{
+  SDEBUG("Before Push Placeholder", s);
+  if(s->sp < s->sc-1)
+  {
+    void * loc = NULL;
+    ++s->sp;
+    loc = ((char *)s->mem + (s->sp * s->dc));
+    memset(loc, 0, s->dc);
+    SDEBUG("Successful Push Placeholder", s);
+    return loc;
+  } else return NULL;
+}
+
+/* Pop a series of cells off the stack as chars until a 0 cell */
+void stack_pop_string(stack * s, char * str)
+{
+  int i = 0;
+  void * x = NULL;
+  SDEBUG("Before Pop String", s);
+  x = stack_pop(s);
+  while ((s->sp >= 0) && (x != NULL) && (*(char *)x != 0))
+  {
+    str[i++] = *(char *)x;
+    x = stack_pop(s);
+  }
+  if (s->sp == -1)
+    str[i++] = *(char *)x; /* bugfix 2003.0726: EOS as string terminator */
+  str[i] = (char)'\0';
+}
+
+/* Push a series of chars onto the stack as cells until a 0 char */
+void stack_push_string(stack * s, char * str)
+{
+  int i = strlen(str) + 1;
+  long int l = 0;
+  SDEBUG("Before Push String", s);
+  while (i > 0)
+  {
+    l = (long)0 | str[--i]; /* pad */
+    stack_push(s, &l);
+  }
+}
+
+/* Given a pointer to a stack and a number of cells from the top */
+/* cell, return an indexed cell without removing it */
+void * stack_read(stack * s, int offset /* 0 = TOS */ )
+{
+  void * k = NULL;
+  if(offset < 0) offset *= -1;
+  SDEBUG("Before Read", s);
+  if (s->sp >= offset)
+  {
+    k = (void *)((char *)s->mem + (s->sp - offset) * s->dc);
+    return k;
+  } else return NULL;
+}
+
+/* Return the number of elements on a given stack */
+int stack_measure(stack * s)
+{
+  SDEBUG("Before Measure", s);
+  if (s != NULL) return s->sp + 1; else return 0;
+}
+
+/* Remove all cells from a given stack */
+void stack_clear(stack * s)
+{
+  SDEBUG("Before Clear", s);
+  if (s != NULL) s->sp = -1;
+}
+
+/* Free the backing store used by a stack, invalidating the stack. */
+/* Like in stack_init, the memory of the Struct stack itself is not */
+/* touched. */
+void stack_release(stack * s)
+{
+  SDEBUG("Before Free", s);
+  if (s != NULL && s->mem != NULL)
+  {
+    free(s->mem);
+  }
+}
+
+/* Stack of stacks - transfer elements a la f98's {} instructions */
+int stack_stack_transfer (stack * t, int count, void * zero)
+{
+  int i;
+  stack * toss; stack * soss;
+  void * q;
+
+  SDEBUG("Before Transfer", t);
+  if (stack_measure(t) > 1)
+  {
+    toss = (stack *)stack_read(t, 0);
+    soss = (stack *)stack_read(t, 1);
+    if (toss != NULL && soss != NULL)
+    {
+      if (count > 0) /* from SOSS to TOSS */
+      {
+        for(i=0;i<count;i++)
+        {
+          q = stack_read(soss, count - 1 - i);
+          if (q != NULL) stack_push(toss, q); else stack_push(toss, zero);
+        }
+        soss->sp -= count;
+        if (soss->sp < 0) soss->sp = -1;
+      } else
+      if (count < 0) /* from TOSS to SOSS */
+      {
+        count *= -1;
+        for(i=0;i<count;i++)
+        {
+          q = stack_read(toss, count - 1 - i);
+          if (q != NULL) stack_push(soss, q); else stack_push(soss, zero);
+        }
+        toss->sp -= count;
+        if (toss->sp <= 0) toss->sp = -1;
+      }
+      return 1;
+    }
+  }
+  return 0;
+}
+/*
+   f98stack.h for f98stack.c v1.0 May 2011 Chris Pressey
+   Funge-98 Stack Stack C Functions - header.
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef _F98STACK_H_
+#define _F98STACK_H_
+
+typedef struct Stack
+{
+  void * mem;        /* pointer to array of cells of any type */
+  long int sp;       /* stack pointer */
+  long int sc;       /* total stack capacity */
+  long int dc;       /* data capacity of each cell */
+} stack;
+
+#ifdef DEBUG_STACK
+  #include <stdio.h>
+  #ifndef SDEBUG
+    #define SDEBUG(x, s) fprintf(stderr, "<-Stack:%s->\n", x);           \
+                         fprintf(stderr, "memory: %08x\n", (unsigned int)s->mem);  \
+                         fprintf(stderr, "stack pointer: %ld\n", s->sp);  \
+                         fprintf(stderr, "stack capacity: %ld\n", s->sc);  \
+                         fprintf(stderr, "data capacity: %ld\n", s->dc);    \
+                         fflush(stderr);
+    #endif
+  #else
+  #ifndef SDEBUG
+    #define SDEBUG(x, s)
+    #endif
+#endif
+
+/* Given the number of cells (sc) and bytes per cell (dc), */
+/* configure a stack object and allocate its backing store */
+extern int          stack_init(stack * u, long int sc, long int dc);
+
+/* Given a pointer to a stack, remove and return the top cell */
+extern void *       stack_pop(stack * s);
+
+/* Given a pointer to a stack and a value, place it on the */
+/* top of the stack */
+extern int          stack_push(stack * s, void * val);
+
+/* Push a dummy value onto the top of the stack and return a */
+/* pointer to it for further manipulation */
+extern void *       stack_push_placeholder(stack * s);
+
+/* Pop a series of cells off the stack as chars until a 0 cell */
+extern void         stack_pop_string(stack * s, char * str);
+
+/* Push a series of chars onto the stack as cells until a 0 char */
+extern void         stack_push_string(stack * s, char * str);
+
+/* Given a pointer to a stack and a number of cells from the top */
+/* cell, return an indexed cell without removing it */
+extern void *       stack_read(stack * s, int offset);
+
+/* Return the number of cells on a given stack */
+extern int          stack_measure(stack * s);
+
+/* Remove all cells from a given stack */
+extern void         stack_clear(stack * s);
+
+/* Free the backing store used by a stack, invalidating the stack */
+extern void         stack_release(stack * s);
+
+/* Some handy definitions when working with stacks of stack *'s */
+
+#define stack_stack_top(t)            (stack *)stack_read(t, 0)
+#define stack_stack_popcell(t)        stack_pop((stack *)stack_read(t, 0))
+#define stack_stack_pushcell(t,s)     stack_push((stack *)stack_read(t, 0),(void *)s)
+
+extern int stack_stack_transfer (stack * t, int count, void * zero);
+
+#endif /* _F98STACK_H_ not defined */
+/*
+   fbbi.c v1.0 May 2011 Chris Pressey
+   Flaming Bovine Befunge-98 Interpreter in ANSI C - Main Unit
+
+   Copyright (c)1998-2011 Cat's Eye Technologies.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notices, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notices, this list of conditions, and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+   3. Neither the names of the copyright holders nor the names of their
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/*
+   FBBI project at catseye.tc: http://catseye.tc/projects/fbbi/
+
+   Usage: fbbi [-F] [-f] [-w] [-t] [-s] [-u] [-93] [-mc n] [-ms n]
+               sourcefile [funge-prog-args]
+
+      -F: not fast: less speed, but allows the program to be
+          interrupted on systems that only check for such an
+          interruption during I/O.
+      -f: fast (default): more speed, but on some systems the
+          program execution cannot be interrupted.
+      -w: warn: like Perl's -w switch.  If an unimplimented
+          instruction is executed, the user is warned.
+          Used in conjunction with -93 or -u, alerts user to
+          behaviour not in the Befunge-93 or Unefunge idioms,
+          as appropriate.
+      -t: trace: display debug info & samples of source
+          during execution, with interactive prompt
+      -s: script: begin execution on the first line that does
+          not begin with a comment (#) symbol
+      -u: unefunge: disables Befunge and Trefunge-specific (>1D)
+          instructions and uses single-scalar vectors
+     -93: disables Funge-98 instructions, changes stringmode
+          and in conjunction with -w tells the user about it
+     -mc: maxcells: specify the maximum number of cells on each
+          stack, default 1024.
+     -ms: maxstacks: specify the maximum number of stacks on the
+          stack stack, default 256.
+      sourcefile: name of file to load and treat as a Befunge source
+      funge-prog-args: made available to Befunge program through y
+
+   -------------------------------------------------------------
+
+   v1.0, May 2011, Chris Pressey.
+          * applied v2003.0722 patch:
+            - have o not output trailing spaces when passed flag
+            - { still pushes a new stack on the stack stack
+            - } still attempts to pop the top of stack stack
+          * applied Jeffrey Lee's patch (thanks Jeffrey!):
+            - correct number of lines read on file input
+            - ensure fingerprint semantics are saved correctly
+            - correct wrapping when backtracking after #, j, etc
+            - correct usage of EOS as string terminator
+          * applied FBBI Mark 3 patch:
+            - guard against negative fingerprint ID lengths
+            - only r once if trying to k an unimplemented instr
+          * IP position restored to location of k before execution
+            of iterated instruction
+          * fixed greatest bound of Funge-space reported by y
+          * fixed off-by-one error in bfspace_fwrite, where the
+            rightmost column of characters was not being output
+          * fixed wrapping logic w.r.t. ; at edge of space
+          * typed ip->s2 and ip_stack() as stack *, removed casts
+          * reworked the stack-stack allocation routines, fixing
+            a crippling memory allocation bug (both stacks and
+            stack stacks were being alloced/freed, even though
+            stacks overlayed stack stacks)
+          * refactored debugger interface, made input more robust
+          * fixed how v2003.0722 fixed { and } in a better way
+          * fixed BSD license verbiage (I am not a Regent)
+          + 'fast' execution is now the default; -F turns it off
+          + improved Makefile (made vars default, added strip target.)
+          X pushing the environment variables doesn't work anymore.
+
+   v0.98a, Mar 26 2003, Chris Pressey.
+          * relicensed under BSD license
+	  * made minor changes to Makefile and docs
+	  * values.h is no longer included under FreeBSD
+	  
+   v0.98, Oct 1 1998, Chris Pressey.
+          * Negative argument to { pushes |n| 0s onto the SOSS
+          * Negative argument to } destroys top |n| values on the SOSS.
+          * } reflects when stack-stack would be about to underflow
+          * y instruction now pushes args and env as per spec
+          - fixed greatest point bug in y's behaviour
+          + f98stack.c module generalized for stacks of any type 
+          + Added trace ViewStackPlayfieldMoveDeltaOffset commands.
+          + Unefunge compatibility [-u] (not well tested though).
+
+   v0.94, Sep 15 1998, Chris Pressey.  [Unreleased]
+          * . and , reflect if stdout fails for whatever reason.
+          * { reflects when no more stacks are available
+          * & sucks and discards all leading non-digit characters
+          - worked around EOL (CR, LF or CRLF) bug (binary mode.)
+          + added _FILE_H_ define checking on all included headers.
+
+   v0.93, Aug 3 1998, Chris Pressey.
+          * y pushes vectors and path seperators
+          * i and o both take a flags argument now
+          * ~ and & instructions act like r on EOF in stdin
+          * space and ; "instructions" are never executed
+            (though they do have meaning in stringmode)
+          * k instruction takes argument from space
+          - fixed off-by-one error in stack_push_string
+          - fixed ss_push_offset and ss_pop_offset
+          - made stack_push, ss_push_stack safer
+          - explicitly externs environ in main()
+          - changed time() code in y to more idiomatic use
+          - = instruction now really pushes return code onto stack
+          - upped default stack and stack stack sizes
+          + added a gcc Makefile (-ansi -pedantic now doesn't complain)
+          + added config.h so end user can recompile with own options
+          + minimal build now knows no fingerprints (more minimal)
+          + added gnuesque --long-name command line options
+            (doesn't accept equals signs like --max-cells=1024 yet)
+          + added Befunge-93 compatibility mode (not thoroughly tested)
+
+   v0.92, Jul 20 1998, Chris Pressey.
+          Brought into line with the changes to spec, which were:
+          * added k Iterate and s Store Character instructions
+          * i and o both now pop the filename first
+          * i pushes results appropriate for input to o
+          * sizes of stacks now pushed before command line in y
+          * environment is now pushed after command line in y
+          * Null fingerprint is now fingerprint number 0x0
+          * Negative args to { or } now treated as zeros
+          Also fixed the following bugs:
+          - CRLF sequence indicates single EOL in bfspace_read
+          - now (almost) cleans up y after taking a non-zero argument
+          - wrapping with ';' instruction uses Lahey-wrap correctly
+          Also made minor fbbi-only improvements, namely:
+          + added size & script switches & longnames to command line
+          + prettied up the source; made ip a struct, etc
+          + modularized; everything in it's own object file
+          + added 'mini' build, shaves 3K off the executable
+
+   v0.91, Jul 8 1998, Chris Pressey.
+          Added fingerprint mechanism and NULL and ROMA fingerprints.
+
+   v0.90, Jul 6-8 1998, Chris Pressey.
+          Did some critical tying up relative to the new spec.
+          Added command line, final instructions {i=you}().
+
+   v0.84, Mar 24 1998, Chris Pressey.
+	  Added the bulk of vanilla Funge-98 instructions, and file I/O
+	  functions for big Befunge-Space.
+
+   v0.83, Mar 1998, Chris Pressey.
+	  Derived from ssbf93 v0.83.
+
+   -------------------------------------------------------------
+
+   Mycology conformance drive: as of this writing, Mycology reports
+   the following BADs with FBBI.  Here is our rationale for them:
+
+    BAD: u with a positive argument gives strange storage offset:
+           expected (0,0)
+
+   Instrumenting FBBI with print statements reveals that Mycology is
+   doing this at one point:
+     $$$ EXECUTING 'BEGIN': assigned storage offset 14, 77
+     $$$ EXECUTING 'END': restored storage offset 14, 13
+   ...but later expecting a storage offset of (0,0).  This is despite