/*
 * 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.0 (29.03.92)";
UBYTE *Copyright =
  "TypeIFF v1.0\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 were doing I/O to the Clipboard */
	cbio = (argv[1][0] == '-'  
	    &&  argv[1][1] == 'c');

	if (!(IFFParseBase = OpenLibrary ("iffparse.library", 0L))) {
		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;

		/* 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 */
	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 terminated */
				printf("%s\n",mem);
			}
			FreeMem(mem,sbytes);
		}
	}
}
