git @ Cat's Eye Technologies FBBI / master src / fbbi.c
master

Tree @master (Download .tar.gz)

fbbi.c @masterraw · history · blame

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
/*
   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
   no BAD being produced up to this point.  I've written my own little
   test for storage offset and u, in the under.b98 example source,
   and FBBI looks like it behaves as expected when saving, transfer-
   ing, and restoring the storage offset.  I am therefore classifying
   this BAD as a problem with Mycology, until further information
   comes to light.

    BAD: form feed reflects

   If form feeds indicate "increment Z coordinate" in Trefunge-ish
   Befunge sources, then form feeds shouldn't be loaded with the i
   instruction.  OTOH, if there are FF characters in Funge-space,
   they should reflect.

    BAD: after spacing top-left corner, y should report least point
           as ( -2 -1 ), not ( -10 -10 )
    BAD: after spacing top-left corner, y should report greatest point
           as ( 182 910 ), not ( 190 919 )
    BAD: after spacing right edge, least point reported by y should
           remain ( -2 -1 )
    BAD: after spacing right edge, y should report greatest point
           as ( 181 910 ), not ( 190 919 )
    BAD: after spacing bottom edge, y should report greatest point
           as ( 181 909 ), not ( 190 919 )

   These are because FBBI does not shrink its idea of the bounds of
   Funge-space, when characters at the edge of Funge-space are erased.
   However, the spec defines these values strangely -- a bounding box
   between the least and greatest points which contain non-space cells
   might not contain all non-space cells in Funge-space, which does not
   coincide with the idea that these values are "useful to give to the
   o instruction to output the entire program source as a text file".
   Thus we suffice to be content that the values FBBI provides for this
   purpose are sufficient, if not optimal, for passing to o to output
   the program as a text file.

    Environment variables

   There are some indications that FBBI does not handle environment
   variables properly in the y instruction.  However, understandably,
   Mycology does not try to test this.  I have contemplated how much
   I care, and have concluded that I don't consider this a blocker
   for the release of version 1.0.

*/

/*-- #INCLUDE'S */

/*---- C libraries */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>

#ifndef FBBI_ANSI
 #ifdef __MSDOS__
  #include <io.h>
 #endif
#endif

/*---- FBBI modules */

#include "config.h"

#include "fbbi.h"
#include "bf98spc.h"
#include "f98ip.h"
#include "f98i.h"
#include "f98fp.h"

/*-- GLOBALS */

char ** global_argv;		/* set to argv in main() */
int global_argc;		/* set to argc in main() */
int fungeprog_arg;		/* set to funge prog's arg in main() */

#ifndef FBBI_MINIMAL
flag fast=1;
flag warn=0;
flag trace=0;
flag script=0;
flag b93=0;
flag une=0;

flag bpt=0;
cell bx=0;
cell by=0;
#endif

/*-- TRACE */

#ifndef FBBI_MINIMAL
int ask_for_two_cells(cell * x, cell *y)
{
  cell savex = *x;
  cell savey = *y;
  int ic;

  fflush(stdin); 
  fflush(stdout);
  ic = scanf("%ld %ld", x, y);
  if (ic < 2) {
    *x = savex;
    *y = savey;
    printf("Could not understand your numbers -- aborting.\n");
    ic = 0;
  }
  fflush(stdin); 
  fflush(stdout);
  return ic;
}

void perform_trace(ip * i)
{
  char c[9];
  cell s[4];
  int j=0; int k=0; cell l=0; cell tx, ty;
  int ic;

  c[0] = PRINT(bfspace_fetch(i->bs, i->x-1, i->y-1));
  c[1] = PRINT(bfspace_fetch(i->bs, i->x, i->y-1));
  c[2] = PRINT(bfspace_fetch(i->bs, i->x+1, i->y-1));
  c[3] = PRINT(bfspace_fetch(i->bs, i->x-1, i->y));
  c[4] = PRINT(bfspace_fetch(i->bs, i->x, i->y));
  c[5] = PRINT(bfspace_fetch(i->bs, i->x+1, i->y));
  c[6] = PRINT(bfspace_fetch(i->bs, i->x-1, i->y+1));
  c[7] = PRINT(bfspace_fetch(i->bs, i->x, i->y+1));
  c[8] = PRINT(bfspace_fetch(i->bs, i->x+1, i->y+1));

  for(k=0;k<=3;k++)
  {
    if (ip_stack_measure(i) > k)
      s[k] = ip_stack_peek_peek(i, 0, k); else
      s[k] = 0;
  }

  printf("+---+ position   : (%06ld, %06ld) stack size: %d cell(s) # of stacks: %d\n",
                              i->x,  i->y,              ip_stack_measure(i), ip_stacks_measure(i));
  printf("|%c%c%c| delta      : (%06ld, %06ld) 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
          c[0], c[1], c[2],     i->dx, i->dy,  s[0],   s[1],    s[2],    s[3]);
  printf("|%c%c%c| offset     : (%06ld, %06ld) decimal (%ld %ld %ld %ld) ascii (%c%c%c%c)\n",
          c[3], c[4], c[5],     i->sx, i->sy,           s[0],s[1],s[2],s[3], PRINT(s[0]), PRINT(s[1]), PRINT(s[2]), PRINT(s[3]));
  printf("|%c%c%c| instruction: 0x%08lx ('%c')\n", c[6], c[7], c[8], i->ir, PRINT(i->ir));
  printf("+---+ stringmode : %s\n", i->sm ? "on" : "off");

  k=0;
  while(!k)
  {
    printf("S)tep R)un B)reakpoint V)iewStack P)layfield M)ove D)elta O)ffset Q)uit: ");
    fflush(stdin); 
    fflush(stdout);
    ic = scanf("%s", c);
    if (ic < 1)
    {
      c[0] = ' ';
      c[1] = (char)0;
    }
    fflush(stdin);
    fflush(stdout);
    if ((c[0] == 'r') || (c[0] == 'R')) { trace=0; k=1; }
    if ((c[0] == 'q') || (c[0] == 'Q')) { i->hm=1; k=1; }
    if ((c[0] == 's') || (c[0] == 'S')) { k=1; }
    if ((c[0] == 'v') || (c[0] == 'V'))
    {
      printf("%d stacks:\n", ip_stacks_measure(i));
      for(j=0;j<ip_stacks_measure(i);j++)
      {
        printf("  stack #%d, %d elements:\n",
                j + 1, ip_stack_measure_offset(i, j));
        for(k=0;k<ip_stack_measure_offset(i, j);k++)
        {
          l = ip_stack_peek_peek(i, j, k);
          printf("    element #%d = %ld ('%c').\n", k + 1, l, PRINT(l));
        }
      }
      k=0;
    }
    if ((c[0] == 'p') || (c[0] == 'P'))
    {
      printf("Enter x and y of upper-left, seperated by whitespace:");
      if (ask_for_two_cells(&tx, &ty))
      {
        bfspace_fwrite(i->bs, stdout, tx, ty, 79, 22, 0);
        fflush(stdout);
      }
      k=0;
    }
    if ((c[0] == 'm') || (c[0] == 'M'))
    {
      printf("Enter x and y coordinates seperated by whitespace:");
      ask_for_two_cells(&i->x, &i->y);
      k=0;
    }
    if ((c[0] == 'd') || (c[0] == 'D'))
    {
      printf("Enter dx and dy values seperated by whitespace:");
      ask_for_two_cells(&i->dx, &i->dy);
      k=0;
    }
    if ((c[0] == 'o') || (c[0] == 'O'))
    {
      printf("Enter x and y storage offsets seperated by whitespace:");
      ask_for_two_cells(&i->sx, &i->sy);
      k=0;
    }
    if ((c[0] == 'b') || (c[0] == 'B'))
    {
      if(!bpt)
      {
        printf("Enter x and y coordinates of breakpoint, seperated by whitespace:");
        if (ask_for_two_cells(&bx, &by))
          bpt=1;
      } else
      {
        printf("Breakpoint deactivated.");
        fflush(stdout);
        bpt=0;
      }
      k=0;
    }
  }
}
#endif

static void usage()
{
  printf("fbbi - flaming bovine befunge-98 interpreter v%d.%d",
          FBBI_VERSION_MAJOR, FBBI_VERSION_MINOR);
#ifdef FBBI_ANSI
  printf(" in ANSI C");
#endif
#ifdef FBBI_MINIMAL
  printf(" - mini");
#endif
  printf("\n    Copyright (c)1998-2011 Cat's Eye Technologies, http://catseye.tc/"
         "\n    Released under BSD license, see source code for more information.\n");
  printf("usage: fbbi ");
#ifndef FBBI_MINIMAL
  printf("[-F] [-f] [-w] [-t] [-s] [-u] [-93]\n            [-mc n] [-ms n] ");
#endif
  printf("sourcefile [funge-prog-args]\n");
#ifndef FBBI_MINIMAL
  printf(" -[not]F[ast]: go slower but allow program interrupt on some systems\n");
  printf(" -f[ast]: go faster but program cannot be interrupted on some systems\n");
  printf(" -w[arn]: issue warnings on unimplemented instructions\n");
  printf(" -t[race]: trace source execution during run\n");
  printf(" -s[cript]: begin execution on first non-# line of source\n");
  printf(" -u[nefunge]: work in one dimension only (Unefunge) mode\n");
  printf(" -[befunge]93: work in Befunge-93 compatibility mode\n");
  printf(" -m[ax]c[ells]: specify number of elements allocated for each stack, def. %d\n", DEFAULT_STACK_SIZE);
  printf(" -m[ax]s[tacks]: specify number of stacks allocated on stack stack, def. %d\n", DEFAULT_STACKSTACK_SIZE);
#endif
  exit(1);
}

/*-- MAIN PROGRAM */

int main(int argc, char **argv)
{
  int k, ec=0;
  FILE *f=NULL;
  bfspace *p=NULL;
  ip *i=NULL;
  cell w,h;
  int ssize  = DEFAULT_STACK_SIZE;
  int sssize = DEFAULT_STACKSTACK_SIZE;

  global_argv = argv;
  global_argc = argc;

  if (argc < 2)
    usage();

  fungeprog_arg = -1;
  for(k=1;k<argc;k++)
  {
#ifndef FBBI_MINIMAL
    if((!strcmp(argv[k], "-F")) || (!strcmp(argv[k], "-not-fast")) || (!strcmp(argv[k], "--not-fast"))) fast=0;
    if((!strcmp(argv[k], "-f")) || (!strcmp(argv[k], "-fast")) || (!strcmp(argv[k], "--fast"))) fast=1;
    if((!strcmp(argv[k], "-w")) || (!strcmp(argv[k], "-warn")) || (!strcmp(argv[k], "--warn"))) warn=1;
    if((!strcmp(argv[k], "-t")) || (!strcmp(argv[k], "-trace")) || (!strcmp(argv[k], "--trace"))) trace=1;
    if((!strcmp(argv[k], "-s")) || (!strcmp(argv[k], "-script")) || (!strcmp(argv[k], "--script"))) script = 1;
    if((!strcmp(argv[k], "-u")) || (!strcmp(argv[k], "-unefunge")) || (!strcmp(argv[k], "--unefunge"))) une = 1;
    if((!strcmp(argv[k], "-93")) || (!strcmp(argv[k], "-befunge93")) || (!strcmp(argv[k], "--befunge-93")) || (!strcmp(argv[k], "--befunge93"))) b93 = 1;
    if((!strcmp(argv[k], "-mc")) || (!strcmp(argv[k], "-maxcells")) || (!strcmp(argv[k], "--max-cells")) || (!strcmp(argv[k], "--maxcells")))
    {
      ssize = atoi(argv[++k]);
    } else
    if((!strcmp(argv[k], "-ms")) || (!strcmp(argv[k], "-maxstacks")) || (!strcmp(argv[k], "--max-stacks"))  || (!strcmp(argv[k], "--maxstacks")))
    {
      sssize = atoi(argv[++k]);
    } else
#endif
    if(argv[k][0] != '-') { fungeprog_arg = k; break; }
  }
  if (fungeprog_arg == -1)
    usage();

  /* initialize */

  srand(time(0));

  DEBUG("Allocating Funge-Space");
  if ((p = bfspace_alloc(NULL)) != NULL)
  {
    DEBUG("Allocating IP");
    if ((i = ip_alloc(p, ssize, sssize)) != NULL)
    {
      DEBUG("Opening Source File");
      if ((f=fopen(argv[fungeprog_arg],"r")) != NULL)
      {
#ifdef FBBI_MSDOS
 #ifndef FBBI_ANSI
        setmode(fileno(f), O_BINARY);
 #endif
#endif
        DEBUG("Reading Source File");
        if (bfspace_fread(i->bs, f, 0, 0, &w, &h, 0))
        {
          fclose(f);
#ifndef FBBI_MINIMAL
          if ((w > 79) || (h > 24))
          {
            if(b93 && warn)
              fprintf(stderr, "fbbi warning: "
              "source too large for Befunge-93-Space (%ld x %ld)\n", w+1, h+1);
          }
          if (h >= 1)
          {
            if(une && warn)
              fprintf(stderr, "fbbi warning: "
              "source too large for Unefunge-98-Space (%ld x %ld)\n", w+1, h+1);
          }
          if (script)
          {
            while (bfspace_fetch(i->bs, 0, i->y)
              == ((long)0 | (long)'#'))
              i->y++;
          }
#endif
          DEBUG("* Begin Interpret *");
          while (!i->hm)
          {
            DEBUG("Moving IP");
            ip_move(i);
#ifndef FBBI_MINIMAL
            if(bpt && i->x == bx && i->y == by) trace=1;
#endif
            DEBUG("Getting Instruction");
            i->ir = bfspace_fetch(i->bs, i->x, i->y);
#ifndef FBBI_MINIMAL
            if (b93 && ((i->x < 0) || (i->y < 0) || (i->x > 79) || (i->y > 24)) )
            {
              if(warn)
                fprintf(stderr, "fbbi warning: "
                "beyond Befunge-93-Space at (%ld,%ld)\n", i->x, i->y);
            }
            if (trace)
            {
              perform_trace(i);
              if (i->hm) break;
            }
#endif
            DEBUG("Executing Instruction");
            if (i->sm && ((char)i->ir != '"'))
            {
              ip_push(i, i->ir);
            } else
            {
              if ((i->ir < 32) || (i->ir > 126))
              {
                fi_unimp(i);
              } else
              {
#ifndef FBBI_MINIMAL
                if(b93) b93instable[(char)i->ir-32](i); else
#endif
                instable[(char)i->ir-32](i);
              }
            }
          }
          DEBUG("* End Interpret *");

          ec = (int)i->ec;
          DEBUG("Freeing IP");
          ip_free(i);
          DEBUG("Freeing Funge-Space");
          bfspace_free(p);

        } else
        {
          DEBUG("Freeing IP");
          ip_free(i);
          DEBUG("Freeing Funge-Space");
          bfspace_free(p);
          fclose(f);
#ifndef FBBI_MINIMAL
          fprintf(stderr, "fbbi error: can't load file\n");
#endif
          exit(1);
        }
      } else
      {
        DEBUG("Freeing IP");
        ip_free(i);
        DEBUG("Freeing Funge-Space");
        bfspace_free(p);
#ifndef FBBI_MINIMAL
        fprintf(stderr, "fbbi error: can't open file\n");
#endif
        exit(1);
      }
    } else
    {
      DEBUG("Freeing Funge-Space");
      bfspace_free(p);
#ifndef FBBI_MINIMAL
      fprintf(stderr, "fbbi error: can't allocate ip\n");
#endif
      exit(1);
    }
  } else
  {
#ifndef FBBI_MINIMAL
    fprintf(stderr, "fbbi error: can't allocate befunge-space\n");
#endif
    exit(1);
  }
  return ec;
}