#define NAME	 "xDir"
#define REVISION "2"

/* Programmheader

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

 1.2   29.11.96 : reworked for new includes
*/

#include <stdlib.h>
#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>

#ifdef __MAXON__
  #define __asm
#endif

struct Library *XpkBase = 0;

#define MAXLINES 2000

UBYTE errbuf[XPKERRMSGSIZE + 1], *Line[MAXLINES];
struct FileInfoBlock *Fib;
LONG utot, ctot, Lines;
UBYTE buf[300];

void exitem(STRPTR name);
void exfile(struct FileInfoBlock *fib);
void print(STRPTR str);
void showlines(void);

void end(STRPTR text)
{
  if(text)	print(text);
  if(XpkBase)	CloseLibrary(XpkBase);
  exit(text ? 10 : 0);
}

UBYTE usage[]= "Usage: xDir files/dirs\n";

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

  if(argc == 2 && !stricmp (argv[1], "?"))
    end(usage);

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

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

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

  if(*argv[1] == '-')
    end (usage);

  print("Original  Packed  Ratio Type Protection Name\n");
  print("-------- -------- ----- ---- ---------- ----\n");
  for(i = 1; i < argc; i++)
    exitem(argv[i]);

  showlines();

  if(utot)
    ratio = 100 - 100 * ctot / utot;
  print("-------- -------- -----\n");
  sprintf(buf, "%8ld %8ld  %2ld%%\n", utot, ctot, ratio);
  print(buf);

  end(NULL);
}

void showlines(void)
{
  LONG 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");
  }
  Lines = 0;
}

void print(STRPTR str)
{
  Write(Output(), str, strlen (str));
}

STRPTR dirname(STRPTR rp)
{
  static UBYTE dir[200];
  STRPTR wp = dir, lp = dir;

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

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

  if(!(lock = Lock (name, ACCESS_READ)))
  {
    sprintf(buf, "Error %ld reading %s\n", IoErr(), name);
    print(buf);
    return;
  }

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

  if(Fib->fib_DirEntryType < 0)
  {
    UnLock(lock);
    if(!(lock = Lock (dirname (name), ACCESS_READ)))
    {
      sprintf (buf, "Error locking %s\n", name);
      print (buf);
      return;
    }

    prev = CurrentDir(lock);
    exfile(Fib);
    UnLock(CurrentDir(prev));
  }
  else
  {
    prev = CurrentDir (lock);

    if(Lines)
    {
      showlines();
      print("\n");
    }

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

void exfile(struct FileInfoBlock *fib)
{
  struct XpkFib xfib;
  UBYTE prot[10];
  LONG i, clen = 0, ulen = 0;
  UBYTE 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, fib->fib_FileName,
		    TAG_DONE) || xfib.xf_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.xf_ULen,
	     clen = xfib.xf_CLen,
	     xfib.xf_Ratio,
	     xfib.xf_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((STRPTR) malloc(strlen(buf) + 1), buf);

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

  utot += ulen;
  ctot += clen;
}
