home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
001-099
/
ff075.lzh
/
Eless
/
eless.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-05-28
|
8KB
|
308 lines
/* :ts=8 bk=0
*
* eless.c: An attempt at a reasonable-speed 'ls' program by fiddling
* with the DOS.
*
* Compiles under Manx 3.20 and patched 3.40.
* cc eless.c
* ln eless.c -lc -o eless
*
* Leo L. Schwab 8704.26 (415)-456-6565
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>
#define BLOCKSIZE 128
#define STARTTAB 6
#define ENDTAB (BLOCKSIZE-51)
#define TABSIZ (BLOCKSIZE-56)
#define FILENAME (BLOCKSIZE-20)
#define HASHCHAIN (BLOCKSIZE-4)
#define SECONDARY (BLOCKSIZE-1)
#define ST_DIR 2
#define ST_FILE -3
/*
* Note: I usually declare Amiga functions this way to disable the compiler's
* type checking. This allows me to assign values to variables without
* explicitly casting them to the appropriate type. In reality, these
* functions return things entirely different from the way I've declared
* them. For example, CreatePort() should really be declared as:
*
* struct MsgPort *CreatePort();
*
* Caveat Programmer.
*/
extern void *AllocMem(), *CreatePort(), *RemTail(), *FindTask();
extern long Lock(), Examine();
long dopacket();
int longcmp(), namecmp();
struct StandardPacket *packet;
struct FileInfoBlock *fib;
struct FileLock *lock;
struct InfoData *id;
struct MsgPort *dosreply;
BPTR lok;
long *buf, hashtab[TABSIZ];
main (ac, av)
char **av;
{
int flag;
openstuff ();
if (ac < 2) /* No arguments; do current directory */
printdir (((struct Process *) FindTask (0L)) -> pr_CurrentDir);
else { /* Arguments; treat as directories */
flag = (ac > 2);
while (++av, --ac) {
if (!(lok = Lock (*av, ACCESS_READ))) {
printf ("%s: Not found.\n", *av);
if (ac > 1)
putchar ('\n');
continue;
}
if (!Examine (lok, fib))
die ("Examine failed.");
if (fib -> fib_DirEntryType < 0) {
printf ("%s: Not a directory.\n", *av);
if (ac > 1)
putchar ('\n');
continue;
}
if (flag)
printf ("%s:\n", *av);
printdir (lok);
if (ac > 1)
putchar ('\n');
UnLock (lok); lok = NULL;
}
}
closestuff ();
}
/*
* This function prints the directory in a nice, pretty columnar format.
*/
printdir (dirlock)
BPTR dirlock;
{
struct List namelist;
register struct Node *name, **namearray;
long args[2];
register int i, n;
int len = 0, ncols, nlines, nfiles = 0;
char fmt1[16], fmt2[16];
char *fn = (char *) (&buf[FILENAME]) + 1;
lock = (struct FileLock *) (dirlock << 2);
args[0] = lock -> fl_Key; /* Block number */
args[1] = (long) buf >> 2; /* BPTR to buffer */
/* Attempt to get raw directory block. */
if (!dopacket (lock -> fl_Task, ACTION_GET_BLOCK, args, 2)) {
if (packet -> sp_Pkt.dp_Res2 == ERROR_ACTION_NOT_KNOWN)
printf ("Not a block device.\n");
else
printf ("Error %ld while getting dirblock.\n",
packet -> sp_Pkt.dp_Res2);
return;
}
/* Copy DOS's hash table into our array. */
for (i=0; i<TABSIZ; i++)
hashtab[i] = buf[i+STARTTAB];
NewList (&namelist);
while (1) {
/* Sort hash table. */
qsort (hashtab, TABSIZ, sizeof (long), longcmp);
if (!hashtab[0]) /* Empty hash table */
break;
/*
* Retrieve disk blocks according to sorted hash table and
* collect filenames.
*/
for (i=0; hashtab[i] && i<TABSIZ; i++) {
args[0] = hashtab[i];
dopacket (lock -> fl_Task, ACTION_GET_BLOCK, args, 2);
if (!(name = AllocMem (sizeof (*name) + *(fn-1) + 1L,
MEMF_CLEAR))) {
puts ("Node memory allocation failure.");
goto bombout;
}
name -> ln_Name = (char *) name + sizeof (*name);
name -> ln_Type = (buf[SECONDARY] == ST_DIR);
fn[*(fn-1)] = '\0'; /* Force null-termination */
strcpy (name -> ln_Name, fn);
AddTail (&namelist, name);
nfiles++; /* Number of files found */
hashtab[i] = buf[HASHCHAIN];
}
}
if (!nfiles) /* No files */
return;
/* Create array that qsort can deal with. */
if (!(namearray = AllocMem
((long) nfiles * sizeof (char *), MEMF_CLEAR))) {
puts ("Name array allocation failure.");
goto bombout;
}
/* Load up the array. */
for (name = namelist.lh_Head, i=0;
name -> ln_Succ;
name = name -> ln_Succ, i++)
namearray[i] = name;
/* Alphabetize filenames. */
qsort (namearray, nfiles, sizeof (struct Node *), namecmp);
/* Find longest string so we can format intelligently. */
for (i=0; i<nfiles; i++)
if ((n = strlen (namearray[i] -> ln_Name)) > len)
len = n;
len += 2; /* Inter-name spacing */
/* Print them suckers out */
ncols = 77 / len; /* Assume CON: is 77 columns */
nlines = nfiles/ncols + (nfiles%ncols != 0);
sprintf (fmt1, "%%-%ds", len); /* Normal format string */
sprintf (fmt2, "\033[33m%%-%ds\033[m", len); /* For directories */
for (i=0; i<nlines; i++) {
for (n=i; n<nfiles; n+=nlines)
printf (namearray[n] -> ln_Type ? fmt2 : fmt1,
namearray[n] -> ln_Name);
putchar ('\n');
}
/* Phew! Now free all the stuff we allocated. */
bombout:
freenamelist (&namelist);
if (namearray)
FreeMem (namearray, (long) nfiles * sizeof (struct Node *));
}
freenamelist (list)
struct List *list;
{
register struct Node *now;
while (now = RemTail (list))
FreeMem (now, sizeof (*now) + strlen (now -> ln_Name) + 1L);
}
/*
* This function assumes the existence of a properly initialized
* standardpacket structure called "packet" and a reply port called
* "dosreply". A more general function would not do this.
*
* This function is synchronous i.e. it doesn't return until the specified
* action has been performed.
*/
long
dopacket (proc, action, args, nargs)
struct MsgPort *proc;
long action;
register long *args;
register int nargs;
{
register long *argp = &packet -> sp_Pkt.dp_Arg1;
for (; nargs>0; nargs--)
*argp++ = *args++;
/*
* AmigaDOS scribbles over the reply port, so we have to initialize
* it every time we send a packet.
*/
packet -> sp_Pkt.dp_Port = dosreply;
packet -> sp_Pkt.dp_Type = action;
PutMsg (proc, packet);
WaitPort (dosreply);
GetMsg (dosreply);
return (packet -> sp_Pkt.dp_Res1);
}
/*
* These functions are called by qsort(). The sense of camparisons is
* reversed in longcmp to get a reverse sort (largest elements first).
*/
longcmp (foo, bar)
long *foo, *bar;
{
/*
* We have to do it this way because qsort() expects an int to be
* returned. Subtracting longs directly might overflow a 16-bit int.
*/
return ((*foo < *bar) - (*foo > *bar));
}
namecmp (foo, bar)
struct Node **foo, **bar;
{
return (strcmp ((*foo) -> ln_Name, (*bar) -> ln_Name));
}
/*
* Resource allocation/deallocation routines.
*/
openstuff ()
{
if (!(packet = AllocMem ((long) sizeof (*packet), MEMF_CLEAR)))
die ("Can't allocate packet space.");
if (!(dosreply = CreatePort (NULL, NULL)))
die ("Dos reply port create failed.");
packet -> sp_Msg.mn_Node.ln_Name = (char *) &packet -> sp_Pkt;
packet -> sp_Pkt.dp_Link = &packet -> sp_Msg;
if (!(fib = AllocMem ((long) sizeof (*fib), MEMF_CLEAR)))
die ("Can't allocate FileInfoBlock.");
/*
* Note: This allocation may not work with DMA hard disks.
*/
if (!(buf = AllocMem (BLOCKSIZE * 4L, MEMF_CHIP | MEMF_PUBLIC)))
die ("Couldn't allocate sector buffer.");
}
closestuff ()
{
if (lok) UnLock (lok);
if (buf) FreeMem (buf, BLOCKSIZE * 4L);
if (fib) FreeMem (fib, (long) sizeof (*fib));
if (dosreply) DeletePort (dosreply);
if (packet) FreeMem (packet, (long) sizeof (*packet));
}
die (str)
char *str;
{
puts (str);
closestuff ();
exit (1);
}