#define NAME	 "xDir"
#define REVISION "3"

/* Programmheader

	Name:		xDir
	Author:		SDI (before 1.2 Urban Dominik Müller)
	Distribution:	PD
	Description:	xpk file lister
	Compileropts:	-
	Linkeropts:	-l xpkmaster

 1.0	: first public release
 1.1	: Enforcer hit fixed, version string added, wrote documentation
 1.2   29.11.96 : reworked for new includes
 1.3   24.04.97 : fixed lots of errors, made a lot shorter, easier
*/

#include "SDI_defines.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/xpkmaster_lib.h>
#include <exec/memory.h>

#ifdef __MAXON__
  #define __asm
#endif

#define MAXLINES 2000

struct Library *	XpkBase	= 0;
struct FileInfoBlock *	fib	= 0;
STRPTR			Line[MAXLINES];
ULONG			utot	= 0,
			ctot	= 0,
			Lines	= 0;

void exitem(STRPTR name);
void exfile(void);
void FreeLines(void);

void end(STRPTR text)
{
  if(text)	printf(text);
  if(XpkBase)	CloseLibrary(XpkBase);
  if(fib)	FreeMem(fib, sizeof(struct FileInfoBlock));
  FreeLines();
  exit(text ? 10 : 0);
}

void FreeLines(void)
{
  while(Lines)
    FreeMem(Line[--Lines], 200);
}

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

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

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

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

  if(!(fib = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
    end("Not enough memory\n");

  printf("Original  Packed  Ratio Type Protection Name\n"
         "-------- -------- ----- ---- ---------- ----\n");

  for(i = 1; i < argc;)
  {
    exitem(argv[i]);
    if(++i < argc)
      printf("\n");
  }

  ratio = (utot && utot < ctot) ? 100 - (100 * ctot) / utot : 0;
  printf("-------- -------- -----\n%8ld %8ld  %2ld%%\n", utot, ctot, ratio);

  end(0);
}

void exitem(STRPTR name)
{
  BPTR lock, prev;
  ULONG i;

  if(!(lock = Lock(name, ACCESS_READ)))
  {
    printf("Error %ld locking %s\n", IoErr(), name);
    return;
  }

  if(!Examine(lock, fib))
  {
    UnLock(lock);
    printf("Error %ld locking %s\n", IoErr(), name);
    return;
  }

  if(fib->fib_DirEntryType < 0)
  {
    UnLock(lock);
    name[strlen(name)-strlen(fib->fib_FileName)] = 0; /* cut the filename */
    if(!(lock = Lock(name, ACCESS_READ)))
    {
      printf("Error locking %s\n", name);
      return;
    }
    prev = CurrentDir(lock);
    exfile();
    UnLock(CurrentDir(prev));
  }
  else
  {
    prev = CurrentDir(lock);

    while(ExNext(lock, fib))
      exfile();
    UnLock(CurrentDir(prev));
  }

  for(i = 0; i < Lines; ++i)
  {
    printf(Line[i]);
    if(SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
      end(" *** Break\n");
  }
  FreeLines();
}

void exfile(void)
{
  struct XpkFib xfib;
  UBYTE prot[9];
  ULONG clen = 0, ulen = 0;
  LONG i;
  STRPTR buf;

  if(SetSignal (0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
    end(" *** Break\n");
  if(Lines >= MAXLINES-1 || !(buf = (STRPTR) AllocMem(200, MEMF_ANY)))
    end("Buffer overflow or no memory\n");
  else
  {
    prot[0] = fib->fib_DirEntryType < 0 ? '-' : 'D';
    for(i = 0; i < 8; i++)
      prot[8 - i] = (fib->fib_Protection ^ 0x0f) & (1 << i) ? "dewrapsh"[i] : '-';

    if(fib->fib_EntryType >= 0)
      sprintf(buf,  "%8s                     %.9s  %-20s\n",
	"<Dir>", prot, fib->fib_FileName);
    else if(!XpkExamineTags(&xfib, XPK_InName, fib->fib_FileName, TAG_DONE) &&
    xfib.xf_Type == XPKTYPE_PACKED)
      sprintf(buf,   "%8ld %8ld  %2ld%%  %4s  %.9s  %-20s\n",
	ulen = xfib.xf_ULen, clen = xfib.xf_CLen, xfib.xf_Ratio,
	xfib.xf_Packer, prot, fib->fib_FileName);
    else
      sprintf(buf, "%8ld                     %.9s  %-20s\n",
	clen = ulen = fib->fib_Size, prot, fib->fib_FileName);

    utot += ulen;
    ctot += clen;

    /* sort and insert the new line */
    for(i = Lines - 1; i >= 0 && stricmp(Line[i] + 40, buf + 40) > 0; i--)
      Line[i + 1] = Line[i];
    Line[i + 1] = buf;

    ++Lines;
  }
}

