#include <libraries/xpk.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dos.h>

#define MAXLINES 2000

struct Library *XpkBase;
char errbuf[XPKERRMSGSIZE+1], *Line[MAXLINES];
struct FileInfoBlock *Fib;
long   utot, ctot, Lines;

char ver[]="$VER: xDir 1.0 ("__DATE__")";

void exitem( char *name );
void exfile( struct FileInfoBlock *fib );
void printm( );

void end( char *text )
{
	if( text )    printm( text );
	if( XpkBase ) CloseLibrary( XpkBase );
	_exit(text ? 10 : 0);
}

int breakfunc(void)
{
	end("***Break\n");
	return 0;
}

void main(int argc, char *argv[])
{
	int i, ratio=0;

	onbreak(breakfunc);

	if( argc==2 && !stricmp(argv[1],"?"))
		end("Usage: xDir files/dirs\n");

	if( !(XpkBase=OpenLibrary(XPKNAME,0)))
		end("Cannot open "XPKNAME"\n");

	if( argc<2 )
		argv[1]="", argc=2;

	if( !(Fib=AllocMem(sizeof(*Fib),0)))
		end("Not enough memory\n");

	printm("Original  Packed  Ratio Type Protection Name\n");
	printm("-------- -------- ----- ---- ---------- ----\n");
	for( i=1; i<argc; i++ )
		exitem( argv[i] );
	for( i=0; i<Lines; i++ ) {
		Write(Output(),Line[i],strlen(Line[i]));
		if( SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C )
			end(" *** Break\n");
	}


	if( utot ) ratio= 100-100*ctot/utot;
	printm("-------- -------- -----\n");
	printm("%8ld %8ld  %2ld%%\n", utot, ctot, ratio );
 
	end( NULL );
}

void printm(a1,a2,a3,a4,a5,a6,a7) char *a1;
{
	char buf[200];

	sprintf(buf,a1,a2,a3,a4,a5,a6,a7);
	Write(Output(),buf,strlen(buf));
}

char *dirname( char *rp )
{
	static char dir[200];
	char *wp=dir, *lp=dir;

	while( *rp ) {
		if( *rp==':' )
			lp=wp+1;
		if( *rp=='/' )
			lp=wp;
		*wp++=*rp++;
	}
	*lp=0;
	return dir;
}

void
exitem( char *name )
{
	BPTR lock, prev;

	if( !(lock=Lock( name, ACCESS_READ))) {
		printm("Error %d reading %s\n",IoErr(),name);
		return;
	}

	if( !Examine( lock, Fib )) {
		UnLock( lock );
		printm("Error %ld reading %s\n",IoErr(),name);
		return;
	}

	if( Fib->fib_DirEntryType<0 ) {
		UnLock( lock );
		if(!(lock=Lock( dirname( name ), ACCESS_READ))) {
			printm("Error %d reading %s\n",IoErr(),dirname(name));
			return;
		}
		prev=CurrentDir( lock );
		exfile( Fib );
		UnLock( CurrentDir(prev));
	} else {
		prev=CurrentDir( lock );
		while( ExNext(lock,Fib))
			exfile( Fib );
		UnLock( CurrentDir(prev));
	}
}

struct TagItem tags[]={ XPK_InName, NULL, XPK_PassThru, TRUE, TAG_DONE };

void
exfile( struct FileInfoBlock *fib )
{
	struct XpkFib xfib;
	char prot[10];
	int  i, clen=0, ulen=0;
	char buf[200];

	if( SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C )
		end(" *** Break\n");

	prot[0]=fib->fib_DirEntryType<0 ? '-' : 'd';
	for( i=0; i<8; i++ )
		prot[8-i]= (Fib->fib_Protection^0x0f) & (1<<i) ? "dewrapsh"[i] : '-';
	prot[9]=0;

	if( XpkExamineTags(
		&xfib,
		XPK_InName,      (long) fib->fib_FileName,
		TAG_DONE
	) || xfib.Type!=XPKTYPE_PACKED ) {
		if( fib->fib_EntryType<0 )
			sprintf(buf,"%8ld                      %9s %-20s\n",
				clen=ulen=fib->fib_Size,
				prot,
				fib->fib_FileName );
		else 
			sprintf(buf,"%8s                      %9s %-20s\n",
				"<Dir>",
				prot,
				fib->fib_FileName );
	} else 
		sprintf(buf,"%8ld %8ld  %2ld%%  %4s  %9s %-20s\n",
			ulen=xfib.ULen,
			clen=xfib.CLen,
			xfib.Ratio,
			xfib.Packer,
			prot,
			fib->fib_FileName );

	for( i=Lines-1; i>=0 && stricmp(Line[i]+40,buf+40)>0; i-- )
		Line[i+1]=Line[i];
	Line[i+1]=strcpy(malloc(strlen(buf)+1),buf);

	if( ++Lines>=MAXLINES )
		end("Buffer overflow\n");

	utot+= ulen;
	ctot+= clen;
}
