home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d09xx
/
d0905.lha
/
DTree
/
DTree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-26
|
14KB
|
497 lines
/*
** DTree.c 1.00
** Copyright (c) 1993 by Sam Yee.
** All Rights Reserved.
**
** Permission is here granted for the distribution of DTree, provided
** that files are intacted and in unmodified state.
*/
/*******************************************************************/
/* includes */
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <exec/memory.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <stdlib.h>
#include <string.h>
/*******************************************************************/
/* constants, macros, etc. */
/* passing arguments through registers sometimes yield smaller code */
#define REG(x) register __ ## x
#define ASM __asm
/* for ReadArgs() */
#define OPT_DIRS 0
#define OPT_SHOWFILES 1
#define OPT_IBMFONT 2
#define OPT_JOINCHARS 3
#define OPT_COLOR 4
#define OPT_COUNT 5
/* ansi control sequences */
#define ANSIOFF "\033[0m"
#define COLOR1 "\033[31m"
#define COLOR2 "\033[32m"
#define COLOR3 "\033[33m"
#define COLOR6 "\033[36m"
/* template for ReadArgs() */
#define TEMPLATE "DTree 1.00 -- Directory Tree Displayer\n\
Copyright (c) 1993 by Sam Yee.\n\
All Rights Reserved. Freely Distributable.\n\
Compiled on "__DATE__ " (" __TIME__").\n\n\
DIR/M,FILES/S,IBMFONT/S,JOINCHARS/K,COLOR/S"
#define LEADING_SPACES 3
/* extract a byte from 32-bit branch display character mask */
#define GET_VBAR(x) ((x) & 0xff)
#define GET_L(x) (((x) & 0xff00) >> 8)
#define GET_T90(x) (((x) & 0xff0000) >> 16)
#define GET_DASH(x) (((x) & 0xff000000) >> 24)
/*******************************************************************/
/* need these for #pragmas */
extern struct DOSBase *DOSBase;
extern struct SysBase *SysBase;
/*******************************************************************/
/* when the FILES argument is given, store each file in a node, and
display the whole linked list when the directory is done scanning
*/
typedef
struct
{
struct List list;
int node_count;
} FileList;
/*******************************************************************/
/* prototypes */
/* disable SAS/C's ^C checking */
void __regargs __chkabort(void);
void __regargs __chkabort(){}
void __regargs _CXBRK(void);
void __regargs _CXBRK(){}
BOOL tree_scan(BPTR dir_lock, struct FileInfoBlock *fib, int depth,
BOOL *nextdir_array, BOOL show_files,
ULONG join_chars, BOOL color);
struct Node * ASM AddName(REG(a0) FileList *list,
REG(a1) char *name);
BOOL ASM do_dir(REG(a0) char *dirname, REG(d0) BOOL show_files,
REG(d1) ULONG join_chars, REG(d2) BOOL color);
void ASM myqsort(REG(a0) char *v[], REG(d0) int left,
REG(d1) int right);
void ASM swap(REG(a0) char *v[], REG(d0) int i, REG(d1) int j);
char ** ASM SortFileList(REG(a0) FileList *file_list);
BOOL NextDirLock(BPTR this_lock, struct FileInfoBlock *fib,
FileList *list, BOOL *die);
/*******************************************************************/
/* some global (oh no!) data */
char *__stdiowin = NULL,
*__stdiov37 = NULL,
*version = "$VER: DTree 1.00 (14.7.93)";
/*******************************************************************/
/* main routine, what else? */
int
main(void)
{
struct RDArgs *myrda;
UBYTE **dirs;
/* IBM extended characters */
ULONG join_chars = 0x2d2b5c7c;
LONG result[OPT_COUNT];
long rc = 10,
i;
if (myrda = (struct RDArgs *)AllocDosObject(DOS_RDARGS,NULL))
{
/* read from stdin instead */
myrda->RDA_Source.CS_Buffer = NULL;
myrda->RDA_Source.CS_Length = 0L;
for (i = 0; i < OPT_COUNT; i++)
result[i] = 0L;
if (ReadArgs(TEMPLATE,result,myrda))
{
if (result[OPT_IBMFONT])
join_chars = 0xc4c3c0b3;
else if (i = result[OPT_JOINCHARS])
{
if (StrToLong((char *)i,&join_chars) < 0)
join_chars = *((ULONG *)i);
}
if (dirs = (UBYTE **)result[OPT_DIRS])
{
for (i = 0; dirs[i]; i++)
{
if (!do_dir(dirs[i],result[OPT_SHOWFILES],
join_chars,
result[OPT_COLOR]) && dirs[i+1])
PutStr("\n");
else
break;
}
}
else /* current directory as default */
do_dir("",result[OPT_SHOWFILES],join_chars,
result[OPT_COLOR]);
if (result[OPT_COLOR])
PutStr(ANSIOFF);
FreeArgs(myrda);
rc = 0;
}
else
PrintFault(IoErr(),NULL);
FreeDosObject(DOS_RDARGS,myrda);
}
return(rc);
}
/*******************************************************************/
/* display the tree of one directory */
BOOL ASM /* ^c break? */
do_dir(REG(a0) char *dirname,
REG(d0) BOOL show_files,
REG(d1) ULONG join_chars,
REG(d2) BOOL color)
{
struct FileInfoBlock *fib;
BPTR dir_lock;
BOOL broke = FALSE,
nextdir_array[64];
char fname[108];
if (dir_lock = Lock(dirname,ACCESS_READ))
{
if (fib = (struct FileInfoBlock *)
AllocDosObject(DOS_FIB,NULL))
{
memset(nextdir_array,0,sizeof(nextdir_array));
/* get real name */
if (NameFromLock(dir_lock,fname,sizeof(fname)))
{
if (color)
PutStr(COLOR6);
PutStr(fname);
PutStr("\n");
}
if (broke = tree_scan(dir_lock,fib,0,nextdir_array,
show_files,join_chars,color))
PrintFault(ERROR_BREAK,NULL);
FreeDosObject(DOS_FIB,fib);
}
UnLock(dir_lock);
}
else
PrintFault(IoErr(),NULL);
return(broke);
}
/*******************************************************************/
/* find the next directory lock, given the current one */
BOOL /* found next dir? */
NextDirLock(BPTR this_lock,
struct FileInfoBlock *fib,
FileList *list,
BOOL *die)
{
/* scan for next directory, or parent directory ends */
while (ExNext(this_lock,fib))
{
if(CheckSignal(SIGBREAKF_CTRL_C))
{
*die = TRUE;
break;
}
else if (fib->fib_DirEntryType > 0) /* a dir */
return(TRUE);
else if (list) /* put filename into link list? */
AddName(list,fib->fib_FileName);
}
return(FALSE);
}
/*******************************************************************/
/* display a branch to parent */
void
DisplayBranch(char *label,
int depth,
BOOL *nextdir_array,
BOOL show_files,
ULONG join_chars,
BOOL is_dir,
BOOL color)
{
BPTR out_fh = Output();
char *col_str = COLOR1; /* color for a file */
int i,
j,
c = 0;
PutStr(color ? COLOR3 : "");
for (i = 0; i < depth; i++)
{
FPutC(out_fh,nextdir_array[i] ? GET_VBAR(join_chars) : ' ');
for(j = 0; j < LEADING_SPACES; j++)
FPutC(out_fh,' ');
}
if (is_dir)
{
col_str = COLOR2;
FPutC(out_fh,nextdir_array[depth] ?
GET_T90(join_chars) : GET_L(join_chars));
c = GET_DASH(join_chars);
}
else if (show_files)
{
FPutC(out_fh,nextdir_array[depth] ?
GET_VBAR(join_chars) : ' ');
c = ' ';
}
if (c)
for (i = 0; i < LEADING_SPACES; i++)
FPutC(out_fh,c);
if (color)
PutStr(col_str);
PutStr(label);
PutStr("\n");
}
/*******************************************************************/
/* return a sorted array of strings, given a linked list,
use FreeVec() to free string array.
note: link list scanning could have been optimized, but
we want keep the nodes as ADT */
char ** ASM
SortFileList(REG(a0) FileList *file_list)
{
struct Node *node;
struct List temp_list;
char **fnames;
int i = 0;
if (fnames = (char **)AllocVec(file_list->node_count<<2,
MEMF_PUBLIC))
{
NewList(&temp_list);
while (node = RemHead((struct List *)file_list))
{
AddTail(&temp_list,node); /* re-queue */
fnames[i++] = node->ln_Name;
}
/* put things back */
while (node = RemTail(&temp_list))
AddHead((struct List *)file_list,node);
myqsort(fnames,0,file_list->node_count-1);
}
return(fnames);
}
/*******************************************************************/
/* scan the directory given */
BOOL /* use press ^C? */
tree_scan(BPTR dir_lock,
struct FileInfoBlock *fib,
int depth, /* how deep from parent? */
BOOL *nextdir_array,
BOOL show_files,
ULONG join_chars,
BOOL color)
{
struct Node *node;
FileList file_list;
struct FileInfoBlock *new_fib;
BPTR new_lock;
char fname[108];
BOOL die = FALSE,
is_dir;
NewList((struct List *)&file_list);
file_list.node_count = 0;
if (Examine(dir_lock,fib))
{
while (ExNext(dir_lock,fib) && !die)
{
if (show_files && (fib->fib_DirEntryType < 0))
AddName(&file_list,fib->fib_FileName);
while (TRUE)
{
if (CheckSignal(SIGBREAKF_CTRL_C))
{
die = TRUE;
break;
}
is_dir = (fib->fib_DirEntryType > 0) ? TRUE : FALSE;
NameFromLock(dir_lock,fname,108);
AddPart(fname,fib->fib_FileName,108);
nextdir_array[depth] =
NextDirLock(dir_lock,fib,show_files ? &file_list
: NULL,&die);
if (is_dir && !die)
{
DisplayBranch(FilePart(fname),depth,
nextdir_array,show_files,join_chars,
is_dir,color);
if (new_lock = Lock(fname,ACCESS_READ))
{
if (new_fib = (struct FileInfoBlock *)
AllocDosObject(DOS_FIB,NULL))
{
/* recursively, go into the sub-dir */
die = tree_scan(new_lock,new_fib,depth+1,
nextdir_array,show_files,
join_chars,color);
FreeDosObject(DOS_FIB,new_fib);
}
UnLock(new_lock);
}
}
if(!nextdir_array[depth] || die)
break;
}
}
if (file_list.node_count && !die)
{
int i;
char **fnames;
if (fnames = SortFileList(&file_list))
{
for (i = 0; i < file_list.node_count; i++)
{
if(CheckSignal(SIGBREAKF_CTRL_C))
{
die = TRUE;
break;
}
DisplayBranch(fnames[i],depth,nextdir_array,
show_files,join_chars,FALSE,color);
}
FreeVec(fnames);
}
if (depth && !die)
{
nextdir_array[depth] = FALSE;
DisplayBranch("",depth,nextdir_array,show_files,
join_chars,FALSE,color);
}
}
while (node = RemHead((struct List *)&file_list))
FreeVec(node);
}
return(die);
}
/*******************************************************************/
/* copy a filename into filenames link list */
struct Node * ASM
AddName(REG(a0) FileList *list,
REG(a1) char *name)
{
struct Node *node;
char *copy;
if (node = AllocVec(sizeof(struct Node) + strlen(name)+1,
MEMF_PUBLIC))
{
copy = ((char *)node) + sizeof(struct Node);
strcpy(copy,name);
node->ln_Name = copy;
AddTail((struct List *)list,node);
list->node_count++;
}
return(node);
}
/*******************************************************************/
/* a significantly smaller quicksort than qsort() */
void ASM
myqsort(REG(a0) char *v[],
REG(d0) int left,
REG(d1) int right)
{
int i,
last;
if (left < right)
{
swap(v,left,(left + right)>>1);
last = left;
for (i = left+1; i <= right; i++)
{
if (stricmp(v[i], v[left]) < 0)
swap(v, ++last, i);
}
swap(v, left, last);
myqsort(v, left, last-1);
myqsort(v, last+1, right);
}
}
/*******************************************************************/
/* swap two text pointers */
void ASM
swap(REG(a0) char *v[],
REG(d0) int i,
REG(d1) int j)
{
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
/*******************************************************************/
/* END */