/* ------------------------------------------------------------------------- */
/*   "infact" :  A small utility to print out an Infix-style debugging info  */
/*               file.  Includes no non-system files.                        */
/*                                                                           */
/*   (C) Copyright Graham Nelson, 1994                                       */
/*                                                                           */
/*   See the format description file                                         */
/*                                                                           */
/*   For use with Inform release 5.4 or later                                */
/* ------------------------------------------------------------------------- */

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

#define ARCHIMEDES

#ifdef ARCHIMEDES
#define Debugging_Name  "Game_Debug"
#endif
#ifdef UNIX
#define Debugging_Name  "game.dbg"
#endif
#ifdef LINUX
#define Debugging_Name  "game.dbg"
#endif
#ifdef PC
#define Debugging_Name  "game.dbg"
#endif
#ifdef VAX
#define Debugging_Name  "game.dbg"
#endif
#ifdef AMIGA
#define Debugging_Name  "game.dbg"
#endif
#ifdef ATARIST
#define Debugging_Name  "game.dbg"
#endif
#ifdef OS2
#define Debugging_Name  "game.dbg"
#endif
#ifdef MACINTOSH
#define Debugging_Name  "game.debug"
#endif
#ifndef Debugging_Name
#define Debugging_Name  "debuginf"
#endif

extern void fatalerror(char *s)
{   printf("Fatal error: %s\n",s);
    exit(1);
}

static void couldntopen(char *m, char *fn)
{   char err_buffer[128];
    sprintf(err_buffer, "%s \"%s\"", m, fn);
    fatalerror(err_buffer);
}

static FILE *Debug_fp;
extern void open_debug_file(void)
{
    Debug_fp=fopen(Debugging_Name,"rb");
    if (Debug_fp==NULL) couldntopen("Couldn't open debugging info file",
        Debugging_Name);
}

extern int read_debug_byte(void)
{   if (ferror(Debug_fp))
        fatalerror("I/O failure: can't write to debugging info file");
    return fgetc(Debug_fp);
}

extern void read_debug_string(char *s)
{   int i=0;
    while ((s[i]=read_debug_byte())!=0) i++;
}

typedef struct linestr_s
{   int file_no;
    int line_no;
} linestr;

extern linestr read_debug_linenum(void)
{   linestr l; int i;
    l.file_no = read_debug_byte();
    i = read_debug_byte();
    l.line_no = i*256 + read_debug_byte();
    return l;
}

extern void close_debug_file(void)
{   if (ferror(Debug_fp))
        fatalerror("I/O failure: can't close debugging info file");
    fclose(Debug_fp);
}

extern void p_debug_string(void)
{   char buffer[256];
    read_debug_string(buffer);
    printf("\"%s\"",buffer);
}

extern void p_line(linestr l)
{   printf("%d:%d",l.file_no,l.line_no);
}

extern void p_address(void)
{   long int l;
    l=read_debug_byte(); l=l*256+read_debug_byte();
    l=l*256+read_debug_byte();
    printf("%05lx (%ld)", l, l);
}

int type_flags[64];

int main(int argc, char **argv)
{   int type; linestr l1; linestr l2; int i, j, k; char *p;
    char junk[256];

    printf("Infact 1 (try \"infact -help\" for instructions)\n");

    for (i=0; i<64; i++) type_flags[i]=1;
    type_flags[10]=0; type_flags[12]=0; type_flags[15]=0;

    if (argc>1)
    {   for (i=0; i<64; i++) type_flags[i]=0;
        for (i=1; i<argc; i++)
        {   p=argv[i];
            if (p[0]!='-') printf("Switches must begin with a -\n"); else p++;
            if (strcmp(p,"help")==0)
            {   printf(
"\"Infact\" is an utility to print out the information in an Infix format \n\
debugging data file, produced by Inform v 5.4 or later.  By default it \n\
prints everything except line references.  Otherwise the following switches \n\
may be used:\n\n\
  -files  -classes  -objects  -globals  -attributes  -fakes  -actions  -map\n\
  -properties  -header  -lines  -code  -codeless  -routines  -source\n\
  -help  -all\n");
            }
            else
            if (strcmp(p,"files")==0) { type_flags[1]=1; type_flags[16]=1; }
            else
            if (strcmp(p,"classes")==0) type_flags[2]=1;
            else
            if (strcmp(p,"objects")==0) type_flags[3]=1;
            else
            if (strcmp(p,"globals")==0) type_flags[4]=1;
            else
            if (strcmp(p,"attributes")==0) type_flags[5]=1;
            else
            if (strcmp(p,"properties")==0) type_flags[6]=1;
            else
            if (strcmp(p,"fakes")==0) type_flags[7]=1;
            else
            if (strcmp(p,"actions")==0) type_flags[8]=1;
            else
            if (strcmp(p,"header")==0) type_flags[9]=1;
            else
            if (strcmp(p,"lines")==0) { type_flags[10]=1; type_flags[12]=1; }
            else
            if (strcmp(p,"code")==0) type_flags[10]=1;
            else
            if (strcmp(p,"routines")==0) { type_flags[11]=1; type_flags[14]=1; }
            else
            if (strcmp(p,"codeless")==0) type_flags[12]=1;
            else
            if (strcmp(p,"map")==0) type_flags[13]=1;
            else
            if (strcmp(p,"source")==0) type_flags[15]=1;
            else
            if (strcmp(p,"all")==0)
                for (i=0; i<64; i++) type_flags[i]=1;
            else printf("Switch -%s unknown\n",p);
        }
    }

    open_debug_file();

    i=read_debug_byte(); j=read_debug_byte();
    k=read_debug_byte(); k=k*256+read_debug_byte();
    printf("Debugging file from Inform %d.%d (v %d)\n",i,j,k);

    do
    {   type=read_debug_byte();
        if (type>16) printf("Unknown type %d\n",type);
        if (type_flags[type]==1)
        switch(type)
        {   case 1: printf("File %d ",read_debug_byte()); p_debug_string();
                    printf(" expanding to "); p_debug_string(); printf("\n");
                    break;
            case 2: l1=read_debug_linenum();
                    printf("Class "); p_debug_string();
                    l2=read_debug_linenum();
                    printf(" from "); p_line(l1);
                    printf(" to "); p_line(l2); printf("\n"); break;
            case 3: k=read_debug_byte(); k=k*256+read_debug_byte();
                    l1=read_debug_linenum();
                    printf("Object %d ", k); p_debug_string();
                    l2=read_debug_linenum();
                    printf(" from "); p_line(l1);
                    printf(" to "); p_line(l2); printf("\n"); break;
            case 4: printf("Global %d ",read_debug_byte());
                    p_debug_string(); printf("\n"); break;
            case 5: printf("Attribute %d ",read_debug_byte());
                    p_debug_string(); printf("\n"); break;
            case 6: printf("Property %d ",read_debug_byte());
                    p_debug_string(); printf("\n"); break;
            case 7: printf("Action %d ",read_debug_byte());
                    p_debug_string(); printf(" (fake)\n"); break;
            case 8: printf("Action %d ",read_debug_byte());
                    p_debug_string(); printf(" (real)\n"); break;
            case 9: printf("Header of game file is:\n");
                    for (i=0; i<64; i++)
                        printf("%02x ",read_debug_byte());
                    printf("\n"); break;
            case 10: printf("Code line "); p_line(read_debug_linenum());
                     printf(" at (byte address) ");
                     p_address(); printf("\n"); break;
            case 11: k=read_debug_byte(); k=k*256+read_debug_byte();
                     printf("Routine %d (line ",k);
                     l1=read_debug_linenum(); p_line(l1); printf(") ");
                     p_debug_string();
                     while (read_debug_string(junk), junk[0]!=0)
                         printf(" %s",junk);
                     printf("\n"); break;
            case 12: printf("Codeless line "); p_line(read_debug_linenum());
                     printf("\n"); break;
            case 13: printf("Memory map:\n");
                     printf("  array area "); p_address(); printf(" to ");
                     p_address();
                     printf("\n  dictionary "); p_address();
                     printf("\n  code area  "); p_address();
                     printf("\n  strings    "); p_address();
                     printf("\n");
                     break;
            case 14: k=read_debug_byte(); k=k*256+read_debug_byte();
                     printf("Routine %d ends on line ",k);
                     p_line(read_debug_linenum()); printf("\n"); break;
            case 15: printf("Line "); p_line(read_debug_linenum());
                     printf(" is at byte "); p_address();
                     printf(" in its file\n"); break;
            case 16: printf("Size of file %d is ",read_debug_byte());
                     p_address();
                     k=read_debug_byte(); k=k*256+read_debug_byte();
                     printf(" chars, %d lines\n",k); break;
        }
        else
        switch(type)
        {   case 1: read_debug_byte(); read_debug_string(junk);
                    read_debug_string(junk); break;
            case 2: read_debug_linenum();
                    read_debug_string(junk);
                    read_debug_linenum();
                    break;
            case 3: read_debug_byte(); read_debug_byte(); read_debug_linenum();
                    read_debug_string(junk);
                    read_debug_linenum();
                    break;
            case 4: case 5: case 6: case 7: case 8: read_debug_byte();
                    read_debug_string(junk); break;
            case 9: for (i=0; i<64; i++) read_debug_byte(); break;
            case 10: read_debug_linenum();
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     break;
            case 11: read_debug_byte(); read_debug_byte();
                     read_debug_linenum(); read_debug_string(junk);
                     while (read_debug_string(junk), junk[0]!=0);
                     break;
            case 12: read_debug_linenum(); break;
            case 13: 
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     break;
            case 14: read_debug_byte(); read_debug_byte();
                     read_debug_linenum(); break;
            case 15: read_debug_linenum(); 
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     break;
            case 16: read_debug_byte(); read_debug_byte(); read_debug_byte();
                     read_debug_byte(); read_debug_byte(); read_debug_byte();
                     break;
        }

    } while (type!=0);
    close_debug_file();
}
