/* SAS 5.0a: lc -cfrusti -b1 -v -L TypeIFF.c */
// TypeIFF.c:  Takes any IFF file and tells you ASCII chars' in it.
// Based on original sift.c by by Stuart Ferguson and Leo Schwab

#include <exec/types.h>
#include <exec/memory.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/iffparse.h>

#include <libraries/dosextens.h>
#include <libraries/iffparse.h>

#include <stdio.h>

#define ChunkMoreBytes(cn)      (cn->cn_Size - cn->cn_Scan)

//-----------------------------------------------------------------------
extern struct Library *OpenLibrary(UBYTE *libName, unsigned long version);
extern BPTR Open(UBYTE *name, long accessMode);
extern void exit(long returnCode);

void main(int argc, char **argv);
void die(long rc);
void PrintTopChunk(struct IFFHandle *iff);

#ifdef LATTICE
// How to do it with Manx ???
int CXBRK(void) { return(0); }     // Disable Lattice CTRL/C
int chkabort(void) { return(0); }  // handling
#endif

//-----------------------------------------------------------------------
UBYTE *vers = "$VER: TypeIFF 1.1 (25.07.92)";
UBYTE *Copyright =
  "TypeIFF v1.1\n1992 Matija Milostnik. This is public domain";
UBYTE *usage = "Usage: TypeIFF <file> or TypeIFF -c";

// English error messages for possible IFFERR_#? returns from various
// IFF routines.  To get the index into this array, take your IFFERR code,
// negate it, and subtract one.
// idx = -error - 1;

char  *errormsgs[] = {
   "End of file (not an error).",
   "End of context (not an error).",
   "No lexical scope.",
   "Insufficient memory.",
   "Stream read error.",
   "Stream write error.",
   "Stream seek error.",
   "File is corrupt.",
   "IFF syntax error.",
   "Not an IFF file.",
   "Required call-back hook missing.",
   "Return to client.  You should never see this."
};

struct Library *IFFParseBase;
struct IFFHandle  *iff = NULL;
short       cbio;
long        rc;

//-----------------------------------------------------------------------
void main(int argc, char *argv[])
{
   long  error;

   // Check to see if an filename argument was passed
   if (argc < 2) {
      printf ("usage: %s [-c] <file>\n", argv[0]);
      die(0);
   }
   // Check to see if user needs help
   if (argv[1][0] == '?') {
      printf ("%s\n%s\n",Copyright,usage);
      die(0);
   }

   // Check to see if were doing I/O to the Clipboard
   cbio = (argv[1][0] == '-'  
       &&  argv[1][1] == 'c');

   if (!(IFFParseBase = OpenLibrary ("iffparse.library", 36L))) {
      puts ("Can't open iff parsing library.");
      die(5);
   }

   // Allocate IFF_File structure
   if (!(iff = AllocIFF ())) {
      puts ("AllocIFF() failed.");
      die(5);
   }

   // Internal support for AmigaDOS and clipboard.device
   if (cbio) {
      // Set up IFF_File for Clipboard I/O
      if (!(iff->iff_Stream =
            (ULONG) OpenClipboard(PRIMARY_CLIP)))
      {
         puts ("Clipboard open failed");
         die(5);
      }
      InitIFFasClip (iff);
   } else {
      // Set up IFF_File for AmigaDOS I/O
      if (!(iff->iff_Stream = Open (argv[1], MODE_OLDFILE))) {
         puts ("File open failed.");
         die(5);
      }
      InitIFFasDOS (iff);
   }

   // Start the IFF transaction
   if (error = OpenIFF (iff, IFFF_READ)) {
      puts ("OpenIFF failed");
      die(5);
   }

   while (1) {

      // The interesting bit.  IFFPARSE_RAWSTEP permits us to
      // have precision monitoring of the parsing process, which
      // is necessary if we wish to print the structure of an
      // IFF file.  ParseIFF() with _RAWSTEP will return the
      // following things for the following reasons:
      // Return code:         Reason:
      // 0              Entered new context
      // IFFERR_EOC        About to leave a context
      // IFFERR_EOF        Encountered end-of-file
      // <anything else>      A parsing error
      
      error = ParseIFF (iff, IFFPARSE_RAWSTEP);

      // Since we're only interested in when we enter a context,
      // we "discard" end-of-context (_EOC) events

      if (error == IFFERR_EOC)
         continue;
      else if (error)
         // Leave the loop if there is any other error
         break;
      else if( SetSignal(0L,0L) & SIGBREAKF_CTRL_C )
         {
            printf("***Break\n");
            die(10);
         }
      // Print out the current state of affairs
      PrintTopChunk (iff);
   }


   // If error is IFFERR_EOF, then the parser encountered the end of
   // the file without problems.  Otherwise, we print a diagnostic

   if (error != IFFERR_EOF) {
      printf ("File scan aborted, error %ld: %s\n",
         error, errormsgs[-error - 1]);
      die(5);
   } else {
      die(0);
   }
}


void die(long rc)
{
   if (iff) {
      // Terminate.  Free all structures
      CloseIFF (iff);

      // Close the stream itself
      if (iff->iff_Stream)
         if (cbio)
            CloseClipboard ( (struct ClipboardHandle *)iff->iff_Stream);
         else
            Close (iff->iff_Stream);

      // Free the IFF_File structure itself
      FreeIFF (iff);
   }
   if (IFFParseBase) CloseLibrary (IFFParseBase);
   exit(rc);
}


void PrintTopChunk(struct IFFHandle *iff)
{
   struct ContextNode   *top;
   char           *mem;
   LONG           sbytes;

   // Get a pointer to the context node describing the current context
   if (!(top = CurrentChunk (iff)))
      return;
   // StopChunk() doesnt fullfill all hits
   // Add here the chunk you are looking for
   if ((top->cn_ID == MAKE_ID('A','N','N','O'))
   ||  (top->cn_ID == MAKE_ID('A','U','T','H'))
   ||  (top->cn_ID == MAKE_ID('C','H','R','S'))
   ||  (top->cn_ID == MAKE_ID('F','V','E','R'))
   ||  (top->cn_ID == MAKE_ID('N','A','M','E'))
   ||  (top->cn_ID == MAKE_ID('T','E','X','T'))
   ||  (top->cn_ID == MAKE_ID('(','c',')',' '))
   ||  (top->cn_ID == MAKE_ID('C','S','T','R'))) {
      sbytes  = ChunkMoreBytes(CurrentChunk(iff));
      if( mem = AllocMem(sbytes+1, MEMF_PUBLIC)) {
         if(ReadChunkBytes(iff,mem,sbytes) == sbytes) {
            mem[sbytes] = 0;        // null termination
            printf("%s\n",mem);
         }
         FreeMem(mem,sbytes);
      }
   }
}

