/*
 * lc - a directory lister in the style of the Waterloo lc for BSD Unix
 *
 * Copyright 1989 Edwin Hoogerbeets
 *
 * This code is freely redistributable as long as no charge other than
 * reasonable copying fees is levied for it.
 *
 *
 * Usage: lc [-dfa] [directory ...]
 *
 *    -d only list directories
 *    -f only list files
 *    -a all files  (useful for listing the directory called "-d")
 *
 */
#include <stdio.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <ctype.h>
#include <errno.h>

#define NUMFILES 500
#define WIDTH 15
#define FILENAMESIZE 31
#define FIBSIZE (long)sizeof(struct FileInfoBlock)
#define TABSIZE (long)NUMFILES*FILENAMESIZE
#define isdir(a) (filetype(a) == 1)

typedef char (*filearray)[NUMFILES][FILENAMESIZE];

/* don't need no steekeen work bench */
_wb_parse() {}

/*
 * case insensitive compare strings. From edlib v1.1. Used with permission
 * from the author. 8-)
 */
int stricmp(str1,str2)
register char *str1,*str2;
{
  register int index = 0;

  while ( str1[index] && str2[index] &&
          tolower(str1[index]) == tolower(str2[index]) )
    ++index;

  return( (tolower(str1[index]) < tolower(str2[index])) ? -1 :
        ( (tolower(str1[index]) > tolower(str2[index])) ?  1 : 0) );
}


extern char             *AllocMem();
extern struct FileLock  *Lock();

/* also from edlib */
int filetype(path)
char *path;
{
  register struct FileInfoBlock *fib;
  register struct FileLock *lock;
  register int result;


  if ( !(fib = (struct FileInfoBlock *) AllocMem(FIBSIZE,MEMF_CLEAR)) ) {
    errno = ENOMEM;
    return(-1);
  }

  if ( !(lock = Lock(path,ACCESS_READ)) ) {
    errno = EACCES;
    return(-1);
  }

  Examine(lock,fib);

  result = ( fib->fib_DirEntryType > 0 ) ? 1 : 0;

  UnLock(lock);
  FreeMem(fib,FIBSIZE);

  return(result);
}

int windowsize()
{
  register char c;
  register int n = 0, width;
  char buffer[32];

  set_raw();

  printf("\2330 q"); /* get window bounds */

  n = 0;

  while( (buffer[n] = getchar()) != 'r' && n++ < 32);

  c = buffer[n-3];

  width = ( (c <= '9' && c > '0') ? (c - '0') * 10 : 0 )
          + buffer[n-2] - '0';

  buffer[n-1] = '\0';

  set_con();

  return(width);
}

usage()
{
  fprintf(stderr,"Usage: lc [-dfa] [directory ...]\n");
  exit(1);
}

int dflag = 0;   /* display the directories? */
int fflag = 0;   /* display the files? */

main(argc,argv)
int argc;
char **argv;
{
  register int index = 1;

  if ( argc > 1 ) {

    /* option must be first argument */
    if ( *argv[index] == '-' ) {

      switch ( argv[index][1] ) {

        case 'd':

          /* only do directories */
          dflag = 1;

          /* advance the index to the next argument */
          ++index;
          break;

        case 'f':

          /* only do files */
          fflag = 1;

          /* advance the index to the next argument */
          ++index;
          break;

        case 'a':
          /* do both, and skip this argument */
          dflag = fflag = 1;
          ++index;
          break;

        default:
          usage();
          break;
      }

    } else {
      /* do both */
      dflag = fflag = 1;
    }

    switch ( argc - index ) {

      case 0:
        lc("");
        break;

      case 1:
        lc(argv[index]);
        break;

      default:
        for ( ; index < argc ; index++ ) {
          printf("%s contains:\n",argv[index]);
          lc(argv[index]);
          if ( index < argc -1 )  {
            printf("\n");
          }
        }
        break;
     }
  } else {
    /* do both */
    dflag = fflag = 1;

    lc("");
  }

  exit(0);
}

char *nomem = "Fatal: Not enough memory\n";

lc(dir)
char *dir;
{
  register filearray dtab, ftab;
  register struct FileLock *lock;
  register struct FileInfoBlock *fib;
  register int findex = 0, dindex = 0;
  int i, j, foo;

  if ( !isdir(dir) ) {
    printf("%s: not a directory\n\n",dir);
    return(1);
  }

  if ( !(dtab = (filearray) AllocMem(TABSIZE,MEMF_CLEAR)) ) {
    fprintf(stderr,nomem);
    exit(2);
  }

  if ( !(ftab = (filearray) AllocMem(TABSIZE,MEMF_CLEAR)) ) {
    fprintf(stderr,nomem);
    FreeMem(dtab,TABSIZE);
    exit(2);
  }

  if ( !(fib = (struct FileInfoBlock *) AllocMem(FIBSIZE,MEMF_CLEAR)) ) {
    fprintf(stderr,nomem);
    FreeMem(ftab,TABSIZE);
    FreeMem(dtab,TABSIZE);
    exit(2);
  }

  if ( !(lock = Lock(dir,ACCESS_READ)) ) {
    fprintf("Error: Could not get a lock on directory %s\n",dir);
    FreeMem(ftab,TABSIZE);
    FreeMem(dtab,TABSIZE);
    return(1);
  }

  Examine(lock,fib);

#ifdef DEBUG
  printf("directory: %s\n",&fib->fib_FileName[0]);
#endif

  while ( ExNext(lock,fib) ) {
    strncpy(fib->fib_DirEntryType > 0 ? &(*dtab)[dindex++] :
            &(*ftab)[findex++],&fib->fib_FileName[0],FILENAMESIZE);
#ifdef DEBUG
    printf("file: %s\n",&fib->fib_FileName[0]);
#endif
  }

#ifdef DEBUG
  printf("%d Directories and %d Files\n", dindex, findex);

  for ( i = 0 ; i < findex ; i++ ) {
    printf("unsorted file %d: %s\n",i,&(*ftab)[i]);
  }
#endif

  if ( dflag && dindex ) {

    printf("Directories:\n");
    list(dtab,dindex,FILENAMESIZE,stricmp);

  }

  if ( fflag && findex ) {

    if ( dflag && dindex ) {
      printf("\n");
    }

    printf("Files:\n");
    list(ftab,findex,FILENAMESIZE,stricmp);

  }

  FreeMem(fib,FIBSIZE);
  FreeMem(ftab,TABSIZE);
  FreeMem(dtab,TABSIZE);
  UnLock(lock);

  return(0);
}

#define pad(x) (((x)<15)?16:32)

list(table,n,size,func)
filearray table;
int n, size;
int (*func)();
{
  register int i, len, col, padded, rightcolumn = windowsize();

  if ( n > 1 ) {
    quicksort(table,n,size,func);
  }

  for ( i = 0, col = 0 ; i < n ; i++ ) {

    len = strlen(&(*table)[i]);
    padded = len + WIDTH - len % WIDTH;

    if ( col + padded > rightcolumn ) {
      printf("\n");
      col = 0;
    }

    col += padded;
    printf("%-*s",padded,&(*table)[i]);

  }

  if ( col < rightcolumn )  {
    printf("\n");
  }

}

quicksort(array, n, size, func)
char *array;
int n, size;
int (*func)();
{
   int b;

   if (n > 0) {
      b = partition(&array[0], n, size, func);
      quicksort(&array[0], b, size, func);
      quicksort(&array[(b+1)*size], n - b - 1, size, func);
   }
}

partition(array, n, size, func)
char *array;
int n, size;
int (*func)();
{
  int i, b;
  char *pivot, *scr;

  scr = AllocMem((long)size,MEMF_CLEAR);

  pivot = &array[0];

  for (b = 0, i = 1; i < n; ++i) {

    if ( func(&array[(i)*size],pivot) < 0) {
      ++b;
      strncpy(scr,&array[(i)*size],size);
      strncpy(&array[(i)*size],&array[(b)*size],size);
      strncpy(&array[(b)*size],scr,size);
    }
  }

  strncpy(scr,&array[0],size);
  strncpy(&array[0],&array[(b)*size],size);
  strncpy(&array[(b)*size],scr,size);

  FreeMem(scr,(long)size);

  return (b);
}



