#define NAME		"xDir"
#define DISTRIBUTION	"(Freeware) "
#define REVISION	"6"

/* Programmheader

	Name:		xDir
	Author:		SDI (before 1.2 Urban Dominik Müller)
	Distribution:	Freeware
	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
 1.4   12.07.97 : totally rewritten
 1.5   27.97.97 : little fixes
 1.6   10.03.98 : new ASM_STD includes, uses xfdmaster for checks always
*/

#include "SDI_defines.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/xpkmaster.h>
#include <exec/memory.h>

struct DataList {
  struct DataList *	next;
  UWORD			size; /* size of complete list */
  UBYTE		     text[0]; /* text data, which follows the structure */
};

#define TEXTSIZE	40

struct Library *XpkBase = 0;

ULONG exitem(STRPTR, ULONG *, ULONG *);
ULONG exfile(struct FileInfoBlock *, struct DataList *, ULONG *, ULONG *);

void main(int argc, char *argv[])
{
  ULONG ret = 20;

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

  if((XpkBase = OpenLibrary(XPKNAME, 3)))
  {
    ULONG utot = 0, ctot = 0;

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

    if(argc == 1)
      ret = exitem("", &utot, &ctot);
    else
    {
      ULONG i = 1;
      while(i < argc && !(ret = exitem(argv[i], &utot, &ctot)))
      {
        if(++i < argc)
          printf("\n");
      }
    }

    if(!ret)
      printf("-------- -------- -----\n%8ld %8ld  %2ld%%\n", utot, ctot,
      (utot && (utot > ctot)) ? 100 - (100 * ctot) / utot : 0);
  }
  else
    printf("Cannot open xpkmaster.library\n");

  if(CTRL_C)
    printf(" *** Break\n");

  exit(ret);
}

ULONG exitem(STRPTR name, ULONG *utot, ULONG *ctot)
{
  BPTR lock;
  ULONG ret = 20;

  if((lock = Lock(name, ACCESS_READ)))
  {
    struct FileInfoBlock *fib;

    if((fib = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
    {
      if(Examine(lock, fib))
      {
        struct DataList *list, *d, in = {0,0};

	list = &in;

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

	  prev = CurrentDir(lock);
	  while(ExNext(lock, fib) && !(ret = exfile(fib, list, utot, ctot)))
	    ;
	  CurrentDir(prev);
	}

	list = list->next; /* skip init entry */

	if(!ret)
	{
	  for(d = list; !CTRL_C && d; d = d->next)
	    printf("%s", d->text);
	}

	while(list) /* free the list */
	{
	  d = list->next;
	  FreeMem(list, list->size);
	  list = d;
	}
      }
      else
        printf("Error %ld locking %s\n", IoErr(), name);

      FreeMem(fib, sizeof(struct FileInfoBlock));
    }
    else
      printf("Not enough memory\n");

    if(lock)
      UnLock(lock);
  }
  else
    printf("Error %ld locking %s\n", IoErr(), name);

  return ret;
}

ULONG exfile(struct FileInfoBlock *fib, struct DataList *l, ULONG *utot, ULONG *ctot)
{
  struct DataList *dl, *le;
  ULONG listsize, fl;
  struct XpkFib xfib;
  ULONG i, clen = 0, ulen = 0;

  fl = strlen(fib->fib_FileName);
  listsize = sizeof(struct DataList) + fl + TEXTSIZE + 2; /* '\n' and '\0' */

  if(!(dl = (struct DataList *) AllocMem(listsize, MEMF_ANY|MEMF_CLEAR)))
  {
    printf("Not enough memory\n"); return 20;
  }

  memset(dl->text, ' ', 40);
  dl->size = listsize;

  if(fib->fib_EntryType >= 0)
    CopyMem("<Dir>", dl->text+3, 5);
  else if(!XpkExamineTags(&xfib, XPK_InName, fib->fib_FileName,
  XPK_UseXfdMaster, TRUE, TAG_DONE)
  && xfib.xf_Type == XPKTYPE_PACKED)
  {
    sprintf(dl->text, "%8ld %8ld  %2ld%%  %4s",
    ulen = xfib.xf_ULen, clen = xfib.xf_CLen, xfib.xf_Ratio,
    xfib.xf_Packer);
    dl->text[28] = ' ';
  }
  else
  {
    sprintf(dl->text, "%8ld", clen = ulen = fib->fib_Size);
    dl->text[8] = ' ';
  }

  dl->text[29] = fib->fib_DirEntryType < 0 ? '-' : 'D';
  for(i = 0; i < 8; i++)
    dl->text[37-i] = (fib->fib_Protection ^ 0x0f) & (1 << i) ? "dewrapsh"[i] : '-';

  *utot += ulen;
  *ctot += clen;

  CopyMem(fib->fib_FileName, dl->text+40, fl);
  dl->text[40+fl] = '\n';

  /* sort and insert the new line, skip &in entry first */
  do
  {
    le = l;
    l = l->next;
  } while(l && stricmp(l->text+40, dl->text+40) < 0);

  dl->next = l;
  le->next = dl;

  return 0;
}

