home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
forum16.lzh
/
SOFTWARE
/
C
/
TREE
/
tree.c
< prev
Wrap
Text File
|
1991-05-06
|
15KB
|
579 lines
/* Revision history (latest entry on top)
* CM = Christian Mahr
* HK = Helmut Kohl
*
* bugs:
* no different behavior if pxd = 1
*
* rev. date note
*----------------------------------------
* 1.23 HK 24.12.90 add option -l for depth control
* 1.22 HK 02.12.90 extended help message / add terminal type Gepard
* automatic detection of GEPARD terminal
* add unsorted printing
* 1.21 CM 17.06.90 last version of Christian Mahr of EFFO-Disk
* new version with sorted directory and special
* graphics for VT100 and ATARI ST/IBM
*/
#define VERSION "v1.23 - 24.12.90 / CM,HK"
#define DEBUG 1
#include <stdio.h>
#include <modes.h>
#include <direct.h>
#include <dir.h>
#include <sgstat.h>
extern int errno;
#define BUFSIZE 256
#define MAXLINE 256
#define TRUE 1
#define FALSE 0
#define ERROR (-1)
/* div terminal types */
#define ANY_TERM 0
#define VT100 1
#define ST 2
#define GEPARD 3
/* aliases for termcap terminal types */
char *vt100_alias[] =
{
"VT100",
"vt100",
"vt100-80",
"VT220",
"vt220",
"vt300",
"vt300-80", /* more ... */
NULL
};
char *st_alias[] =
{
"st",
"st50",
"stlow",
NULL
};
extern char *malloc();
#define DIRSIZ sizeof(struct direct)
#define DEF_NAME_FIELD 12
/* special character functions */
#define INTRO 0
#define RIGHT 1
#define DOWN 2
#define DOWN_RIGHT 3
#define RIGHT_DOWN 4
#define LAST_RIGHT 5
/* special character tables */
static char *VT100_seq[] =
{
"\x1b)0",
"\x0Eq\x0F",
"\x0Ex\x0F",
"\x0Et\x0F",
"\x0Ew\x0F",
"\x0Em\x0F",
};
static char *any_terminal[] =
{
"","-","|","|","+","`"
};
static char *ST_seq[] =
{
"", "\xC4", "\xB3", "\xC3", "\xC2", "\xC0"
};
static char *gepard_terminal[] =
{
"","\xB8","╣","»","\xBA","¼"
};
char **special_char ;
char left[MAXLINE]; /* output line up to the actual position */
int debug, show_files, sort_files, terminal_type, name_field;
/* option variables */
static char *cmds[] =
{
"tree, ",VERSION,
"\nSyntax: tree [<directory>] [<opts>]\n",
"Function: print all subdirectories as a tree\n",
" use special graphics for VT100 compatible terminals,\n",
" IBM compatible printers, ATARI ST and Gepard systems.\n",
"Options: \n",
" -f print all files\n",
" -u unsorted printing\n",
" -w=n limit name field width to n characters (default: n=12)\n",
" -l=n limit tree depth to n level (max.:n = 40) (default: n=max)\n",
#ifdef DEBUG
" -d internal debug flag\n",
#endif
" -a force terminal type to be ANY_TERM (default)\n",
" -v force terminal type to be VT100\n",
" -s force terminal type to be ST/IBM\n",
" -g force terminal type to be Gepard\n",
""
};
#define MAXDEEP 40 /* absolute maximum directory depth */
int pxd=0; /* pxd =0 look for
dir,owner executable,owner read attr. */
/* pxd =1 look for dir,read attr. */
char *pelem[MAXDEEP+1]; /* path element pointers */
direct char **pstk = pelem; /* path element stack ptr */
int dir_depth;
static direct int gpath;
/* ---------------------------------------- */
main (argc,argv)
int argc ;
char *argv[];
{
char *p;
int argc1; /* duplicate counters/pointers */
char **argv1;
char home[MAXLINE]; /* current home directory */
int arg_finished; /* flag if an arg is finished by = */
int done_once; /* flag if once done */
debug = FALSE; /* defaults for options */
show_files = FALSE;
terminal_type = term_typ(); /* det. terminal type of stdout path */
name_field = DEF_NAME_FIELD; /* set default field length */
dir_depth = MAXDEEP; /* set default directory depth */
sort_files = TRUE;
argc1 = argc; /* scan arguments for options */
argv1 = &argv[0];
while (--argc1 > 0)
{
p = *++argv1;
if (*p++ == '-')
{
arg_finished = FALSE;
while (*p != '\0' && !arg_finished)
{
switch (tolower(*p++))
{
case 'a': terminal_type=ANY_TERM; break;
case 'v': terminal_type=VT100; break;
case 's': terminal_type=ST; break;
case 'g': terminal_type=GEPARD; break;
case 'd': debug++; break;
case 'f': show_files++; break;
case 'u': sort_files = FALSE; break;
case 'w': if (*p == '=')
{
name_field = atoi(&p[1]);
arg_finished = TRUE;
}
break;
case 'l': if (*p == '=')
{
dir_depth = atoi(&p[1]);
arg_finished = TRUE;
if ((dir_depth > MAXDEEP) | (dir_depth <= 0))
dir_depth = MAXDEEP;
}
break;
default: usage(); exit(0);
}
}
}
}
switch(terminal_type)
{
case VT100: special_char = VT100_seq; break;
case ST: special_char = ST_seq; break;
case GEPARD: special_char = gepard_terminal; break;
case ANY_TERM:
default: special_char = any_terminal; break;
}
printf("%s",special_char[INTRO]);
done_once = FALSE;
while (--argc > 0)
{
p = *++argv;
if (p[0] != '-')
{
left[0] = '\0'; /* no chars left of actual pos. */
if (chdir(p) == ERROR)
non_fatal(errno,"can't chd to %s",p);
else
{
add_blanks(left,name_field);
print_to(p,name_field);
fflush(stdout);
directory(name_field-strlen(p));
if (chdir("..") == ERROR)
non_fatal(errno,"can't chd to ..");
done_once = TRUE;
printf("\n");
}
}
}
if (!done_once)
{ /* default current directory */
#ifdef DEBUG
if (debug) printf ("No explicit directory specified\n");
#endif
left[0] = '\0';
pd_str(home); /* get home directory */
add_blanks(left,name_field);
print_to(home,name_field);
fflush(stdout);
directory(name_field-strlen(home));
printf("\n");
}
}
/* ---------------------------------------- */
usage()
{
register char **p = cmds, **cmdsend = cmds+(sizeof cmds)/(sizeof(char **));
while (p < cmdsend) fputs(*p++,stderr);
}
/* ---------------------------------------- */
add_blanks(s,n)
char *s;
int n;
{
while (n-- > 0) strcat(s," ");
};
/* ---------------------------------------- */
/* print actual path
n = field width
*s = actual path name
*/
print_to(s,n)
char *s;
int n;
{
int i,l;
l=strlen(s);
if (n < l) l=n;
for (i = 0; i < l ; i++)
putc(s[i],stdout);
};
/* ----------------------------------------
* sort POINTERS for dir entry */
sort_dir(db,n)
struct direct *db[]; /* pointer array to dir entries */
int n;
{
register int gap,i,j;
register struct direct *temp;
if (sort_files == TRUE)
{
for (gap = n/2; gap > 0; gap /= 2)
{
for (i = gap; i < n ; i++)
{
for (j = i-gap ; j >= 0; j -= gap)
{
if (strcmp(db[j]->d_name,db[j+gap]->d_name)<=0) break;
temp=db[j+gap];
db[j+gap]=db[j];
db[j]=temp;
}
}
}
}
}
/* ---------------------------------------- */
int directory (horiz_line) /* size of all files in "name" */
int horiz_line; /* max. field with - actual field length */
{
int i,j,cur_column,do_dir;
int db_size,db_entries,entries_read;
char *cur_dir;
struct direct *p,*dba,**db;
struct _dirdesc *dirp ;
printf(" "); /* blank AFTER name */
add_blanks(left,1);
if ( (dirp = opendir(".")) == NULL) return(ERROR);
if ( (db_size = _gs_size(dirp->dd_fd)) == ERROR) return(ERROR);
db_entries = db_size / sizeof(struct dirent); /* size in file !!!!! */
#ifdef DEBUG
if (debug)
printf("db_size= %d, db_entries= %d, dir_depth= %d\n",db_size,db_entries,dir_depth);
#endif
if ((db = (struct direct **) calloc(db_entries,4)) == NULL) /* pointers */
fatal(errno,"can't get enough memory");
if ((dba= (struct direct *) calloc(db_entries,DIRSIZ)) == NULL)
fatal(errno,"can't get enough memory");
i=0;
while ( p=readdir(dirp) )
{
if ( p->d_name[0] != '.')
{
_strass( (db[i] = &dba[i]), p, DIRSIZ); /* store in array */
#ifdef DEBUG
if (debug) printf("db[%d]->d_name=%s\n",i,db[i]->d_name);
#endif
if (show_files || (access(db[i]->d_name,S_IFDIR)==0)) i++;
}
if (i > db_entries) fatal (0," to many entries in dir ");
}
entries_read = i;
#ifdef DEBUG
if (debug) printf("entries_read =%d\n",entries_read);
#endif
sort_dir(db,entries_read);
for (i=0; i < entries_read; i++)
{
cur_dir = db[i]->d_name;
if (i == 0) /* are we at first entry ? */
{
j = (entries_read == 1)?RIGHT:RIGHT_DOWN;
while (horiz_line-- > 0) printf("%s",special_char[RIGHT]);
}
else
{
j = (i == entries_read-1) ? LAST_RIGHT:DOWN_RIGHT; /* `- or |- */
printf("\n%s",left);
}
printf("%s%s ",special_char[j],special_char[RIGHT]);
print_to(cur_dir,name_field);
fflush(stdout);
cur_column = strlen(left);
if (j == LAST_RIGHT || j == RIGHT)
strcat(left," ");
else
strcat(left,special_char[DOWN]);
add_blanks(left,name_field+2);
if (show_files)
do_dir = (access(cur_dir,S_IFDIR)==0);
else
do_dir = TRUE; /* not necessary to ask */
if (do_dir)
{
if (chdir(cur_dir) == ERROR)
{
non_fatal(errno,"can't chd to %s",cur_dir);
return (ERROR);
}
if (dir_depth-- > 1) directory (name_field-strlen(cur_dir));
dir_depth++;
if (chdir("..") == ERROR)
{
non_fatal(errno,"can't chd to ..");
return (ERROR);
}
}
left[cur_column]='\0';
}
closedir(dirp);
free (db);
free (dba);
return(0); /* no error */
}
/* ----------------------------------------
* print information and exit */
non_fatal (err,f,p1,p2,p3)
int err;
char *f;
int p1,p2,p3;
{
fflush(stdout);
fprintf(stderr,"tree: error, ");
fprintf(stderr,f,p1,p2,p3);
fprintf(stderr,"\n");
print_error(err);
fflush(stderr);
}
/* ---------------------------------------- */
fatal (err,f,p1,p2,p3)
int err;
char *f;
int p1,p2,p3;
{
non_fatal (err,f,p1,p2,p3);
exit(err);
}
/* ----------------------------------------
print error routine ....
serach for error message file almost 'everywhere'
*/
print_error(err_stat)
int err_stat;
{
register int errmsg_path; /* path no */
register char **name_poi;
static char *err_files[] =
{
"/dd/sys/errmsg",
"/h0/sys/errmsg",
"/d0/sys/errmsg",
"" /* delimit list */
};
if (err_stat==0) return(0);
name_poi=err_files;
do
{
errmsg_path = open (*name_poi++,S_IREAD); /* try to open error file */
}
while (errmsg_path==ERROR && **name_poi);
if (errmsg_path==ERROR) /* if unsuccessfull, number only */
prerr(0,err_stat);
else
prerr(errmsg_path,err_stat); /* print the error message */
close(errmsg_path); /* close the error message path */
}
/* ---------------------------------------- */
opndir()
{
int dpath, mode;
mode = pxd ? S_IFDIR|S_IEXEC|S_IREAD : S_IFDIR|S_IREAD;
if ((dpath = open(".",mode)) == ERROR)
exit(_errmsg(errno,"can't open current directory. "));
return dpath;
}
/* ---------------------------------------- */
getcwd()
{
register char *dir;
char dots[MAXDEEP+2];
for(dir=dots; dir<(dots+(sizeof dots)-1); ++dir)
*dir='.';
*dir='\0';
dir-=2; /* point to ".." */
gpath=opndir();
getcwds(dir);
close(gpath);
}
/* ---------------------------------------- */
getcwds(dir)
char *dir;
{
static char devname[34] = {'/'};
struct dirent dirbuf;
register long cfds,pfds,nfds;
register char *p=devname+1,*fn=dirbuf.dir_name;
extern char* ebrk();
lseek(gpath,nfds=0l,0);
read(gpath,&dirbuf,sizeof dirbuf);
pfds=dirbuf.dir_addr;
read(gpath,&dirbuf,sizeof dirbuf);
if((cfds = dirbuf.dir_addr) == pfds)
{
if(_gs_devn(gpath,p)==ERROR)
exit(_errmsg(errno,"can't get device name. "));
*pstk++ = devname;
while(*p++>0);
}
else
{
close(gpath);
if ((gpath = open(dir,
pxd ? S_IREAD|S_IFDIR|S_IEXEC : S_IREAD|S_IFDIR)) == ERROR)
exit(_errmsg(errno,"can't open \"%s\". ",dir));
lseek(gpath,nfds=(sizeof dirbuf) * 2,0);
do
{
read(gpath,&dirbuf,sizeof dirbuf);
}
while(cfds != dirbuf.dir_addr);
getcwds(--dir);
if ((int)(*pstk++ = (p = ebrk(sizeof dirbuf.dir_name))) == ERROR)
exit(_errmsg(errno,"can't get memory. "));
while((*p++ = *fn++) > 0);
}
p[-1] &= 0x7f;
*p='\0';
}
/* ---------------------------------------- */
pd_str(showp)
char *showp;
{
register char **p,*sp,*pp;
getcwd();
for(sp=showp,p=pelem; p<pstk; ++p)
{
for(pp=*p; *pp; )
*sp++ = *pp++;
*sp++ = '/';
}
*--sp = '\0';
}
/* ----------------------------------------
determine terminal type from environment var */
int term_typ()
{
char *p;
extern char *getenv();
char **tt;
p = getenv("TERM");
if (p)
{
for (tt = vt100_alias; *tt; tt++)
if (strcmp(p,*tt)==0) return (VT100);
for (tt = st_alias; *tt; tt++)
if (strcmp(p,*tt)==0) return (ST);
if (strcmp (p,"Gepard")==0) return (GEPARD);
}
return (ANY_TERM);
}