v08i072: dtree, Part01/02
Konstantinos Konstantinides
kk at hpkronos.hpl.hp.com
Thu Aug 16 13:04:27 AEST 1990
Submitted-by: Konstantinos Konstantinides <kk at hpkronos.hpl.hp.com>
Posting-number: Volume 8, Issue 72
Archive-name: dtree/part01
This version of dtree is an X extension of the program originally
written by Dave Borman. It displays on a terminal or under X11
(using Motif widgets) the tree structure of a Unix directory tree.
On a color terminal, different colors can be used for files, directories,
and symbolic links. One can select nodes of the tree, and edit them,
view them, or print them. One can also traverse nodes not fully
shown on the original tree.
K. Konstantinides
kk at hpkronos.hpl.hp.com
-------------------------Beginning of submission--Part 1 of 2----------
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Konstantinos Konstantinides <kk at hpkronos> on Tue Aug 14 15:06:50 1990
#
# This archive contains:
# dtree.1 dtree.c Makefile Dtree
# dtree-i.h Imakefile README
#
LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH
echo x - dtree.1
cat >dtree.1 <<'@EOF'
.TH DTREE 1L
.SH NAME
dtree \- display directory tree structures
.SH SYNOPSIS
.B dtree
[
.I \-aDfghHNpsStvx
] [
.I \-l level
] [
.I \-c linelength
] [
.BR directory ...
]
.SH DESCRIPTION
.I dtree
displays a graphic representation of the directory structure of each given
.B directory
and its children either on the terminal stdout or on an X11 window, using
the Motif widgets (default). If no directories are specified, the current
directory is used.
By default, only directories, not regular files, are shown, and only their
filenames are given. Various options add additional
information to the tree.
.SS OPTIONS
.TP
.I \-a
Include files in the listing (excluding entries beginning with '.').
.TP
.I \-c linelength
Make
.I linelength
the length of each
column of the printout. By default, this is 14.
Any entries longer than
the column length are truncated accordingly, and the last character that
fits into the column is replaced by an asterisk.
This option only has an effect if the
.I -v
option is specified.
.TP
.I \-l level
Search only up to the specified level. (Maximum is 10).
.TP
.I \-D
List directories first. For each directory, its subdirectories
will be listed first, and then all of its other entries.
.TP
.I \-f
List files first. The reverse of
.IR \-D .
.TP
.I \-S
Long listing. Display useful information to the right of
each entry: the name of the file's owner, its size in blocks, and its mode.
.TP
.I \-g
Same as the
.I \-S
option, except that the group name is used instead of
the owner name. If both the
.I \-S
and
.I \-g
options are used, both the
owner and group will be displayed.
.TP
.I \-H
Display a header at the top of the printout that gives the time and
date that the printout was made and a summary of the type of
information contained in the tree.
.TP
.I \-N
No sort. Entries are listed in the order they are read
from the directories.
.TP
.I \-p
Include entries beginning with '.' (except '.' and '..').
.TP
.I \-s
Simplify the long listing: display the user id, size in blocks, and
octal mode of the file. This option implies the
.I \-S
option unless the
.I \-g
option is specified.
.TP
.I \-v
Do not let column lengths vary; use the same
width for each column of output. The width defaults to 14
but can be set with the
.I \-c
option.
.TP
.I \-x
Do not cross file systems.
.I dtree
will not cross over to a
subdirectory if it is on a different file system.
.TP
.I \-h
Will print a list of the options.
.TP
.I \-t
Terminal mode.
In default mode
.I
dtree
will display the directory tree structure in an X11 window.
The \-t option allows the tree to be printed on the terminal stdout.
Under the X11 window mode, a button click on a tree node, makes it
the "active" node. The name of the "active" node always appears
at the top of the window, by the "quit" button.
With a button click in the area where the "active" node is shown,
a menu appears with the mode of the node, the group and user IDs,
and \fIfile\fR or \fIdirectory\fR options .
There are
four \fIfile\fR options: \fIview, topview, edit\fR and \fIprint\fR.
There are three \fIdirectory\fR options: \fIshow subtree, list files\fR,
and \fIlist '../'\fR.
Thus, the \-c, \-S, \-g, \-s, and \-v options are meaningful only
when the \-t option is used.
.TP
.B view
Display the whole file on a scrolled window.
Since the program reads a file all at once,
the wait may be significant for a very large file. However, the option
.TP
.B topview
shows only the top of the file (2000 bytes).
.TP
.B edit
Edit the file. \fIdtree\fR first checks and executes the command
specified by the
.B dtree*editor:
resource in .Xdefaults. If that command is NULL, \fIdtree\fR
forks an hpterm window using the editor command specified
in the
.B EDITOR
environmental variable. If that variable is not specified, it uses \fIvi\fR
.TP
.B print
Print the file. It prints the file on the printer destination specified
by the
.B dtree*lpdest:
resource in .Xdefaults.
If that variable is not specified it uses
the default lp destination.
.TP
.B "show subtree"
Show the directory subtree starting from the selected "active"
directory node.
.TP
.B "list files"
List all files and directories for the "active" directory node.
This is equivalent to an "ls" command on that directory.
.TP
.B "list \.\.\/"
List the directories in the parent (top) directory. Allows the user
to traverse upwards the directory tree.
Except for the \fIview\fR and \fItopview\fR options, in all other cases
a click on the "quit" button of the "parent" will
cause the "parent" \fIdtree\fR window to freeze until the selected command
has been executed or the "child" window has been killed.
Then the "parent" window will automatically die.
Thus it is recommended to kill "children" applications before
you try to kill the "parent".
On a color terminal, one can choose different colors to distinguish
between directories, files, and symbolic links.
When the XmGraph widget is used, the directory tree can be seen both
vertically and horizontally.
To set up a simple color scheme for \fIdtree\fR, put the following entries
in your ~/.Xdefaults file:
dtree*geometry: 500x500
.br
dtree*quit.background: DarkSlateBlue
.br
dtree*dir.background: Red
.br
dtree*sym_link.background: Brown
.br
dtree*options.background: Red
A set of simple resources is also specified in
/usr/lib/X11/app-defaults/Dtree
.SH AUTHOR
Dave Borman, Digital Unix Engineering Group
.br
decvax!borman
.br
Originally written at St. Olaf College, Northfield, MN.
.br
Additions for the X11 windows display by K. Konstantinides,
Hewlett-Packard Laboratories.
Copyright: Hewlett-Packard, 1990.
e-mail:kk at hpkronos.hpl.hp.com
@EOF
chmod 644 dtree.1
echo x - dtree.c
cat >dtree.c <<'@EOF'
/*
* DTREE - Print the tree structure of a directory
* 4/7/83 name was changed from TREE to DTREE
* 9/7/83 mods for 4.1c and 4.2 dirctory structure added
*
* Dave Borman, Digital Unix Engineering Group
* decvax!borman
* Originally written at St. Olaf College, Northfield MN.
* Copyright (c) 1983 by Dave Borman
* All rights reserved
* This program may not be sold, but may be distributed
* provided this header is included.
*
* Usage: dtree [-aDfghHlNpstvx] [-c line-length] [directory...]
* Flags: -a) include non-directory entries in listing
* -D) sort tree with directories at the top
* -f) sort tree with files at the top
* -g) same as l, but use group name instead of user name
* -h) help
* -H) display a header at top
* -S) print stats with each listing
* if both g & l flags are given, both owner and
* group will be printed
* -N) do not sort the tree
* -p) include files starting with a '.' (except "." & "..")
* -s) use shorter stats. Implies -S if -g isn't given.
* -t) Use terminal mode (no X windows)
* -v) variable length columns off
* -x) do not cross mounted file systems.
* -c length) set max column length to "length"
* -l level) search up to the specified "level".
*/
/* Modified by Ed Arnold CSU-CS (csu-cs!arnold) 3-5-84
*
* Allows symbolic links to both directories and individual files.
* With a '-S' or '-aS' option, links are denoted with a 'l' in front of
* file or directory permissions. In all other instances both links to
* directories and files are represented just as files are. Contents of
* linked directories are not printed due to the possibility of
* recursively linked directories.
*
* Big directory name option added by:
* Mike Vevea CSU-CS (csu-cs!vevea) 3-22-84
*
* Toggle sense of -v (running 4.2), and eliminate some extraneous
* print info Mike Meyer Energy Analysts (mwm at ea) 4/17/84
*
* Fix the exit status to correctly indicate what happened.
* Mike Meyer Energy Analysts (mwm at ea) 4/23/84
*
* Change MAX to INITIAL_ELEM to fix conflict on Suns,
* fix incorrect default value for Clength when -v not given,
* add -H option to print header with date and description of tree,
* remove -b option (useless) and simplify array access,
* use getopt to parse options, fix usage message,
* use getwd instead of opening a pipe to pwd,
* make error messages more informative,
* use strncpy instead of sprintf for speed,
* move function declarations to top of file,
* comment out junk after #else and #endif,
* make symbolic link configuring automatic,
* check all error returns from malloc and realloc,
* add System V/Xenix/Unos compatibility,
* remove definition of rindex.
* David MacKenzie <djm at enumd.edu> 12/20/89
*
* Modified to display the tree on X11 windows using the Motif
* widgets and the Tree widget described by D.Young in his book,
* "The X Window System, Programming and applications with Xt,
* OSF/MOTIF EDITION", Prentice Hall, 1990.
* Clicking on the "active" node pops-up a menu with the Mode, and Group
* and User IDs. Clicking on "view" pops up a window with the whole
* contents of the file. Clicking on "topview" shows the top
* of the file only (2000 bytes).
* On the tree, files, directories, and symbolic links can be
* shown with different colors.
* Changed some options so there is no conflict with X-window
* options ( -d to -D, and -n to -N).
* Added the -t and -h options. Changed the -l option to -S
* Added the "-l level" option.
* Konstantinos Konstantinides, Hewlett-Packard Laboratories
* konstantinos_konstantinides at hplabs.hp.com 3/23/90
*
* Copyright: HEWLETT-PACKARD, 1990
* Motif is a trademark of Open Software Foundation, Inc.
* X Window System is a trademark of the Massachusetts Institute of
* Technology
*
* Added support for both the Tree and XmGraph widgets
* K. Konstantinides 4/16/90
*/
/* Compile-time options:
*
* STATS leave undefined to remove stats, giving more core space
* and thus the ability to tree larger tree structures on PDP 11/70s.
*
* NEWDIR directory structure a la Berkeley 4.1c or 4.2
*
* NDIR use <sys/ndir.h> instead of <sys/dir.h>
* NEWDIR must be defined as well.
*
* DIRENT use Posix directory library.
* NEWDIR must be defined as well.
*
* SYSV use getcwd instead of getwd, strrchr instead of rindex.
*/
void re_orient();
void disarm_callback();
void activate_callback();
void arm_callback();
void clickB();
void w_print();
void button_print();
void pop_data();
void view();
void quit_b();
void quit_b_pop();
void do_menu();
static char Sccsid[]="@(#)dtree.c 2.3 2/14/84";
#ifdef S_IFLNK
static char Rcsid[] ="$Header: dtree.c,v 1.7.1.2 90/04/18 09:57:30 kk Exp $";
#endif /* S_IFLNK */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
/* Include files for X windows */
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/CascadeB.h>
#include <Xm/RowColumn.h>
#include <Xm/ScrolledW.h>
#include <Xm/Separator.h>
#include <Xm/MainW.h>
#include <Xm/Frame.h>
#include <Xm/Text.h>
#ifdef TREE
#include "Tree.h"
#else
#include "Graph.h"
#include "Arc.h"
#endif
/* Original Defs */
#ifdef STATS
# include <pwd.h>
# include <grp.h>
#endif /* STATS */
#ifdef NEWDIR
# if DIRENT
# include <dirent.h>
# define direct dirent
# else
# if NDIR
# include <sys/ndir.h>
# else
# include <sys/dir.h>
# endif
# endif /* DIRENT */
#else
# include <sys/dir.h>
#endif /* NEWDIR */
/* default column length when -v is given */
#ifdef unos
#define DEFCOLWID 30
#else
#define DEFCOLWID 14
#endif
#include <sys/param.h> /* for MAXPATHLEN */
#ifndef MAXPATHLEN
# ifdef LPNMAX /* Xenix from stdio.h */
# define MAXPATHLEN (LPNMAX - 1)
# else
# include <limits.h> /* try somewhere else */
# define MAXPATHLEN PATH_MAX
# endif
#endif
#ifndef MAXNAMLEN /* defined with NEWDIR routines */
# ifdef LFNMAX /* Xenix again */
# define MAXNAMLEN (LFNMAX - 1)
# else
# define MAXNAMLEN DEFCOLWID
# endif
#endif
#define DEPTH 10 /* maximum depth that dtree will go */
#define INITIAL_ELEM 100 /* initial # of elements for list of files */
#define FFIRST 2 /* sort files first */
#define DFIRST 1 /* sort directories first */
#define FAIL -1 /* failure return status of sys calls */
#define GREATER 1 /* return value of strcmp if arg1 > arg2 */
#define LESSTHAN -1 /* return value of strcmp if arg1 < arg2 */
#define SAME 0 /* return value of strcmp if arg1 == arg2 */
#ifdef STATS
char *getmode();
char *guid();
char *ggid();
struct passwd *getpwuid();
struct group *getgrgid();
#endif /* STATS */
#ifdef SYSV
#define rindex strrchr
#endif /* SYSV */
char *getwd();
char *rindex();
/*
int qsort();
char *malloc();
char *realloc();
*/
long time();
int compar(); /* comparison routine for qsort */
char *xmalloc();
char *xrealloc();
#ifdef SYSV
#define getwd(buf) getcwd((buf), MAXPATHLEN + 1)
#endif /* SYSV */
int Index = 0; /* current element of list[] */
int CLength = 0; /* max length of a column */
int All = 0; /* all != 0; list non-directory entries */
int File_dir = 0; /* flag for how to sort */
int Sort = 1; /* flag to cause sorting of entries */
int Point = 1; /* skip point files if set */
int Header = 0; /* print verbose header */
int Maxes[DEPTH]; /* array keeps track of max length in columns */
int Level = 0; /* counter for how deep we are */
int Device; /* device that we are starting tree on */
int Xdev = 1; /* set to allow crossing of devices */
int Varspaces = 1; /* set to allow compaction of column width */
#ifdef STATS
int Gflag = 0; /* set for group stats instead of owner */
int Longflg = 0; /* set for long listing */
int Compact = 0; /* set for shortened long listing */
#endif /* STATS */
#undef Status
struct stat Status;
#ifdef S_IFLNK
struct stat Lstat; /* stat of link, if there is one */
#endif /* S_IFLNK */
struct entry {
int next; /* index to next element in list */
/* could be a ptr, but realloc() */
/* might screw us then */
#ifdef STATS
off_t e_size; /* size in blocks */
unsigned short e_mode; /* file mode */
short e_uid; /* uid of owner */
short e_gid; /* gid of owner */
#endif /* STATS */
unsigned short dir : 1; /* entry is a directory */
unsigned short last : 1; /* last entry in the dir. */
unsigned short dev : 1; /* set if same device as top */
unsigned short end : 13; /* index of last subdir entry*/
char e_name[MAXNAMLEN + 1]; /* name from directory entry */
char path_name[MAXPATHLEN + 1]; /* path name */
} *List, *SaveList;
unsigned Size; /* how big of space we've malloced */
char *Spaces; /* used for output */
char Buf1[BUFSIZ]; /* buffers for stdio stuff. We don't want */
#ifndef NEWDIR
char Buf2[BUFSIZ]; /* anyone calling malloc, because then */
/* realloc() will have to move the whole list */
#endif
#define FS(str) (void) fprintf(stderr,str)
help()
{
fprintf(stderr,
#ifdef STATS
"Usage: dtree [-aDfghHlNpstvx] [-c linelength] [directory ... ]\n"
#else /* STATS */
"Usage: dtree [-aDfhHNptvx] [-c linelength] [directory ... ]\n"
#endif /* STATS */
);
FS(" options -a) include non-directory entries in listing\n");
FS(" -D) sort tree with directories at the top\n");
FS(" -f) sort tree with files at the top\n");
FS(" -h) help - prints this message\n");
FS(" -H) display a header at top\n");
FS(" -x) do not cross mounted file systems.\n");
FS(" -p) include files starting with a . (except . and ..)\n");
FS(" -N) do not sort the tree\n");
FS(" -t) Use terminal mode, don't display on an X window\n\n");
FS(" -l level) Search only up to the specified level \n\n");
FS(" Valid only if -t is used. Under default mode, a click on a \n");
FS(" node pops up a menu with mode, user and group ids.\n\n");
FS(" -S) print stats with each listing\n");
FS(" if both g & l flags are given, both owner and\n");
FS(" group will be printed\n");
FS(" -g) same as l, but use group name instead of user name \n");
FS(" -s) use shorter stats. Implies -S if -g isn't given.\n");
FS(" -v) variable length columns \n");
FS(" -c length) set max column length to -length-\n");
FS(" X-Window version 1.1 4/16/90 \n");
}
int newlevel = DEPTH;
Widget boxes[11], options;
Widget file_menu, dir_menu;
struct entry *file_pointer;
main(argc, argv)
char **argv;
int argc;
{
extern int optind;
extern char *optarg;
register int i;
char top[MAXPATHLEN + 1]; /* array for treetop name */
char home[MAXPATHLEN + 1]; /* starting dir for multiple trees */
char *ptr;
Widget toplevel;
Widget sw, tree, q_button, w_button;
Widget menu_bar, frame, main_w, title;
Arg wargs[10];
int flagX=1; /* use X windows as default */
Widget quit_menu, exit_b, reorient;
int really_quit, n;
setbuf(stdout, Buf1);
while ((i = getopt (argc, argv,
#ifdef STATS
"haDfgHl:NpsSvxtc:"
#else
"haDfHl:Npvxtc:"
#endif /* STATS */
)) != EOF) {
switch (i) {
case 'a':
All = 1;
break;
case 'c':
CLength = atoi(optarg);
if (CLength > MAXNAMLEN)
CLength = MAXNAMLEN;
else if (CLength < 1)
CLength = DEFCOLWID;
break;
case 'l':
newlevel = atoi(optarg);
if(newlevel > DEPTH) {
newlevel = DEPTH;
}
break;
case 'D':
File_dir = DFIRST;
break;
case 'f':
File_dir = FFIRST;
break;
case 'H':
Header = 1;
break;
case 'N':
Sort = 0;
break;
case 'p':
Point = 0;
break;
case 'v':
Varspaces = 0;
break;
case 'x':
Xdev = 0;
break;
case 't':
flagX = 0;
break;
case 'h':
help();
exit(0);
#ifdef STATS
case 'g':
Gflag = 1;
break;
case 'S':
Longflg = 1;
break;
case 's':
Compact = 1;
break;
#endif /* STATS */
default:
help();
exit(FAIL);
}
}
#ifdef STATS
if (Compact && !Gflag)
Longflg = 1;
#endif /* STATS */
if (CLength == 0)
CLength = Varspaces ? MAXNAMLEN : DEFCOLWID;
/* Establish where we are (our home base...) */
if (getwd(home) == 0) {
fprintf(stderr,
"dtree: Cannot get initial directory: %s\n", home);
exit(1);
}
Spaces = xmalloc(MAXNAMLEN+2);
for(i = 0; i <= MAXNAMLEN; i++)
Spaces[i] = ' ';
Spaces[i] = '\0';
/* Get initial Storage space */
Size = sizeof(struct entry) * INITIAL_ELEM;
SaveList = (struct entry *)xmalloc(Size);
/* adjust for no specified directory */
if (optind == argc )
if(optind > 1) argv[--optind] = ".";
else { argv[1] = ".", optind = 1; argc = 2;}
if (Header)
print_date();
/* walk down the rest of the args, treeing them one at at time */
for (; optind < argc; optind++) {
if (chdir(home) == -1) {
fprintf(stderr, "dtree: Cannot change to initial directory ");
perror(home);
exit(1);
}
strncpy (top, argv[optind], MAXPATHLEN);
if (chdir(top) == FAIL) {
fprintf(stderr, "dtree: Cannot change to top directory ");
perror(top);
continue;
} else if (getwd(top) == 0) {
fprintf(stderr,"dtree: Cannot get current directory: %s\n", top);
continue;
}
List = SaveList; Index = 0;
getwd(List[0].path_name);
ptr = rindex(top, '/');
if (!ptr || *++ptr == '\0')
strncpy(List[Index].e_name, top, MAXNAMLEN);
else
strncpy(List[Index].e_name, ptr, MAXNAMLEN);
if(stat(top, &Status) == FAIL) {
fprintf(stderr, "dtree: Cannot stat directory ");
perror(top);
continue;
}
Device = Status.st_dev;
List[0].dir = 1;
List[0].last = 1;
List[0].next = 1;
#ifdef STATS
List[0].e_mode = Status.st_mode;
List[0].e_uid = Status.st_uid;
List[0].e_gid = Status.st_gid;
List[0].e_size = Status.st_size;
#endif /* STATS */
Index = 1;
for (i = 1; i < DEPTH; i++)
Maxes[i] = 0;
Maxes[0] = stln(List[0].e_name);
Level = 1;
/* Don't waste time if there is no display */
if(flagX == 1)
toplevel = XtInitialize(argv[0], "Dtree", NULL, 0, &argc, argv);
fprintf(stderr,"Started searchin...Please wait \n");
/* search the tree */
List[0].end = t_search(top, &List[0]);
if (Index == 1) /* empty tree */
List[0].next = 0;
if (Header) {
if (All)
printf("\nDirectory structure and contents of %s\n", top);
else
printf("\nDirectory structure of %s\n", top);
if (Point)
printf("(excluding entries that begin with '.')\n");
}
if(flagX == 0) pt_tree();
else {
/* Create a MainWindow, with a MenuBar and a Frame window
Put on the Frame, a ScrolledWindow and the Tree window
The MenuBar has a quit button and the directory Name
*/
fprintf(stderr,"Opening display now...Please wait\n");
/* main window */
main_w = XmCreateMainWindow(toplevel,"mainw",NULL,0);
XtManageChild(main_w);
/* menu bar */
menu_bar = XmCreateMenuBar(main_w,"menu",NULL,0);
XtManageChild(menu_bar);
/* frame */
XtSetArg(wargs[0], XmNshadowType, XmSHADOW_OUT);
frame = XmCreateFrame(main_w,"frame",wargs,1);
XtManageChild(frame);
/* quit button */
quit_menu = XmCreatePulldownMenu(menu_bar,
"quit_menu",NULL,0);
XtSetArg(wargs[0], XmNsubMenuId,quit_menu);
q_button = XmCreateCascadeButton(menu_bar,
"quit",wargs,1);
XtManageChild(q_button);
w_button =XtCreateManagedWidget("warning",
xmLabelWidgetClass,quit_menu, NULL,0);
w_print(w_button,"Don't exit unless all children are dead\n");
exit_b = XtCreateManagedWidget("Exit",
xmPushButtonWidgetClass, quit_menu, NULL, 0);
XtAddCallback(exit_b, XmNarmCallback,
arm_callback, &really_quit);
XtAddCallback(exit_b, XmNdisarmCallback,
disarm_callback, &really_quit);
XtAddCallback(exit_b, XmNactivateCallback,
activate_callback, &really_quit);
#ifndef TREE
/* Reorient button */
reorient = XmCreateCascadeButton(menu_bar,"ReOrient",
NULL,0);
XtManageChild(reorient);
#endif
/* Create the options pull-down menu */
file_pointer = &List[0];
show_menu(menu_bar,file_pointer);
/* title (path) widget */
title = XtCreateManagedWidget("title",
xmCascadeButtonWidgetClass, menu_bar, NULL,0);
XtSetArg(wargs[0],XmNmenuHelpWidget, title);
XtSetValues(menu_bar, wargs, 1);
w_print(title,top);
XtSetArg(wargs[0], XmNscrollingPolicy, XmAUTOMATIC);
sw = XtCreateManagedWidget("swindow",
xmScrolledWindowWidgetClass, frame, wargs, 1);
/* Tree widget */
#ifdef TREE
tree = XtCreateManagedWidget("tree",XstreeWidgetClass,
sw, NULL,0);
#else
n=0;
XtSetArg(wargs[n],XmNautoLayoutMode, TRUE); n++;
XtSetArg(wargs[n],XmNsiblingSpacing, 5); n++;
XtSetArg(wargs[n],XmNarcDrawMode,XmPOSITION_FIXED);n++;
tree = XmCreateGraph(sw,"tree", wargs,n);
/* XmAddTabGroup(tree); */
XtManageChild(tree);
XtAddCallback(reorient, XmNactivateCallback,
re_orient, tree);
#endif
XmMainWindowSetAreas(main_w, menu_bar, NULL,
NULL, NULL, frame);
show_dtree(tree);
clickB(options,file_pointer,NULL);
XtRealizeWidget(toplevel);
XtMainLoop();
}
}
exit(0) ;
}
t_search(dir, addrs)
char *dir;
struct entry *addrs;
{
int bsort; /* index to begin sort */
int stmp; /* save temporary index value */
struct entry *sstep; /* saved step in list */
int nitems; /* # of items in this directory */
#ifdef NEWDIR
DIR *dirp; /* pointer to directory */
#else
FILE *dirp;
#endif
char sub[MAXNAMLEN+1]; /* used for subdirectory names */
int i;
#ifdef NEWDIR
struct direct *dp;
#else
struct direct dirent;
struct direct *dp = &dirent;
#endif /* NEWDIR */
int n_subs = 0;
int tmp = 0;
#ifdef NEWDIR
dirp = opendir(".");
#else
dirp = fopen(".", "r");
#endif /* NEWDIR */
if (dirp == NULL) {
fprintf(stderr, "dtree: Cannot open directory ");
perror(dir);
return(0);
}
#ifndef NEWDIR
setbuf(dirp, Buf2);
#endif /* NEWDIR */
bsort = Index;
sstep = &List[bsort]; /* initialize sstep for for loop later on */
nitems = Index;
/* get the entries of the directory that we are interested in */
#ifndef NEWDIR
while (fread((char *)(dp), sizeof(struct direct), 1, dirp) == 1) {
#else
while ((dp = readdir(dirp)) != NULL) {
#endif /* NEWDIR */
if (dp->d_ino
#ifdef unos
== -1
#else
== 0
#endif /* unos */
|| (strcmp(dp->d_name, ".") == SAME)
|| (strcmp(dp->d_name, "..") == SAME)
|| (Point && dp->d_name[0] == '.'))
continue;
strncpy(sub, dp->d_name, MAXNAMLEN);
#ifdef S_IFLNK
if (lstat(sub,&Lstat) == FAIL) {
fprintf(stderr, "dtree: In directory %s, cannot lstat entry ", dir);
perror(sub);
continue;
}
#endif /* S_IFLNK */
if (stat(sub, &Status) == FAIL) {
fprintf(stderr, "dtree: In directory %s, cannot stat entry ", dir);
perror(sub);
continue;
}
#ifdef S_IFLNK
if (((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
((Status.st_mode & S_IFMT) == S_IFDIR))
List[Index].dir = 0;
else if ((((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
((Status.st_mode & S_IFMT) != S_IFDIR)) && (All))
List[Index].dir = 0;
#endif /* S_IFLNK */
else if ((Status.st_mode & S_IFMT) == S_IFDIR)
List[Index].dir = 1;
else if (All)
List[Index].dir = 0;
else
continue;
strncpy(List[Index].e_name, dp->d_name, MAXNAMLEN);
getwd(List[Index].path_name);
List[Index].last = 0;
List[Index].end = 0;
#ifdef S_IFLNK
if ((Lstat.st_mode & S_IFMT) == S_IFLNK) {
List[Index].dev = (Device == Lstat.st_dev);
List[Index].e_mode = Lstat.st_mode;
List[Index].e_uid = Lstat.st_uid;
List[Index].e_gid = Lstat.st_gid;
List[Index].e_size = Lstat.st_size;
}
else {
#endif /* S_IFLNK */
List[Index].dev = (Device == Status.st_dev);
#ifdef STATS
List[Index].e_mode = Status.st_mode;
List[Index].e_uid = Status.st_uid;
List[Index].e_gid = Status.st_gid;
List[Index].e_size = Status.st_size;
#endif /* STATS */
#ifdef S_IFLNK
}
#endif /* S_IFLNK */
if (stln(List[Index].e_name) > Maxes[Level])
Maxes[Level] = stln(List[Index].e_name);
++Index;
if (Index*sizeof(struct entry) >= Size) {
Size += 20*sizeof(struct entry);
List = (struct entry *)xrealloc((char *)List, Size);
}
}
#ifdef NEWDIR
closedir(dirp);
#else
fclose(dirp);
#endif /* NEWDIR */
nitems = Index - nitems; /* nitems now contains the # of */
/* items in this dir, rather than */
/* # total items before this dir */
if (Sort)
qsort(&List[bsort], nitems, sizeof(struct entry), compar);
List[Index-1].last = 1; /* mark last item for this dir */
n_subs = nitems;
stmp = Index;
/* now walk through, and recurse on directory entries */
/* sstep was initialized above */
for (i = 0; i < nitems; sstep = &List[stmp - nitems+(++i)]) {
if (sstep->dir && (Level < newlevel) && (Xdev || sstep->dev)) {
sstep->next = Index;
strncpy(sub, sstep->e_name, MAXNAMLEN);
tmp = n_subs;
Level++;
if (chdir(sub) == FAIL) {
fprintf(stderr,
"dtree: Cannot change to directory %s/", dir);
perror(sub);
} else {
n_subs += t_search(sub, sstep);
if (chdir("..") == FAIL) {
fprintf(stderr,
"dtree: %s/%s lacks '..' entry\n",dir, sub);
exit(1);
}
}
--Level;
if (n_subs - tmp <= 0)
sstep->next = 0;
else
--n_subs;
}
else
sstep->next = 0;
}
addrs->end = (unsigned)n_subs;
return(n_subs);
}
/*
* comparison routine for qsort
*/
compar(a, b)
struct entry *a, *b;
{
if (!File_dir) /* straight alphabetical */
return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
/* sort alphabetically if both dirs or both not dirs */
if ((a->dir && b->dir) || (!a->dir && !b->dir))
return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
if (File_dir == FFIRST) { /* sort by files first */
if (a->dir)
return(GREATER);
else
return(LESSTHAN);
}
if (a->dir) /* sort by dir first */
return(LESSTHAN);
else
return(GREATER);
}
pt_tree()
{
register int i,j;
struct entry *l;
struct entry *hdr[DEPTH];
int posit[DEPTH]; /* array of positions to print dirs */
int con[DEPTH]; /* flags for connecting up tree */
char flag = 0; /* flag to leave blank line after dir */
struct entry *stack[DEPTH]; /* save positions for changing levels */
int top = 0; /* index to top of stack */
int count = 1; /* count of line of output */
Level = 0; /* initialize Level */
/* this loop appends each entry with dashes or spaces, for */
/* directories or files respectively */
for (i = 0; i < Index; i++) {
for (j = 0; j < MAXNAMLEN; j++) {
if (!List[i].e_name[j])
break;
}
if (List[i].dir) {
for (; j < MAXNAMLEN; j++)
List[i].e_name[j] = '-';
} else {
for (; j < MAXNAMLEN; j++)
List[i].e_name[j] = ' ';
}
}
/* adjust the Maxes array according to the flags */
for (i = 0; i < DEPTH; i++) {
if (Varspaces) {
if (Maxes[i] > CLength )
Maxes[i] = CLength;
} else
Maxes[i] = CLength;
}
/* clear the connective and position flags */
for (i = 0; i < DEPTH; i++)
con[i] = posit[i] = 0;
/* this is the main loop to print the tree structure. */
l = &List[0];
j = 0;
for (;;) {
/* directory entry, save it for later printing */
if (l->dir != 0 && l->next != 0) {
hdr[Level] = l;
posit[Level] = count + (l->end + 1)/2 - 1;
flag = 1;
stack[top++] = l;
l = &List[l->next];
++Level;
continue;
}
#ifdef STATS
do_it_again:
#endif /* STATS */
/* print columns up to our entry */
for (j = 0; j < (flag ? Level-1 : Level); j++) {
if (!flag && posit[j] && posit[j] <= count) {
/* time to print it */
if (hdr[j]->e_name[CLength-1] != '-')
hdr[j]->e_name[CLength-1] = '*';
printf("|-%.*s",Maxes[j],hdr[j]->e_name);
posit[j] = 0;
if (hdr[j]->last != 0)
con[j] = 0;
else
con[j] = 1;
#ifdef STATS
if (Gflag || Longflg) {
if ((i = j+1) <= Level)
printf("| %.*s", Maxes[i], Spaces);
for (i++; i <= Level; i++) {
printf("%c %.*s",
(con[i] ? '|' : ' '),
Maxes[i], Spaces);
}
if (!Compact) {
printf("%s ", getmode(hdr[j]->e_mode));
if (Longflg)
printf("%8.8s ",guid(hdr[j]->e_uid));
if (Gflag)
printf("%8.8s ",ggid(hdr[j]->e_gid));
printf("%7ld\n",
(hdr[j]->e_size+511L)/512L);
} else {
printf(" %04o ",hdr[j]->e_mode & 07777);
if (Longflg)
printf("%5u ", hdr[j]->e_uid);
if (Gflag)
printf("%5u ", hdr[j]->e_gid);
printf("%7ld\n",
(hdr[j]->e_size+511L)/512L);
}
goto do_it_again;
}
#endif /* STATS */
} else
printf("%c %.*s", (con[j] ? '|' : ' '),
Maxes[j], Spaces);
}
if (flag) { /* start of directory, so leave a blank line */
printf(con[j] ? "|\n" : "\n");
flag = 0;
continue;
} else {
/* normal file name, print it out */
if (l->e_name[CLength-1] != '-' &&
l->e_name[CLength-1] != ' ')
l->e_name[CLength-1] = '*';
printf("|-%.*s",Maxes[Level],l->e_name);
if (l->last) {
con[j] = 0;
} else {
con[j] = 1;
}
#ifdef STATS
if (Gflag || Longflg) {
if (Compact) {
printf(" %04o ", l->e_mode & 07777);
if (Longflg)
printf("%5u ", l->e_uid);
if (Gflag)
printf("%5u ", l->e_gid);
printf("%7ld",
(l->e_size+511L)/512L);
} else {
printf("%s ", getmode(l->e_mode));
if (Longflg)
printf("%8.8s ",guid(l->e_uid));
if (Gflag)
printf("%8.8s ",ggid(l->e_gid));
printf("%7ld",
(l->e_size+511L)/512L);
}
}
#endif /* STATS */
}
printf("\n");
if (l->last) {
/* walk back up */
while (l->last) {
--Level;
if (--top <= 0)
return;
l = stack[top];
}
}
l = &l[1];
++count;
}
}
#ifdef STATS
char *
guid(uid)
short uid;
{
static char tb[10];
struct passwd *pswd;
pswd = getpwuid(uid);
if (pswd == NULL)
sprintf(tb,"%u", uid);
else
sprintf(tb, "%8s", pswd->pw_name);
return(tb);
}
char *
ggid(gid)
short gid;
{
static char tb[10];
struct group *grp;
grp = getgrgid(gid);
if (grp == NULL)
sprintf(tb,"%u", gid);
else
sprintf(tb, "%8s", grp->gr_name);
return(tb);
}
/* take the mode and make it into a nice character string */
char *
getmode(p_mode)
unsigned short p_mode;
{
static char a_mode[16];
register int i = 0, j = 0;
a_mode[j++] = ' ';
switch (p_mode & S_IFMT) {
#ifdef S_IFLNK
case S_IFLNK:
a_mode[j++] = 'l';
break;
#endif /* S_IFLNK */
case S_IFDIR:
a_mode[j++] = 'd';
break;
#ifdef S_IFMPC /* defined in stat.h if you have MPX files */
case S_IFMPC:
a_mode[j-1] = 'm';
/* FALL THROUGH */
#endif /* S_IFMPC */
case S_IFCHR:
a_mode[j++] = 'c';
break;
#ifdef S_IFMPB /* defined in stat.h if you have MPX files */
case S_IFMPB:
a_mode[j-1] = 'm';
/* FALL THROUGH */
#endif /* S_IFMPB */
case S_IFBLK:
a_mode[j++] = 'b';
break;
case S_IFREG:
default:
a_mode[j++] = (p_mode & S_ISVTX) ? 't' : ' ';
break;
}
a_mode[j++] = ' ';
for( i = 0;i<3;i++ ) {
a_mode[j++] = (p_mode<<(3*i) & S_IREAD) ? 'r' : '-';
a_mode[j++] = (p_mode<<(3*i) & S_IWRITE) ? 'w' : '-';
a_mode[j++] = (i<2 && (p_mode<<i & S_ISUID)) ? 's' :
((p_mode<<(3*i) & S_IEXEC ) ? 'x' : '-');
a_mode[j++] = ' ';
}
a_mode[j] = '\0';
return(a_mode);
}
#endif
/* like strlen, but returns length up to MAXNAMLEN-1 */
stln(st)
register char *st;
{
register int t;
for (t=0; t<MAXNAMLEN-1; ++t)
if (!st[t])
return (++t);
return (++t);
}
print_date()
{
long now;
time(&now);
printf ("%s", ctime(&now));
}
void
memory_out()
{
fprintf(stderr, "dtree: Virtual memory exhausted\n");
exit(1);
}
/* Allocate `size' bytes of memory dynamically, with error checking. */
char *
xmalloc (size)
unsigned size;
{
char *ptr;
ptr = malloc (size);
if (ptr == 0 && size != 0)
memory_out ();
return ptr;
}
/* Change the size of an allocated block of memory `ptr' to `size' bytes,
with error checking.
If `ptr' is NULL, run xmalloc.
If `size' is 0, run free and return NULL. */
char *
xrealloc (ptr, size)
char *ptr;
unsigned size;
{
if (ptr == 0)
return xmalloc (size);
if (size == 0) {
free (ptr);
return 0;
}
ptr = realloc (ptr, size);
if (ptr == 0 && size != 0)
memory_out ();
return ptr;
}
/*-------------------------New functions for X windows -----------------*/
/* Main program to display the tree in an X window */
show_dtree(parent)
Widget parent;
{
Arg wargs[4];
struct entry *stack[DEPTH], *branch;
int n, top=0, *dir_index;
int dir_node=0, dir_count=0, i;
Widget parent_node=NULL, *Dir, arc;
XmString label_s = NULL;
/* Find the number of directories */
for(i=0; i < Index; i++)
if(List[i].dir == 1) dir_count++;
if((Dir = (Widget *) malloc( dir_count * sizeof(Widget))) == NULL){
fprintf(stderr,"malloc failure\n");
exit(1);
}
if((dir_index = (int *) malloc(dir_count * sizeof(int))) == NULL) {
fprintf(stderr,"malloc failure\n");
exit(1) ;
}
branch = &List[0];
if(dir_count == 1 && branch->next == 0) {
if(All == 0) {
fprintf(stderr,"No subdirectories under directory %s\n",
branch->e_name);
fprintf(stderr,"You may want to try the -ap option\n");
}
else fprintf(stderr,"No files under directory %s\n",
branch->e_name);
exit(0);
}
/* Distinguish between directories and files */
for(;;) {
if(branch->dir != 0 && branch->next != 0) {
dir_index[top] = dir_node;
stack[top++] = branch;
n=0;
#ifdef TREE
XtSetArg(wargs[n], XtNsuperNode,parent_node); n++;
#endif
label_s = XmStringCreateLtoR(branch->e_name,
XmSTRING_DEFAULT_CHARSET);
XtSetArg(wargs[n], XmNlabelString,label_s); n++;
Dir[dir_node] = XmCreatePushButton(parent,"dir",
wargs,n);
XtManageChild(Dir[dir_node]);
XtAddCallback(Dir[dir_node],XmNactivateCallback,
clickB, branch);
#ifndef TREE
/* create the arc */
if(parent_node) {
n=0;
XtSetArg(wargs[n], XmNarcDirection, XmDIRECTED); n++;
XtSetArg(wargs[n], XmNto, Dir[dir_node]); n++;
XtSetArg(wargs[n], XmNfrom, parent_node); n++;
arc = XmCreateArc(parent, branch->e_name,wargs,n);
XtManageChild(arc);
}
#endif
branch = &List[branch->next];
parent_node = Dir[dir_node++];
continue;
}
create_file_node(parent,branch,parent_node);
if(branch->last) {
while(branch->last) {
if(--top <= 0 ) {
free(Dir);
free(dir_index);
return;
}
branch = stack[top];
parent_node = Dir[dir_index[top-1]];
}
}
branch = &branch[1];
}
}
/* Function that creates a widget for a node. Three types are available,
dir, for directories , file, for files, and sym_link for
symbolic links
*/
create_file_node(pparent,bbranch,nnode)
Widget pparent, nnode;
struct entry *bbranch;
{
Widget w, arc;
Arg wargs[4];
int n;
char *win_type;
XmString label_s = NULL;
int Gflag=1; /* this is a gadget */
n=0;
label_s = XmStringCreateLtoR(bbranch->e_name,
XmSTRING_DEFAULT_CHARSET);
XtSetArg(wargs[n], XmNlabelString,label_s); n++;
/* Check the type of the node */
if(bbranch->dir == 1) {
win_type = "dir";
Gflag = 0;
}
#ifdef STATS
else if(strncmp(" l",getmode(bbranch->e_mode),2) == 0)
{win_type = "sym_link"; Gflag = 0;}
#endif /* STATS */
else win_type = "file";
#ifdef TREE
XtSetArg(wargs[n], XtNsuperNode, nnode); n++;
w = XmCreatePushButton(pparent, win_type, wargs, n);
#else
if(Gflag == 0)
w = XmCreatePushButton(pparent, win_type, wargs, n);
else
w = XmCreatePushButtonGadget(pparent, win_type, wargs, n);
#endif
XtManageChild(w);
XtAddCallback(w,XmNactivateCallback,clickB,bbranch);
#ifndef TREE
/* create the arcs */
n=0;
XtSetArg(wargs[n], XmNarcDirection, XmDIRECTED); n++;
XtSetArg(wargs[n], XmNto, w); n++;
XtSetArg(wargs[n], XmNfrom, nnode); n++;
arc = XmCreateArc(pparent, bbranch->e_name,wargs,n);
XtManageChild(arc);
#endif
}
/* Function that creates the pull-down menu when someone clicks on the
active node of the tree.
*/
show_menu(pparent, bbranch)
Widget pparent;
struct entry *bbranch;
{
Widget menu ;
Widget submenu_dir, submenu_file;
int i;
char *mode_name;
Arg wargs[4];
menu = XmCreatePulldownMenu(pparent,"menu",NULL, 0);
XtSetArg(wargs[0], XmNsubMenuId,menu);
options = XtCreateManagedWidget("options",xmCascadeButtonWidgetClass,
pparent, wargs, 1);
w_print(options, bbranch->e_name);
/*
boxes[0] = XtCreateManagedWidget("title",xmLabelWidgetClass,
menu, NULL,0);
XtCreateManagedWidget("separator",xmSeparatorWidgetClass,
menu, NULL,0);
*/
#ifdef STATS
for(i = 1; i < 4 ; i++)
boxes[i] = XtCreateManagedWidget("id",xmLabelWidgetClass,
menu, NULL,0);
button_print(bbranch); /* print the labels on the menu */
XtCreateManagedWidget("separator2",xmSeparatorWidgetClass,
menu, NULL,0);
/* Create sub-menus */
#endif /*STATS */
file_menu = XtCreateManagedWidget("File Options",
xmCascadeButtonWidgetClass, menu, NULL,0);
dir_menu = XtCreateManagedWidget("Directory Options",
xmCascadeButtonWidgetClass, menu, NULL,0);
/* Create cascading sub-menus */
/* If it is a file */
submenu_file = XmCreatePulldownMenu(menu, "filesubmenu", NULL, 0);
XtSetArg(wargs[0], XmNsubMenuId, submenu_file);
XtSetValues(file_menu, wargs, 1);
boxes[4] = XtCreateManagedWidget("view",xmPushButtonWidgetClass,
submenu_file, NULL,0);
XtAddCallback(boxes[4], XmNactivateCallback,view, NULL);
boxes[5] = XtCreateManagedWidget("topview",
xmPushButtonWidgetClass, submenu_file, NULL,0);
XtAddCallback(boxes[5], XmNactivateCallback,view, NULL);
boxes[6] = XtCreateManagedWidget("edit",
xmPushButtonWidgetClass, submenu_file, NULL,0);
XtAddCallback(boxes[6], XmNactivateCallback,do_menu, NULL);
boxes[7] = XtCreateManagedWidget("print",
xmPushButtonWidgetClass, submenu_file, NULL,0);
XtAddCallback(boxes[7], XmNactivateCallback,do_menu, NULL);
/* if it a directory */
submenu_dir = XmCreatePulldownMenu(menu, "dirsubmenu", NULL, 0);
XtSetArg(wargs[0], XmNsubMenuId, submenu_dir);
XtSetValues(dir_menu, wargs, 1);
boxes[8] = XtCreateManagedWidget("show subtree",
xmPushButtonWidgetClass, submenu_dir, NULL,0);
XtAddCallback(boxes[8], XmNactivateCallback,do_menu, NULL);
boxes[9] = XtCreateManagedWidget("list files",
xmPushButtonWidgetClass, submenu_dir, NULL,0);
XtAddCallback(boxes[9], XmNactivateCallback,do_menu, NULL);
boxes[10] = XtCreateManagedWidget("list ../",
xmPushButtonWidgetClass, submenu_dir, NULL,0);
XtAddCallback(boxes[10], XmNactivateCallback,do_menu, NULL);
}
/* Not used here, but may be useful in the future !!! */
/* Copied from D. Young's book */
/*
void post_menu_handler(w, menu, event)
Widget w, menu;
XEvent *event;
{
Arg wargs[10];
int button;
XtSetArg(wargs[0], XmNwhichButton, &button);
XtGetValues(menu, wargs, 1);
if(event->xbutton.button == button) {
XmMenuPosition(menu, event);
XtManageChild(menu);
}
}
*/
/* Quick and dirty way to view a file in a pop-up window
Speed may improve, if one reads and displays page by page
No check to see if the file is binary
*/
void view(w, call_mydata, call_data)
Widget w;
caddr_t call_data, call_mydata;
{
struct entry *branch;
char *filename[MAXPATHLEN+1];
struct stat statbuf; /* Information on a file. */
int file_length; /* Length of file. */
unsigned char * file_string; /* Contents of file. */
FILE *fp = NULL;
Widget text, toplevel2, sw2, button, frame, main_w, menu_bar;
Widget title;
XmString name_string = NULL;
char *button_name = NULL;
int topflag=0;
Arg wargs[10];
int n=0;
branch = file_pointer;
/* find which button called us */
XtSetArg(wargs[0], XmNlabelString, &name_string);
XtGetValues(w,wargs,1);
XmStringGetLtoR(name_string,XmSTRING_DEFAULT_CHARSET,&button_name);
if(strcmp("topview",button_name) == 0) topflag = 1;
/* find first the correct path */
strncpy(filename,branch->path_name,MAXPATHLEN);
strcat(filename,"/");
strcat(filename,branch->e_name);
if ((fp = fopen(filename, "r")) == NULL) {
fprintf(stderr,"Can't open file name %s\n",filename);
return;
}
if (stat(filename, &statbuf) == 0)
file_length = statbuf.st_size;
else
file_length = 1000000; /* arbitrary file length */
/* read the file string */
if(topflag == 1 && file_length >= 2000 ) file_length = 2000;
file_string = (unsigned char *) XtMalloc((unsigned)file_length);
fread(file_string, sizeof(char), file_length, fp);
if (fclose(fp) != NULL) fprintf(stderr, "Warning: unable to close file.\n");
/* Create another pop-pup top-shell with a MainWindow */
toplevel2 = XtCreateApplicationShell("Dtreef",topLevelShellWidgetClass,
NULL,0);
main_w = XmCreateMainWindow(toplevel2,"mainw",NULL,0);
XtManageChild(main_w);
menu_bar = XmCreateMenuBar(main_w,"menu",NULL,0);
XtManageChild(menu_bar);
XtSetArg(wargs[0], XmNshadowType, XmSHADOW_OUT);
frame = XmCreateFrame(main_w,"frame",wargs,1);
XtManageChild(frame);
XtSetArg(wargs[0], XmNscrollingPolicy, XmAUTOMATIC);
sw2 = XtCreateManagedWidget("swindowf",
xmScrolledWindowWidgetClass,frame, wargs,1);
XmMainWindowSetAreas(main_w, menu_bar, NULL, NULL, NULL, frame);
button = XmCreateCascadeButton(menu_bar, "quit",NULL,0);
XtManageChild(button);
XtAddCallback(button,XmNactivateCallback,quit_b_pop,toplevel2);
title = XtCreateManagedWidget("title",
xmCascadeButtonWidgetClass, menu_bar, NULL,0);
w_print(title, filename);
/* Create Text widget */
n=0;
XtSetArg (wargs[n], XmNeditable, FALSE); n++;
text = XmCreateText(sw2, "text", wargs, n);
/* added the file string to the text widget */
XmTextSetString(text, file_string);
if(file_string != NULL) XtFree(file_string);
if(name_string != NULL) XtFree(name_string);
/* Poput the text file */
XtPopup(toplevel2,XtGrabNone);
XtManageChild(text);
}
/* CallBack function of the quit button on a pop-up window */
void quit_b_pop(w, topshell, call_data)
Widget w;
Widget topshell;
caddr_t call_data;
{
XtPopdown(topshell);
}
/* function that forks a command from the menu */
/* Needs work!!!!!
*/
void do_menu(w,call_mydata,call_data)
Widget w;
caddr_t call_data, call_mydata;
{
struct entry *branch;
char *filename[MAXPATHLEN+1];
char *topdir[MAXPATHLEN+1];
XmString name_string = NULL;
char *button_name = NULL;
char *lpdest=NULL, *editor = NULL;
char *EDITOR="EDITOR\0";
int pid, pathl,namel;
Arg wargs[3];
/* find which button called us */
branch = file_pointer;
XtSetArg(wargs[0], XmNlabelString, &name_string);
XtGetValues(w,wargs,1);
XmStringGetLtoR(name_string,XmSTRING_DEFAULT_CHARSET,&button_name);
/* find first the correct path - append the file name
except for the "root" directory */
strncpy(filename,branch->path_name,MAXPATHLEN);
if(branch->next != 1) {
strcat(filename,"/");
strcat(filename,branch->e_name);
}
/* fork a new process */
pid = fork();
if(pid > 0) {
/* wait((int *)0); */
return;
}
if(pid == 0) {
/* for(fd = 0; fd < _NFILE; fd++) close(fd); */
if(strcmp(button_name,"print") == 0) {
lpdest = XGetDefault(XtDisplay(w),"dtree","lpdest");
if (lpdest != NULL){
execl("/usr/bin/lp","lp","-d",lpdest,filename,(char *)0);
}
else
execl("/usr/bin/lp","lp",filename,(char *)0);
}
else if(strcmp(button_name,"edit") == 0) {
editor = XGetDefault(XtDisplay(w),"dtree","editor");
if (editor == NULL) {
editor = getenv(EDITOR);
if(editor == NULL)
editor="/usr/bin/vi";
execl("/usr/bin/X11/hpterm",
"hpterm","-e",editor,
filename,(char *)0);
} else
execlp(editor,editor, filename,(char *)0);
}
else if(strcmp(button_name,"list files") == 0) {
execlp("dtree", "dtree",
"-a", "-l","1",filename, (char *)0);
}
else if(strcmp(button_name,"list ../") == 0) {
/* find the parent directory */
pathl = strlen(filename);
namel = strlen(branch->e_name);
strncpy(topdir,branch->path_name,pathl-namel);
execlp("dtree", "dtree", "-l","1",topdir, (char *)0);
}
else
execlp("dtree", "dtree",
"-a",filename, (char *)0);
fprintf(stderr,"%s command failed\n",button_name);
}
fprintf(stderr,"fork for %s command failed\n",button_name);
}
/* Function that updates the pop-up menu labels and permissions
when someone clicks on a node.
*/
void clickB( w,branch,call_data)
Widget w;
struct entry *branch;
caddr_t call_data;
{
Arg wargs[3];
XrmValue bgcolor;
if(branch->dir == 1) {
XtSetSensitive(file_menu ,FALSE);
XtSetSensitive(dir_menu ,True);
}
else {
XtSetSensitive(dir_menu ,False);
#ifdef STATS
/* Don't do anything with symb. links */
if(strncmp(" l",getmode(branch->e_mode),2) == 0)
XtSetSensitive(file_menu ,False);
else
#endif /* STATS */
XtSetSensitive(file_menu ,True);
}
w_print(options, branch->e_name);
/* Get the background color of the activated button
Need to get the foreground color too
*/
_XmSelectColorDefault (w, NULL, &bgcolor);
XtSetArg(wargs[0], XmNbackground, *((Pixel *) bgcolor.addr));
XtSetValues(options, wargs, 1);
file_pointer = branch;
button_print(branch);
}
/* Print a string on a widget */
void w_print(w, string)
Widget w;
char *string;
{
XmString xmstr;
Arg wargs[2];
xmstr = XmStringLtoRCreate(string, XmSTRING_DEFAULT_CHARSET);
XtSetArg(wargs[0], XmNlabelString, xmstr);
XtSetValues(w,wargs, 1);
}
/* print the labels on the popup menu */
void button_print(branch)
struct entry *branch;
{
char tmp[40];
/* w_print(boxes[0], branch->e_name); */
#ifdef STATS
strncpy(tmp,"Mode :",40);
strcat(tmp,getmode(branch->e_mode));
w_print(boxes[1],tmp);
strncpy(tmp,"User :",40);
strcat(tmp,guid(branch->e_uid));
w_print(boxes[2], tmp);
strncpy(tmp,"Group:",40);
strcat(tmp, ggid(branch->e_gid));
w_print(boxes[3], tmp);
#endif /* STATS */
}
/*
* Copied from D. Young's book with some changes
* Define three callbacks. Make them static - no need
* to make them known outside this file.
*/
static void arm_callback(w, flag, call_data)
Widget w;
int *flag;
XmAnyCallbackStruct *call_data;
{
*flag = FALSE;
}
static void activate_callback(w, flag, call_data)
Widget w;
int *flag;
XmAnyCallbackStruct *call_data;
{
*flag = TRUE;
}
static void disarm_callback(w, flag, call_data)
Widget w;
int *flag;
XmAnyCallbackStruct *call_data;
{
if(*flag){
XtCloseDisplay(XtDisplay(w));
exit(0);
}
}
/* function to re-orient the graph */
#ifndef TREE
void re_orient(w, graph, call_data)
Widget w, graph;
caddr_t call_data;
{
Arg wargs[2];
XtSetArg(wargs[0], XmNreorient, True);
XtSetValues(graph, wargs, 1);
}
#endif
@EOF
chmod 444 dtree.c
echo x - Makefile
cat >Makefile <<'@EOF'
# Makefile for dtree
# Things that might go in DEFS:
# -DSTATS -DNEWDIR -DDIRENT -DNDIR -DSYSV
# The -DTREE flag is used to create dtree with the Tree widget
# otherwise it uses the XmGraph widget.
DEFS = -D_HPUX_SOURCE -DSTATS -DNEWDIR -DSYSV #-DDIRENT -DS_IFLNK
CFLAGS = $(DEFS) -O
LDFLAGS =
LIBS = # For Xenix use -lx with -DNDIR
LIBS = -lmalloc -lXm -lXt -lX11 -lm
BINDIR = /usr/local/bin/X11
MANDIR = /usr/local/man/man1
OBJECTS_A = dtree.o Arc.o Graph.o #using XmGraph
OBJECTS_B = dtree_tree.o Tree.o #using D. Young's tree.
ARCH_FILES = dtree.1 dtree.c Makefile Dtree Tree.h TreeP.h \
dtree-i.h Tree.c Arc.c Arc.h ArcP.h Graph.c Graph.h GraphP.h
ARCH_FILESB = dtree.1 dtree.c Makefile Dtree dtree-i.h Imakefile README
all: dtree_tree
dtree: $(OBJECTS_A)
$(CC) -o dtree $(LDFLAGS) $(OBJECTS_A) $(LIBS)
dtree_tree: $(OBJECTS_B)
$(CC) -o dtree $(LDFLAGS) $(OBJECTS_B) $(LIBS)
Arc.o: Arc.c
$(CC) -c $(CFLAGS) Arc.c +Ns4000
Graph.o: Graph.c
$(CC) -c $(CFLAGS) Graph.c +Ns4000
dtree_tree.o: dtree.c
$(CC) -o dtree_tree.o -c $(CFLAGS) -DTREE dtree.c
install: dtree dtree.1
cp dtree $(BINDIR)
cp dtree.1 $(MANDIR)
lint: dtree.c
lint $(DEFS) dtree.c
shar: $(ARCH_FILESB)
shar $(ARCH_FILESB) > dtree.shar_1
shar Tree* > dtree.shar_2
dist: dtree.tar.Z
tar: dtree.tar.Z
dtree.tar.Z: $(ARCH_FILES)
tar cf - $(ARCH_FILES) | compress > dtree.tar.Z
clean:
rm -f dtree *.o core tags a.out
@EOF
chmod 644 Makefile
echo x - Dtree
cat >Dtree <<'@EOF'
#
# app-defaults file for dtree
#
dtree*geometry: 500x500
dtree*dir.background: Red
dtree*file.background: Gray
dtree*sym_link.background: Brown
dtree*quit.background: DarkSlateBlue
dtree*options.background: Red
dtree*XmGraph*childSpacing: 50 #distance between levels
Mwm*Dtree*iconImage: /usr/local/include/X11/bitmaps/dtree-i.h
Hpwm*Dtree*iconImage: /usr/local/include/X11/bitmaps/dtree-i.h
!dtree*lpdest: rljet #Printer destination
!dtree*editor: emacsclient #window-clever editor
!dtree*sym_link.foreground:
@EOF
chmod 644 Dtree
echo x - dtree-i.h
cat >dtree-i.h <<'@EOF'
#define load_i_width 50
#define load_i_height 50
static char load_i_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10,
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0xf8, 0x0f, 0x10, 0x00, 0x20, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
0x20, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x20, 0x00, 0x00, 0x0f, 0x08,
0x00, 0x00, 0x20, 0x00, 0x00, 0x09, 0x08, 0x10, 0x00, 0x20, 0x00, 0x80,
0x08, 0x08, 0x00, 0x00, 0x20, 0x00, 0x80, 0xf8, 0x0f, 0x10, 0x00, 0x20,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x10,
0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0xfe,
0x13, 0xfe, 0xe3, 0x17, 0x00, 0x20, 0x02, 0x0a, 0x02, 0x22, 0x04, 0x00,
0x20, 0xaa, 0x0a, 0x56, 0x23, 0x14, 0x00, 0x20, 0x02, 0xfe, 0x03, 0x3e,
0x04, 0x00, 0x20, 0xaa, 0x0a, 0xaa, 0x22, 0x14, 0x00, 0x20, 0x02, 0x0a,
0x02, 0x22, 0x04, 0x00, 0x20, 0xfe, 0x13, 0xfe, 0xe3, 0x17, 0x00, 0x20,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x10,
0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0xf8,
0x0f, 0x10, 0x00, 0x20, 0x00, 0x40, 0x08, 0x08, 0x00, 0x00, 0x20, 0x00,
0x80, 0x08, 0x08, 0x10, 0x00, 0x20, 0x00, 0x80, 0x08, 0x08, 0x00, 0x00,
0x20, 0x00, 0x00, 0x0f, 0x08, 0x10, 0x00, 0x20, 0x00, 0x00, 0x08, 0x08,
0x00, 0x00, 0x20, 0x00, 0x00, 0xf8, 0x0f, 0x10, 0x00, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10,
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x55, 0x55, 0x55,
0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00};
@EOF
chmod 644 dtree-i.h
echo x - Imakefile
cat >Imakefile <<'@EOF'
#Imakefile to create dtree using the "tree" widget.
DEFINES = -DSTATS -DNEWDIR -DSYSV -DTREE
LOCAL_LIBRARIES =
SYS_LIBRARIES = -lmalloc -lXm -lXt -lX11 -lm
SRCS = dtree.c Tree.c
OBJS = dtree.o Tree.o
ComplexProgramTarget(dtree)
@EOF
chmod 644 Imakefile
echo x - README
cat >README <<'@EOF'
This version of dtree is an X extension of the program originally
written by Dave Borman. It displays on a terminal or under X11
(using Motif widgets) the tree structure of a Unix directory tree.
On a color terminal, different colors can be used for files, directories,
and symbolic links. One can select nodes of the tree, and edit them,
view them, or print them. One can also traverse nodes not fully
shown on the original tree.
The program uses the "tree" widget described in D. Young's book on
X window programming (code included here). The program also runs
using the XmGraph widget, but because that code is not yet stable,
the code for the XmGraph widget is not included here.
To make the program run: make dtree_tree
The program runs faster with the "tree" widget, but the XmGraph
widgets may provide the potential for additional capabilities, such
as: removing files from the tree, copying of files and directories, etc.
Potential problem: because dtree creates a PushButton widget for every file
or directory shown, you may run out of memory. It is recommended that you
start with a moderate size tree, and create new ones as needed.
Experience will show how much you can push it!!
If you have a monochrome monitor, you may want to substitute those
widgets with gadgets.
For example: dtree -l 2
will show the tree of your current directory up to depth 2.
dtree -al 2
will show both files and directories up to depth 2.
K. Konstantinides
HP Labs
kk at hpkronos.hpl.hp.com
@EOF
chmod 644 README
exit 0
dan
----------------------------------------------------
O'Reilly && Associates argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list