home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume8 / dtree / part01.1 < prev    next >
Internet Message Format  |  1990-08-16  |  57KB

  1. Path: uunet!sdrc!cinnet!spca6!uccba!ucunix!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!usc!apple!sun-barr!newstop!sun!hpkronos.hpl.hp.com
  2. From: kk@hpkronos.hpl.hp.com (Konstantinos Konstantinides)
  3. Newsgroups: comp.sources.x
  4. Subject: v08i072: dtree, Part01/02
  5. Message-ID: <140746@sun.Engngun.COM>
  6. Date: 16 Aug 90 03:04:27 GMT
  7. Sender: news@sun.EnSun.COM
  8. Lines: 2095
  9. Approved: argv@sun.com
  10.  
  11. Submitted-by: Konstantinos Konstantinides <kk@hpkronos.hpl.hp.com>
  12. Posting-number: Volume 8, Issue 72
  13. Archive-name: dtree/part01
  14.  
  15. This version of dtree is an X extension of the program originally
  16. written by Dave Borman. It displays on a terminal or under X11
  17. (using Motif widgets) the tree structure of a Unix directory tree.
  18. On a color terminal, different colors can be used for files, directories,
  19. and symbolic links. One can select nodes of the tree, and edit them,
  20. view them, or print them. One can also traverse nodes not fully
  21. shown on the original tree.
  22.  
  23. K. Konstantinides
  24. kk@hpkronos.hpl.hp.com
  25. -------------------------Beginning of submission--Part 1 of 2----------
  26. # This is a shell archive.  Remove anything before this line,
  27. # then unpack it by saving it in a file and typing "sh file".
  28. #
  29. # Wrapped by Konstantinos Konstantinides <kk@hpkronos> on Tue Aug 14 15:06:50 1990
  30. #
  31. # This archive contains:
  32. #    dtree.1        dtree.c        Makefile    Dtree        
  33. #    dtree-i.h    Imakefile    README        
  34. #
  35.  
  36. LANG=""; export LANG
  37. PATH=/bin:/usr/bin:$PATH; export PATH
  38.  
  39. echo x - dtree.1
  40. cat >dtree.1 <<'@EOF'
  41. .TH DTREE 1L
  42. .SH NAME
  43. dtree \- display directory tree structures
  44. .SH SYNOPSIS
  45. .B dtree
  46. [
  47. .I \-aDfghHNpsStvx
  48. ] [
  49. .I \-l level
  50. ] [
  51. .I \-c linelength
  52. ] [
  53. .BR directory ...
  54. ]
  55. .SH DESCRIPTION
  56. .I dtree
  57. displays a graphic representation of the directory structure of each given
  58. .B directory 
  59. and its children either on the terminal stdout or on an X11 window, using
  60. the Motif widgets (default). If no directories are specified, the current
  61. directory is used.
  62. By default, only directories, not regular files, are shown, and only their
  63. filenames are given.  Various options add additional
  64. information to the tree.
  65. .SS OPTIONS
  66. .TP
  67. .I \-a
  68. Include files in the listing (excluding entries beginning with '.').
  69. .TP
  70. .I \-c linelength
  71. Make
  72. .I linelength
  73. the length of each
  74. column of the printout.  By default, this is 14.
  75. Any entries longer than
  76. the column length are truncated accordingly, and the last character that
  77. fits into the column is replaced by an asterisk.
  78. This option only has an effect if the
  79. .I -v 
  80. option is specified.
  81. .TP
  82. .I \-l level
  83. Search only up to the specified level. (Maximum is 10).
  84. .TP
  85. .I \-D
  86. List directories first.  For each directory, its subdirectories
  87. will be listed first, and then all of its other entries.
  88. .TP
  89. .I \-f
  90. List files first.  The reverse of
  91. .IR  \-D .
  92. .TP
  93. .I \-S
  94. Long listing.  Display useful information to the right of
  95. each entry: the name of the file's owner, its size in blocks, and its mode.
  96. .TP
  97. .I \-g
  98. Same as the
  99. .I \-S
  100. option, except that the group name is used instead of
  101. the owner name.  If both the
  102. .I \-S
  103. and
  104. .I \-g
  105. options are used, both the
  106. owner and group will be displayed.
  107. .TP
  108. .I \-H
  109. Display a header at the top of the printout that gives the time and
  110. date that the printout was made and a summary of the type of
  111. information contained in the tree.
  112. .TP
  113. .I \-N
  114. No sort.  Entries are listed in the order they are read
  115. from the directories.
  116. .TP
  117. .I \-p
  118. Include entries beginning with '.' (except '.' and '..').
  119. .TP
  120. .I \-s
  121. Simplify the long listing: display the user id, size in blocks, and
  122. octal mode of the file.  This option implies the
  123. .I \-S
  124. option unless the
  125. .I \-g
  126. option is specified.
  127. .TP
  128. .I \-v
  129. Do not let column lengths vary; use the same
  130. width for each column of output.  The width defaults to 14
  131. but can be set with the
  132. .I \-c
  133. option.
  134. .TP
  135. .I \-x
  136. Do not cross file systems.  
  137. .I dtree
  138. will not cross over to a
  139. subdirectory if it is on a different file system.
  140. .TP
  141. .I \-h
  142. Will print a list of the options.
  143. .TP
  144. .I \-t
  145. Terminal mode.
  146. In default mode
  147. .I
  148. dtree
  149. will display the directory tree structure in an X11 window.
  150. The \-t option allows the tree to be printed on the terminal stdout.
  151.  
  152. Under the X11 window mode, a button click on a tree node,  makes it
  153. the "active" node. The name of the "active" node always appears
  154. at the top of the window, by the "quit" button.
  155. With a  button click in the area where the "active" node is shown,
  156. a menu appears with the mode of the node, the group and user IDs,
  157. and \fIfile\fR or \fIdirectory\fR options .
  158. There are
  159. four \fIfile\fR options: \fIview, topview, edit\fR and \fIprint\fR.
  160. There are three \fIdirectory\fR options: \fIshow subtree, list files\fR,
  161. and \fIlist '../'\fR.
  162. Thus, the \-c, \-S, \-g, \-s, and \-v options are meaningful only
  163. when the \-t option is used.
  164. .TP
  165. .B view 
  166. Display the whole file on a scrolled window.
  167. Since the program reads a file all at once,
  168. the wait may be significant for a very large file.  However, the option
  169. .TP
  170. .B topview 
  171. shows only the top of the file (2000 bytes).
  172. .TP
  173. .B edit
  174. Edit the file. \fIdtree\fR first checks and executes the command 
  175. specified by the
  176. .B dtree*editor:
  177. resource in .Xdefaults. If that command is NULL, \fIdtree\fR
  178. forks an hpterm window using the editor command specified
  179. in the
  180. .B EDITOR
  181. environmental variable. If that variable is not specified, it uses \fIvi\fR
  182. .TP
  183. .B print
  184. Print the file. It prints the file on the printer destination specified
  185. by the
  186. .B dtree*lpdest:
  187. resource in .Xdefaults.
  188. If that variable is not specified it uses
  189. the default lp destination.
  190. .TP
  191. .B "show subtree"
  192. Show the directory subtree starting from the selected "active"
  193. directory node.
  194. .TP
  195. .B "list files"
  196. List all files and directories for the "active" directory node.
  197. This is equivalent to an "ls" command on that directory.
  198. .TP
  199. .B "list \.\.\/"
  200. List the directories in the parent (top) directory.  Allows the user
  201. to traverse upwards the directory tree.
  202.  
  203. Except for the \fIview\fR and \fItopview\fR options, in all other cases
  204. a click on the "quit" button of the "parent" will
  205. cause the "parent" \fIdtree\fR window to freeze until the selected command
  206. has been executed or the "child" window has been killed.
  207. Then the "parent" window will automatically die.
  208. Thus it is recommended to kill "children" applications before
  209. you try to kill the "parent".
  210.  
  211. On a color terminal, one can choose different colors to distinguish
  212. between directories, files, and symbolic links.
  213. When the XmGraph widget is used, the directory tree can be seen both
  214. vertically and horizontally.
  215. To set up a simple color scheme for \fIdtree\fR, put the following entries
  216. in your ~/.Xdefaults file:
  217.  
  218. dtree*geometry:                     500x500
  219. .br
  220. dtree*quit.background:              DarkSlateBlue
  221. .br
  222. dtree*dir.background:               Red      
  223. .br
  224. dtree*sym_link.background:          Brown  
  225. .br
  226. dtree*options.background:           Red        
  227.  
  228. A set of simple resources is also specified in
  229. /usr/lib/X11/app-defaults/Dtree
  230. .SH AUTHOR
  231. Dave Borman, Digital Unix Engineering Group
  232. .br
  233. decvax!borman
  234. .br
  235. Originally written at St. Olaf College, Northfield, MN.
  236. .br
  237. Additions for the X11 windows display by K. Konstantinides,
  238. Hewlett-Packard Laboratories.
  239. Copyright: Hewlett-Packard, 1990.
  240. e-mail:kk@hpkronos.hpl.hp.com
  241. @EOF
  242.  
  243. chmod 644 dtree.1
  244.  
  245. echo x - dtree.c
  246. cat >dtree.c <<'@EOF'
  247. /*
  248.  *    DTREE - Print the tree structure of a directory
  249.  *    4/7/83 name was changed from TREE to DTREE
  250.  *    9/7/83 mods for 4.1c and 4.2 dirctory structure added
  251.  *
  252.  *    Dave Borman, Digital Unix Engineering Group
  253.  *        decvax!borman
  254.  *    Originally written at St. Olaf College, Northfield MN.
  255.  *    Copyright (c) 1983 by Dave Borman
  256.  *    All rights reserved
  257.  *    This program may not be sold, but may be distributed
  258.  *    provided this header is included.
  259.  *
  260.  *    Usage:    dtree [-aDfghHlNpstvx] [-c line-length] [directory...]
  261.  *    Flags:    -a) include non-directory entries in listing
  262.  *        -D) sort tree with directories at the top
  263.  *        -f) sort tree with files at the top
  264.  *        -g) same as l, but use group name instead of user name
  265.  *              -h) help
  266.  *        -H) display a header at top
  267.  *        -S) print stats with each listing
  268.  *            if both g & l flags are given, both owner and
  269.  *            group will be printed
  270.  *        -N) do not sort the tree
  271.  *        -p) include files starting with a '.' (except "." & "..")
  272.  *        -s) use shorter stats. Implies -S if -g isn't given.
  273.  *              -t) Use terminal mode (no X windows)
  274.  *        -v) variable length columns off
  275.  *        -x) do not cross mounted file systems.
  276.  *        -c length) set max column length to "length"
  277.  *        -l level) search up to the specified "level".
  278.  */
  279.  
  280.  /*     Modified by      Ed Arnold      CSU-CS   (csu-cs!arnold)     3-5-84
  281.   *
  282.   *     Allows symbolic links to both directories and individual files.
  283.   *     With a '-S' or '-aS' option, links are denoted with a 'l' in front of 
  284.   *     file or directory permissions. In all other instances both links to 
  285.   *     directories and files are represented just as files are. Contents of
  286.   *     linked directories are not printed due to the possibility of 
  287.   *     recursively linked directories.
  288.   *
  289.   *     Big directory name option added by:
  290.   *                      Mike Vevea      CSU-CS (csu-cs!vevea)      3-22-84
  291.   *
  292.   *    Toggle sense of -v (running 4.2), and eliminate some extraneous
  293.   *        print info    Mike Meyer Energy Analysts (mwm@ea)    4/17/84
  294.   *
  295.   *    Fix the exit status to correctly indicate what happened.
  296.   *                Mike Meyer Energy Analysts (mwm@ea)    4/23/84
  297.   *
  298.   *    Change MAX to INITIAL_ELEM to fix conflict on Suns,
  299.   *    fix incorrect default value for Clength when -v not given,
  300.   *    add -H option to print header with date and description of tree,
  301.   *    remove -b option (useless) and simplify array access,
  302.   *    use getopt to parse options, fix usage message,
  303.   *    use getwd instead of opening a pipe to pwd,
  304.   *    make error messages more informative,
  305.   *    use strncpy instead of sprintf for speed,
  306.   *    move function declarations to top of file,
  307.   *    comment out junk after #else and #endif,
  308.   *    make symbolic link configuring automatic,
  309.   *    check all error returns from malloc and realloc,
  310.   *    add System V/Xenix/Unos compatibility,
  311.   *    remove definition of rindex.
  312.   *        David MacKenzie <djm@enumd.edu> 12/20/89
  313.   *
  314.   *    Modified to display the tree on X11 windows using the Motif
  315.   *    widgets and the Tree widget described by D.Young in his book,
  316.   *     "The X Window System, Programming and applications with Xt,
  317.   *     OSF/MOTIF EDITION", Prentice Hall, 1990.
  318.   *     Clicking on the "active" node pops-up a menu with the Mode, and Group
  319.   *     and User IDs. Clicking on "view" pops up a window with the whole
  320.   *     contents of the file. Clicking on "topview" shows the top
  321.   *    of the file only (2000 bytes).
  322.   *     On the tree, files, directories, and symbolic links can be
  323.   *     shown with different colors.
  324.   *     Changed some options so there is no conflict with X-window
  325.   *    options ( -d to -D, and -n to -N).
  326.   *    Added the -t and -h options. Changed the -l option to -S
  327.   *     Added the "-l level" option.
  328.   *    Konstantinos Konstantinides, Hewlett-Packard Laboratories
  329.   *     konstantinos_konstantinides@hplabs.hp.com  3/23/90
  330.   *
  331.   *     Copyright: HEWLETT-PACKARD, 1990
  332.   *     Motif is a trademark of Open Software Foundation, Inc.
  333.   *     X Window System is a trademark of the Massachusetts Institute of
  334.   *     Technology
  335.   *
  336.   *    Added support for both the Tree and XmGraph widgets
  337.   *    K. Konstantinides 4/16/90
  338.   */
  339.  
  340. /* Compile-time options:
  341.  *
  342.  * STATS    leave undefined to remove stats, giving more core space
  343.  * and thus the ability to tree larger tree structures on PDP 11/70s.
  344.  *
  345.  * NEWDIR    directory structure a la Berkeley 4.1c or 4.2
  346.  *
  347.  * NDIR        use <sys/ndir.h> instead of <sys/dir.h>
  348.  * NEWDIR must be defined as well.
  349.  *
  350.  * DIRENT    use Posix directory library.
  351.  * NEWDIR must be defined as well.
  352.  *
  353.  * SYSV        use getcwd instead of getwd, strrchr instead of rindex.
  354.  */
  355. void re_orient();
  356. void disarm_callback();
  357. void activate_callback();
  358. void arm_callback();
  359. void clickB();
  360. void w_print();
  361. void button_print();
  362. void pop_data();
  363. void view();
  364. void quit_b();
  365. void quit_b_pop();
  366. void do_menu();
  367.  
  368. static    char Sccsid[]="@(#)dtree.c    2.3    2/14/84";
  369.  
  370. #ifdef S_IFLNK
  371. static  char Rcsid[] ="$Header: dtree.c,v 1.7.1.2 90/04/18 09:57:30 kk Exp $";
  372. #endif /* S_IFLNK */
  373.  
  374. #include    <stdio.h>
  375. #include    <sys/types.h>
  376. #include    <sys/stat.h>
  377. #include    <time.h>
  378. #include    <string.h>
  379. #include    <stdlib.h>
  380.  
  381. /* Include files for X windows */
  382. #include <X11/Intrinsic.h>
  383. #include <X11/Shell.h>
  384. #include <X11/StringDefs.h>
  385. #include <Xm/Xm.h>
  386. #include <Xm/Label.h>
  387. #include <Xm/PushB.h>
  388. #include <Xm/PushBG.h>
  389. #include <Xm/CascadeB.h>
  390. #include <Xm/RowColumn.h>
  391. #include <Xm/ScrolledW.h>
  392. #include <Xm/Separator.h>
  393. #include <Xm/MainW.h>
  394. #include <Xm/Frame.h>
  395. #include <Xm/Text.h>
  396. #ifdef TREE
  397. #include "Tree.h"
  398. #else
  399. #include "Graph.h"
  400. #include "Arc.h"
  401. #endif
  402.  
  403. /* Original Defs */
  404. #ifdef    STATS
  405. # include    <pwd.h>
  406. # include    <grp.h>
  407. #endif    /* STATS */
  408.  
  409. #ifdef    NEWDIR
  410. # if    DIRENT
  411. #  include    <dirent.h>
  412. #  define    direct    dirent
  413. # else
  414. #  if    NDIR
  415. #   include    <sys/ndir.h>
  416. #  else
  417. #   include    <sys/dir.h>
  418. #  endif
  419. # endif /* DIRENT */
  420. #else
  421. # include    <sys/dir.h>
  422. #endif    /* NEWDIR */
  423.  
  424. /* default column length when -v is given */
  425. #ifdef unos
  426. #define DEFCOLWID    30
  427. #else
  428. #define DEFCOLWID       14
  429. #endif
  430.  
  431. #include    <sys/param.h>    /* for MAXPATHLEN */
  432. #ifndef MAXPATHLEN
  433. # ifdef LPNMAX        /* Xenix from stdio.h */
  434. #  define MAXPATHLEN (LPNMAX - 1)
  435. # else
  436. #  include <limits.h>    /* try somewhere else */
  437. #  define MAXPATHLEN PATH_MAX
  438. # endif
  439. #endif
  440.  
  441. #ifndef MAXNAMLEN    /* defined with NEWDIR routines */
  442. # ifdef LFNMAX        /* Xenix again */
  443. #  define MAXNAMLEN (LFNMAX - 1)
  444. # else
  445. #  define MAXNAMLEN      DEFCOLWID
  446. # endif
  447. #endif
  448.  
  449. #define    DEPTH 10    /* maximum depth that dtree will go */
  450. #define    INITIAL_ELEM    100    /* initial # of elements for list of files */
  451.  
  452. #define    FFIRST    2    /* sort files first */
  453. #define DFIRST    1    /* sort directories first */
  454. #define    FAIL    -1    /* failure return status of sys calls */
  455. #define    GREATER    1    /* return value of strcmp if arg1 > arg2 */
  456. #define    LESSTHAN -1    /* return value of strcmp if arg1 < arg2 */
  457. #define    SAME    0    /* return value of strcmp if arg1 == arg2 */
  458.  
  459. #ifdef    STATS
  460. char *getmode();
  461. char *guid();
  462. char *ggid();
  463. struct passwd *getpwuid();
  464. struct group *getgrgid();
  465. #endif /* STATS */
  466.  
  467. #ifdef    SYSV
  468. #define    rindex    strrchr
  469. #endif /* SYSV */
  470.  
  471. char *getwd();
  472. char *rindex();
  473. /* 
  474. int qsort();
  475. char *malloc();
  476. char *realloc();
  477. */
  478. long time();
  479.  
  480. int compar();            /* comparison routine for qsort */
  481. char *xmalloc();
  482. char *xrealloc();
  483.  
  484. #ifdef    SYSV
  485. #define getwd(buf) getcwd((buf), MAXPATHLEN + 1)
  486. #endif /* SYSV */
  487.  
  488. int    Index = 0;        /* current element of list[]    */
  489. int     CLength = 0;        /* max length of a column       */
  490. int    All = 0;        /* all != 0; list non-directory entries */
  491. int    File_dir = 0;        /* flag for how to sort */
  492. int    Sort = 1;        /* flag to cause sorting of entries */
  493. int    Point = 1;        /* skip point files if set    */
  494. int    Header = 0;        /* print verbose header */
  495. int    Maxes[DEPTH];        /* array keeps track of max length in columns */
  496. int    Level = 0;        /* counter for how deep we are    */
  497. int    Device;            /* device that we are starting tree on */
  498. int    Xdev = 1;        /* set to allow crossing of devices */
  499. int    Varspaces = 1;        /* set to allow compaction of column width */
  500. #ifdef    STATS
  501. int    Gflag = 0;        /* set for group stats instead of owner */
  502. int    Longflg = 0;        /* set for long listing */
  503. int    Compact = 0;        /* set for shortened long listing */
  504. #endif    /* STATS */
  505. #undef Status
  506. struct    stat Status;
  507. #ifdef  S_IFLNK
  508. struct  stat Lstat;   /* stat of link, if there is one */
  509. #endif  /* S_IFLNK */
  510.  
  511. struct entry {
  512.     int next;            /* index to next element in list */
  513.                     /* could be a ptr, but realloc() */
  514.                     /* might screw us then */
  515. #ifdef    STATS
  516.     off_t    e_size;            /* size in blocks */
  517.     unsigned short    e_mode;        /* file mode */
  518.     short    e_uid;            /* uid of owner */
  519.     short    e_gid;            /* gid of owner */
  520. #endif    /* STATS */
  521.     unsigned short dir : 1;        /* entry is a directory */
  522.     unsigned short last : 1;    /* last entry in the dir. */
  523.     unsigned short dev : 1;        /* set if same device as top */
  524.     unsigned short end : 13;    /* index of last subdir entry*/
  525.     char    e_name[MAXNAMLEN + 1];    /* name from directory entry */
  526.     char    path_name[MAXPATHLEN + 1]; /* path name */
  527. } *List, *SaveList;
  528.  
  529. unsigned Size;                /* how big of space we've malloced */
  530.  
  531. char    *Spaces;    /* used for output */
  532. char    Buf1[BUFSIZ];    /* buffers for stdio stuff.  We don't want    */
  533. #ifndef NEWDIR
  534. char    Buf2[BUFSIZ];    /* anyone calling malloc, because then        */
  535.             /* realloc() will have to move the whole list    */
  536. #endif
  537. #define FS(str) (void) fprintf(stderr,str)
  538.  
  539. help()
  540. {
  541.                     fprintf(stderr,
  542. #ifdef    STATS
  543.         "Usage: dtree [-aDfghHlNpstvx] [-c linelength] [directory ... ]\n"
  544. #else    /* STATS */
  545.         "Usage: dtree [-aDfhHNptvx] [-c linelength] [directory ... ]\n"
  546. #endif    /* STATS */
  547.                         );
  548. FS("   options  -a) include non-directory entries in listing\n");
  549. FS("            -D) sort tree with directories at the top\n");
  550. FS("            -f) sort tree with files at the top\n");
  551. FS("            -h) help - prints this message\n");
  552. FS("            -H) display a header at top\n");
  553. FS("            -x) do not cross mounted file systems.\n");
  554. FS("            -p) include files starting with a . (except . and ..)\n");
  555. FS("            -N) do not sort the tree\n");
  556. FS("            -t) Use terminal mode, don't display on an X window\n\n");
  557. FS("            -l level) Search only up to the specified level \n\n");
  558. FS("            Valid only if -t is used. Under default mode, a click on a \n");
  559. FS("            node pops up a menu with mode, user and group ids.\n\n");
  560. FS("            -S) print stats with each listing\n");
  561. FS("                if both g & l flags are given, both owner and\n");
  562. FS("                group will be printed\n");
  563. FS("            -g) same as l, but use group name instead of user name \n");
  564. FS("            -s) use shorter stats. Implies -S if -g isn't given.\n");
  565. FS("            -v) variable length columns \n");
  566. FS("            -c length) set max column length to -length-\n");
  567. FS("  X-Window version 1.1 4/16/90 \n");
  568. }
  569. int newlevel = DEPTH;
  570. Widget boxes[11], options;
  571. Widget file_menu, dir_menu;
  572. struct entry *file_pointer;
  573. main(argc, argv)
  574. char    **argv;
  575. int    argc;
  576. {
  577.     extern int optind;
  578.     extern char *optarg;
  579.     register int i;
  580.     char    top[MAXPATHLEN + 1];    /* array for treetop name */
  581.     char    home[MAXPATHLEN + 1];    /* starting dir for multiple trees */
  582.     char    *ptr;
  583.  
  584.     Widget toplevel;
  585.     Widget sw, tree, q_button, w_button;
  586.     Widget menu_bar, frame, main_w, title;
  587.     Arg    wargs[10];
  588.     int    flagX=1;            /* use X windows as default */
  589.     Widget quit_menu, exit_b, reorient;
  590.     int really_quit, n;
  591.  
  592.     setbuf(stdout, Buf1);
  593.  
  594.     while ((i = getopt (argc, argv,
  595. #ifdef STATS
  596.                 "haDfgHl:NpsSvxtc:"
  597. #else
  598.                 "haDfHl:Npvxtc:"
  599. #endif /* STATS */
  600.                 )) != EOF) {
  601.         switch (i) {
  602.                 case 'a':
  603.                     All = 1;
  604.                     break;
  605.                 case 'c':
  606.                     CLength = atoi(optarg);
  607.                     if (CLength > MAXNAMLEN)
  608.                         CLength = MAXNAMLEN;
  609.                     else if (CLength < 1)
  610.                         CLength = DEFCOLWID;
  611.                     break;
  612.                 case 'l':
  613.                     newlevel = atoi(optarg);
  614.                     if(newlevel > DEPTH) {
  615.                     newlevel = DEPTH;
  616.                     }
  617.                     break;
  618.                 case 'D':
  619.                     File_dir = DFIRST;
  620.                     break;
  621.                 case 'f':
  622.                     File_dir = FFIRST;
  623.                     break;
  624.                 case 'H':
  625.                     Header = 1;
  626.                     break;
  627.                 case 'N':
  628.                     Sort = 0;
  629.                     break;
  630.                 case 'p':
  631.                     Point = 0;
  632.                     break;
  633.                 case 'v':
  634.                     Varspaces = 0;
  635.                     break;
  636.                 case 'x':
  637.                     Xdev = 0;
  638.                     break;
  639.                 case 't':
  640.                     flagX = 0;
  641.                     break;
  642.  
  643.                 case 'h':
  644.                     help();
  645.                     exit(0);
  646. #ifdef    STATS
  647.                 case 'g':
  648.                     Gflag = 1;
  649.                     break;
  650.                 case 'S':
  651.                     Longflg = 1;
  652.                     break;
  653.                 case 's':
  654.                     Compact = 1;
  655.                     break;
  656. #endif    /* STATS */
  657.                 default:
  658.                     help();
  659.                     exit(FAIL);
  660.                 }
  661.     }
  662. #ifdef    STATS
  663.     if (Compact && !Gflag)
  664.         Longflg = 1;
  665. #endif    /* STATS */
  666.     if (CLength == 0)
  667.         CLength = Varspaces ? MAXNAMLEN : DEFCOLWID;
  668.  
  669.     /* Establish where we are (our home base...) */
  670.     if (getwd(home) == 0) {
  671.         fprintf(stderr,
  672.             "dtree: Cannot get initial directory: %s\n", home);
  673.         exit(1);
  674.     }
  675.  
  676.     Spaces = xmalloc(MAXNAMLEN+2);
  677.     for(i = 0; i <= MAXNAMLEN; i++)
  678.         Spaces[i] = ' ';
  679.     Spaces[i] = '\0';
  680.  
  681.     /* Get initial Storage space */
  682.     Size = sizeof(struct entry) * INITIAL_ELEM;
  683.     SaveList = (struct entry *)xmalloc(Size);
  684.  
  685.     /* adjust for no specified directory */
  686.     if (optind == argc )
  687.         if(optind > 1) argv[--optind] = ".";
  688.         else { argv[1] = ".", optind = 1; argc = 2;}
  689.  
  690.     if (Header)
  691.         print_date();
  692.  
  693.     /* walk down the rest of the args, treeing them one at at time */
  694.     for (; optind < argc; optind++) {
  695.         if (chdir(home) == -1) {
  696.             fprintf(stderr, "dtree: Cannot change to initial directory ");
  697.             perror(home);
  698.             exit(1);
  699.         }
  700.         strncpy (top, argv[optind], MAXPATHLEN);
  701.  
  702.         if (chdir(top) == FAIL) {
  703.             fprintf(stderr, "dtree: Cannot change to top directory ");
  704.             perror(top);
  705.             continue;
  706.         } else if (getwd(top) == 0) {
  707.             fprintf(stderr,"dtree: Cannot get current directory: %s\n", top);
  708.             continue;
  709.         }
  710.  
  711.         List = SaveList; Index = 0;
  712.         getwd(List[0].path_name);
  713.         ptr = rindex(top, '/');
  714.  
  715.         if (!ptr || *++ptr == '\0')
  716.             strncpy(List[Index].e_name, top, MAXNAMLEN);
  717.         else
  718.             strncpy(List[Index].e_name, ptr, MAXNAMLEN);
  719.  
  720.         if(stat(top, &Status) == FAIL) {
  721.             fprintf(stderr, "dtree: Cannot stat directory ");
  722.             perror(top);
  723.             continue;
  724.         }
  725.         Device = Status.st_dev;
  726.         List[0].dir = 1;
  727.         List[0].last = 1;
  728.         List[0].next = 1;
  729. #ifdef    STATS
  730.         List[0].e_mode = Status.st_mode;
  731.         List[0].e_uid = Status.st_uid;
  732.         List[0].e_gid = Status.st_gid;
  733.         List[0].e_size = Status.st_size;
  734. #endif    /* STATS */
  735.         Index = 1;
  736.         for (i = 1; i < DEPTH; i++)
  737.             Maxes[i] = 0;
  738.         Maxes[0] = stln(List[0].e_name);
  739.         Level = 1;
  740.  
  741.         /* Don't waste time if there is no display */
  742.         if(flagX == 1)
  743.         toplevel = XtInitialize(argv[0], "Dtree", NULL, 0, &argc, argv);
  744.  
  745.         fprintf(stderr,"Started searchin...Please wait \n");
  746.         /* search the tree */
  747.         List[0].end = t_search(top, &List[0]);
  748.  
  749.         if (Index == 1)                /* empty tree */
  750.             List[0].next = 0;
  751.  
  752.         if (Header) {
  753.         if (All)
  754.             printf("\nDirectory structure and contents of %s\n", top);
  755.         else
  756.             printf("\nDirectory structure of %s\n", top);
  757.         if (Point)
  758.             printf("(excluding entries that begin with '.')\n");
  759.         }
  760.  
  761.         if(flagX == 0) pt_tree();
  762.         else {
  763.  
  764.     /* Create a MainWindow, with a MenuBar and a Frame window
  765.        Put on the Frame, a ScrolledWindow and the Tree window
  766.        The MenuBar has a quit button and the directory Name
  767.     */
  768.             fprintf(stderr,"Opening display now...Please wait\n");
  769.  
  770.             /* main window */
  771.             main_w = XmCreateMainWindow(toplevel,"mainw",NULL,0);
  772.             XtManageChild(main_w);
  773.  
  774.             /* menu bar */
  775.             menu_bar = XmCreateMenuBar(main_w,"menu",NULL,0);
  776.             XtManageChild(menu_bar);
  777.  
  778.             /* frame */
  779.             XtSetArg(wargs[0], XmNshadowType, XmSHADOW_OUT);
  780.             frame = XmCreateFrame(main_w,"frame",wargs,1);
  781.             XtManageChild(frame);
  782.  
  783.             /* quit button */
  784.  
  785.             quit_menu = XmCreatePulldownMenu(menu_bar,
  786.                     "quit_menu",NULL,0);
  787.             XtSetArg(wargs[0], XmNsubMenuId,quit_menu);
  788.             q_button = XmCreateCascadeButton(menu_bar, 
  789.                            "quit",wargs,1);
  790.             XtManageChild(q_button);
  791.  
  792.                w_button =XtCreateManagedWidget("warning",
  793.                 xmLabelWidgetClass,quit_menu, NULL,0);
  794.         w_print(w_button,"Don't exit unless all children are dead\n");
  795.                exit_b = XtCreateManagedWidget("Exit", 
  796.                   xmPushButtonWidgetClass, quit_menu, NULL, 0);
  797.                XtAddCallback(exit_b, XmNarmCallback, 
  798.                 arm_callback, &really_quit);
  799.                XtAddCallback(exit_b, XmNdisarmCallback, 
  800.                 disarm_callback, &really_quit);
  801.                XtAddCallback(exit_b, XmNactivateCallback, 
  802.                 activate_callback, &really_quit);     
  803.  
  804. #ifndef TREE
  805.             /* Reorient button */
  806.             reorient = XmCreateCascadeButton(menu_bar,"ReOrient",
  807.                           NULL,0);
  808.             XtManageChild(reorient);
  809. #endif
  810.             /* Create the options pull-down menu */
  811.             file_pointer = &List[0];
  812.             show_menu(menu_bar,file_pointer);
  813.  
  814.             /* title (path) widget */
  815.  
  816.             title = XtCreateManagedWidget("title", 
  817.                    xmCascadeButtonWidgetClass, menu_bar, NULL,0);
  818.             XtSetArg(wargs[0],XmNmenuHelpWidget, title);
  819.             XtSetValues(menu_bar, wargs, 1);
  820.             w_print(title,top);
  821.  
  822.             XtSetArg(wargs[0], XmNscrollingPolicy, XmAUTOMATIC);
  823.             sw = XtCreateManagedWidget("swindow",
  824.                 xmScrolledWindowWidgetClass, frame, wargs, 1);
  825.             /* Tree widget */
  826. #ifdef TREE
  827.             tree = XtCreateManagedWidget("tree",XstreeWidgetClass,
  828.                     sw, NULL,0);
  829. #else
  830.             n=0;
  831.             XtSetArg(wargs[n],XmNautoLayoutMode, TRUE); n++;
  832.             XtSetArg(wargs[n],XmNsiblingSpacing, 5); n++;
  833.             XtSetArg(wargs[n],XmNarcDrawMode,XmPOSITION_FIXED);n++;
  834.             tree = XmCreateGraph(sw,"tree", wargs,n);
  835.             /* XmAddTabGroup(tree); */
  836.             XtManageChild(tree);
  837.  
  838.             XtAddCallback(reorient, XmNactivateCallback,
  839.                             re_orient, tree);
  840. #endif
  841.             XmMainWindowSetAreas(main_w, menu_bar, NULL,
  842.                NULL, NULL, frame);
  843.             show_dtree(tree);
  844.             clickB(options,file_pointer,NULL);
  845.             XtRealizeWidget(toplevel);
  846.             XtMainLoop();
  847.         }
  848.         
  849.     }
  850.     exit(0) ;
  851. }
  852.  
  853.  
  854. t_search(dir, addrs)
  855. char *dir;
  856. struct    entry *addrs;
  857. {
  858.     int    bsort;            /* index to begin sort */
  859.     int    stmp;            /* save temporary index value */
  860.     struct entry *sstep;        /* saved step in list */
  861.     int    nitems;            /* # of items in this directory */
  862. #ifdef    NEWDIR
  863.     DIR    *dirp;            /* pointer to directory */
  864. #else
  865.     FILE    *dirp;
  866. #endif
  867.     char    sub[MAXNAMLEN+1];    /* used for subdirectory names */
  868.     int    i;
  869. #ifdef    NEWDIR
  870.     struct direct *dp;
  871. #else
  872.     struct direct dirent;
  873.     struct direct *dp = &dirent;
  874. #endif    /* NEWDIR */
  875.     int    n_subs = 0;
  876.     int    tmp = 0;
  877.  
  878. #ifdef    NEWDIR
  879.     dirp = opendir(".");
  880. #else
  881.     dirp = fopen(".", "r");
  882. #endif    /* NEWDIR */
  883.     if (dirp == NULL) {
  884.         fprintf(stderr, "dtree: Cannot open directory ");
  885.         perror(dir);
  886.         return(0);
  887.     }
  888. #ifndef    NEWDIR
  889.     setbuf(dirp, Buf2);
  890. #endif    /* NEWDIR */
  891.  
  892.     bsort = Index;
  893.     sstep = &List[bsort]; /* initialize sstep for for loop later on */
  894.     nitems = Index;
  895.     /* get the entries of the directory that we are interested in */
  896. #ifndef    NEWDIR
  897.     while (fread((char *)(dp), sizeof(struct direct), 1, dirp) == 1) {
  898. #else
  899.     while ((dp = readdir(dirp)) != NULL) {
  900. #endif    /* NEWDIR */
  901.  
  902.         if (dp->d_ino
  903. #ifdef unos
  904.             == -1
  905. #else
  906.             == 0
  907. #endif /* unos */
  908.             || (strcmp(dp->d_name, ".") == SAME)
  909.             || (strcmp(dp->d_name, "..") == SAME)
  910.             || (Point && dp->d_name[0] == '.'))
  911.                 continue;
  912.  
  913.         strncpy(sub, dp->d_name, MAXNAMLEN);
  914. #ifdef S_IFLNK
  915.         if (lstat(sub,&Lstat) == FAIL) {
  916.             fprintf(stderr, "dtree: In directory %s, cannot lstat entry ", dir);
  917.             perror(sub);
  918.             continue;
  919.                 }
  920. #endif /* S_IFLNK */
  921.         if (stat(sub, &Status) == FAIL) {
  922.             fprintf(stderr, "dtree: In directory %s, cannot stat entry ", dir);
  923.             perror(sub);
  924.             continue;
  925.         }
  926. #ifdef S_IFLNK
  927.         if (((Lstat.st_mode & S_IFMT) == S_IFLNK)  &&
  928.             ((Status.st_mode & S_IFMT) == S_IFDIR)) 
  929.                 List[Index].dir = 0;    
  930.         else if ((((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
  931.             ((Status.st_mode & S_IFMT) != S_IFDIR)) && (All)) 
  932.                         List[Index].dir = 0;
  933. #endif /* S_IFLNK */
  934.         else if ((Status.st_mode & S_IFMT) == S_IFDIR)
  935.             List[Index].dir = 1;
  936.         else if (All)
  937.             List[Index].dir = 0;
  938.         else
  939.             continue;
  940.         strncpy(List[Index].e_name, dp->d_name, MAXNAMLEN);
  941.         getwd(List[Index].path_name);
  942.         List[Index].last = 0;
  943.         List[Index].end = 0;
  944. #ifdef S_IFLNK
  945.         if ((Lstat.st_mode & S_IFMT) == S_IFLNK) {
  946.              List[Index].dev = (Device == Lstat.st_dev);
  947.              List[Index].e_mode = Lstat.st_mode;
  948.              List[Index].e_uid = Lstat.st_uid;
  949.              List[Index].e_gid = Lstat.st_gid;
  950.              List[Index].e_size = Lstat.st_size;
  951.                 }
  952.                 else {
  953. #endif /* S_IFLNK */
  954.              List[Index].dev = (Device == Status.st_dev);
  955. #ifdef STATS
  956.              List[Index].e_mode = Status.st_mode;
  957.              List[Index].e_uid = Status.st_uid;
  958.              List[Index].e_gid = Status.st_gid;
  959.              List[Index].e_size = Status.st_size;
  960. #endif /* STATS */
  961. #ifdef S_IFLNK
  962.                 }
  963. #endif /* S_IFLNK */
  964.         if (stln(List[Index].e_name) > Maxes[Level])
  965.             Maxes[Level] = stln(List[Index].e_name);
  966.         ++Index;
  967.         if (Index*sizeof(struct entry) >= Size) {
  968.             Size += 20*sizeof(struct entry);
  969.             List = (struct entry *)xrealloc((char *)List, Size);
  970.         }
  971.     }
  972. #ifdef    NEWDIR
  973.     closedir(dirp);
  974. #else
  975.     fclose(dirp);
  976. #endif    /* NEWDIR */
  977.  
  978.     nitems = Index - nitems;    /* nitems now contains the # of */
  979.                     /* items in this dir, rather than */
  980.                     /* # total items before this dir */
  981.  
  982.     if (Sort)
  983.         qsort(&List[bsort], nitems, sizeof(struct entry), compar);
  984.  
  985.     List[Index-1].last = 1;    /* mark last item for this dir */
  986.     n_subs = nitems;
  987.     stmp = Index;
  988.  
  989.     /* now walk through, and recurse on directory entries */
  990.     /* sstep was initialized above */
  991.  
  992.     for (i = 0; i < nitems; sstep = &List[stmp - nitems+(++i)]) {
  993.         if (sstep->dir && (Level < newlevel) && (Xdev || sstep->dev)) {
  994.             sstep->next = Index;
  995.             strncpy(sub, sstep->e_name, MAXNAMLEN);
  996.             tmp = n_subs;
  997.             Level++;
  998.             if (chdir(sub) == FAIL) {
  999.                 fprintf(stderr,
  1000.                     "dtree: Cannot change to directory %s/", dir);
  1001.                 perror(sub);
  1002.             } else {
  1003.                 n_subs += t_search(sub, sstep);
  1004.                 if (chdir("..") == FAIL) {
  1005.                     fprintf(stderr,
  1006.                         "dtree: %s/%s lacks '..' entry\n",dir, sub);
  1007.                     exit(1);
  1008.                 }
  1009.             }
  1010.             --Level;
  1011.             if (n_subs - tmp <= 0)
  1012.                 sstep->next = 0;
  1013.             else
  1014.                 --n_subs;
  1015.         }
  1016.         else
  1017.             sstep->next = 0;
  1018.     }
  1019.     addrs->end = (unsigned)n_subs;
  1020.     return(n_subs);
  1021. }
  1022.  
  1023. /*
  1024.  *    comparison routine for qsort
  1025.  */
  1026.  
  1027. compar(a, b)
  1028. struct entry *a, *b;
  1029. {
  1030.     if (!File_dir)        /* straight alphabetical */
  1031.         return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
  1032.  
  1033.     /* sort alphabetically if both dirs or both not dirs */
  1034.  
  1035.     if ((a->dir && b->dir) || (!a->dir && !b->dir))
  1036.         return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
  1037.  
  1038.     if (File_dir == FFIRST) {    /* sort by files first */
  1039.         if (a->dir)
  1040.             return(GREATER);
  1041.         else
  1042.             return(LESSTHAN);
  1043.     }
  1044.  
  1045.     if (a->dir)            /* sort by dir first */
  1046.         return(LESSTHAN);
  1047.     else
  1048.         return(GREATER);
  1049. }
  1050.  
  1051.  
  1052. pt_tree()
  1053. {
  1054.     register int    i,j;
  1055.     struct entry *l;
  1056.     struct entry *hdr[DEPTH];
  1057.     int posit[DEPTH];        /* array of positions to print dirs */
  1058.     int con[DEPTH];            /* flags for connecting up tree */
  1059.     char    flag = 0;        /* flag to leave blank line after dir */
  1060.     struct    entry *stack[DEPTH];    /* save positions for changing levels */
  1061.     int    top = 0;        /* index to top of stack */
  1062.     int    count = 1;        /* count of line of output */
  1063.  
  1064.     Level = 0;            /* initialize Level */
  1065.  
  1066.     /* this loop appends each entry with dashes or spaces, for */
  1067.     /* directories or files respectively */
  1068.  
  1069.     for (i = 0; i < Index; i++) {
  1070.         for (j = 0; j < MAXNAMLEN; j++) {
  1071.             if (!List[i].e_name[j])
  1072.                 break;
  1073.         }
  1074.         if (List[i].dir) {
  1075.             for (; j < MAXNAMLEN; j++)
  1076.                 List[i].e_name[j] = '-';
  1077.         } else {
  1078.             for (; j < MAXNAMLEN; j++)
  1079.                 List[i].e_name[j] = ' ';
  1080.         }
  1081.     }
  1082.  
  1083.     /* adjust the Maxes array according to the flags */
  1084.  
  1085.     for (i = 0; i < DEPTH; i++) {
  1086.         if (Varspaces) {
  1087.             if (Maxes[i] > CLength )
  1088.                 Maxes[i] = CLength;
  1089.         } else
  1090.             Maxes[i] = CLength;
  1091.     }
  1092.  
  1093.     /* clear the connective and position flags */
  1094.  
  1095.     for (i = 0; i < DEPTH; i++)
  1096.         con[i] = posit[i] = 0;
  1097.  
  1098.     /* this is the main loop to print the tree structure. */
  1099.     l = &List[0];
  1100.     j = 0;
  1101.     for (;;) {
  1102.         /* directory entry, save it for later printing */
  1103.         if (l->dir != 0 && l->next != 0) {
  1104.             hdr[Level] = l;
  1105.             posit[Level] = count + (l->end + 1)/2 - 1;
  1106.             flag = 1;
  1107.             stack[top++] = l;
  1108.             l = &List[l->next];
  1109.             ++Level;
  1110.             continue;
  1111.         }
  1112.  
  1113. #ifdef    STATS
  1114.     do_it_again:
  1115. #endif    /* STATS */
  1116.         /* print columns up to our entry */
  1117.         for (j = 0; j < (flag ? Level-1 : Level); j++) {
  1118.             if (!flag && posit[j] && posit[j] <= count) {
  1119.                 /* time to print it */
  1120.                 if (hdr[j]->e_name[CLength-1] != '-')
  1121.                     hdr[j]->e_name[CLength-1] = '*';
  1122.                 printf("|-%.*s",Maxes[j],hdr[j]->e_name);
  1123.                 posit[j] = 0;
  1124.                 if (hdr[j]->last != 0)
  1125.                     con[j] = 0;
  1126.                 else
  1127.                     con[j] = 1;
  1128. #ifdef    STATS
  1129.                 if (Gflag || Longflg) {
  1130.                     if ((i = j+1) <= Level)
  1131.                     printf("| %.*s", Maxes[i], Spaces);
  1132.                     for (i++; i <= Level; i++) {
  1133.                     printf("%c %.*s",
  1134.                         (con[i] ? '|' : ' '),
  1135.                         Maxes[i], Spaces);
  1136.                     }
  1137.                     if (!Compact) {
  1138.                     printf("%s ", getmode(hdr[j]->e_mode));
  1139.                     if (Longflg)
  1140.                        printf("%8.8s ",guid(hdr[j]->e_uid));
  1141.                     if (Gflag)
  1142.                        printf("%8.8s ",ggid(hdr[j]->e_gid));
  1143.                     printf("%7ld\n",
  1144.                         (hdr[j]->e_size+511L)/512L);
  1145.                     } else {
  1146.                     printf(" %04o ",hdr[j]->e_mode & 07777);
  1147.                     if (Longflg)
  1148.                         printf("%5u ", hdr[j]->e_uid);
  1149.                     if (Gflag)
  1150.                         printf("%5u ", hdr[j]->e_gid);
  1151.                     printf("%7ld\n",
  1152.                         (hdr[j]->e_size+511L)/512L);
  1153.                     }
  1154.                     goto do_it_again;
  1155.                 }
  1156. #endif    /* STATS */
  1157.             } else
  1158.                 printf("%c %.*s", (con[j] ? '|' : ' '),
  1159.                     Maxes[j], Spaces);
  1160.         }
  1161.         if (flag) {    /* start of directory, so leave a blank line */
  1162.             printf(con[j] ? "|\n" : "\n");
  1163.             flag = 0;
  1164.             continue;
  1165.         } else {
  1166.                 /* normal file name, print it out */
  1167.             if (l->e_name[CLength-1] != '-' &&
  1168.                 l->e_name[CLength-1] != ' ')
  1169.                 l->e_name[CLength-1] = '*';
  1170.             printf("|-%.*s",Maxes[Level],l->e_name);
  1171.             if (l->last) {
  1172.                 con[j] = 0;
  1173.             } else {
  1174.                 con[j] = 1;
  1175.             }
  1176. #ifdef    STATS
  1177.             if (Gflag || Longflg) {
  1178.                 if (Compact) {
  1179.                     printf(" %04o ", l->e_mode & 07777);
  1180.                     if (Longflg)
  1181.                         printf("%5u ", l->e_uid);
  1182.                     if (Gflag)
  1183.                         printf("%5u ", l->e_gid);
  1184.                     printf("%7ld",
  1185.                         (l->e_size+511L)/512L);
  1186.                 } else {
  1187.                     printf("%s ", getmode(l->e_mode));
  1188.                     if (Longflg)
  1189.                         printf("%8.8s ",guid(l->e_uid));
  1190.                     if (Gflag)
  1191.                         printf("%8.8s ",ggid(l->e_gid));
  1192.                     printf("%7ld",
  1193.                         (l->e_size+511L)/512L);
  1194.                 }
  1195.             }
  1196. #endif    /* STATS */
  1197.         }
  1198.         printf("\n");
  1199.  
  1200.         if (l->last) {
  1201.             /* walk back up */
  1202.             while (l->last) {
  1203.                 --Level;
  1204.                 if (--top <= 0)
  1205.                     return;
  1206.                 l = stack[top];
  1207.             }
  1208.         }
  1209.         l = &l[1];
  1210.         ++count;
  1211.     }
  1212. }
  1213.  
  1214. #ifdef    STATS
  1215.  
  1216. char *
  1217. guid(uid)
  1218. short uid;
  1219. {
  1220.     static char tb[10];
  1221.     struct passwd *pswd;
  1222.  
  1223.     pswd = getpwuid(uid);
  1224.     if (pswd == NULL)
  1225.         sprintf(tb,"%u", uid);
  1226.     else
  1227.         sprintf(tb, "%8s", pswd->pw_name);
  1228.     return(tb);
  1229. }
  1230.  
  1231. char *
  1232. ggid(gid)
  1233. short gid;
  1234. {
  1235.     static char tb[10];
  1236.     struct group *grp;
  1237.  
  1238.     grp = getgrgid(gid);
  1239.     if (grp == NULL)
  1240.         sprintf(tb,"%u", gid);
  1241.     else
  1242.         sprintf(tb, "%8s", grp->gr_name);
  1243.     return(tb);
  1244. }
  1245.  
  1246. /* take the mode and make it into a nice character string */
  1247.  
  1248. char    *
  1249. getmode(p_mode)
  1250. unsigned short p_mode;
  1251. {
  1252.     static char a_mode[16];
  1253.     register int    i = 0, j = 0;
  1254.  
  1255.     a_mode[j++] = ' ';
  1256.  
  1257.     switch (p_mode & S_IFMT) {
  1258. #ifdef S_IFLNK
  1259.     case S_IFLNK:
  1260.         a_mode[j++] = 'l';
  1261.         break;
  1262. #endif /* S_IFLNK */
  1263.     case S_IFDIR:
  1264.         a_mode[j++] = 'd';
  1265.         break;
  1266. #ifdef    S_IFMPC        /* defined in stat.h if you have MPX files */
  1267.     case S_IFMPC:
  1268.         a_mode[j-1] = 'm';
  1269.         /* FALL THROUGH */
  1270. #endif    /* S_IFMPC */
  1271.     case S_IFCHR:
  1272.         a_mode[j++] = 'c';
  1273.         break;
  1274. #ifdef    S_IFMPB        /* defined in stat.h if you have MPX files */
  1275.     case S_IFMPB:
  1276.         a_mode[j-1] = 'm';
  1277.         /* FALL THROUGH */
  1278. #endif    /* S_IFMPB */
  1279.     case S_IFBLK:
  1280.         a_mode[j++] = 'b';
  1281.         break;
  1282.     case S_IFREG:
  1283.     default:
  1284.         a_mode[j++] = (p_mode & S_ISVTX) ? 't' : ' ';
  1285.         break;
  1286.     }
  1287.     a_mode[j++] = ' ';
  1288.     for( i = 0;i<3;i++ ) {
  1289.         a_mode[j++] = (p_mode<<(3*i) & S_IREAD) ? 'r' : '-';
  1290.         a_mode[j++] = (p_mode<<(3*i) & S_IWRITE) ? 'w' : '-';
  1291.         a_mode[j++] = (i<2 && (p_mode<<i & S_ISUID)) ? 's' :
  1292.                   ((p_mode<<(3*i) & S_IEXEC ) ? 'x' : '-');
  1293.         a_mode[j++] = ' ';
  1294.     }
  1295.     a_mode[j] = '\0';
  1296.     return(a_mode);
  1297. }
  1298. #endif
  1299.  
  1300. /* like strlen, but returns length up to MAXNAMLEN-1 */
  1301. stln(st)
  1302. register char *st;
  1303. {
  1304.     register int t;
  1305.  
  1306.     for (t=0; t<MAXNAMLEN-1; ++t)
  1307.         if (!st[t])
  1308.             return (++t);
  1309.     return (++t);
  1310. }
  1311.  
  1312. print_date()
  1313. {
  1314.     long now;
  1315.  
  1316.     time(&now);
  1317.     printf ("%s", ctime(&now));
  1318. }
  1319.  
  1320. void
  1321. memory_out()
  1322. {
  1323.     fprintf(stderr, "dtree: Virtual memory exhausted\n");
  1324.     exit(1);
  1325. }
  1326.  
  1327. /* Allocate `size' bytes of memory dynamically, with error checking.  */
  1328.  
  1329. char *
  1330. xmalloc (size)
  1331. unsigned size;
  1332. {
  1333.     char *ptr;
  1334.  
  1335.     ptr = malloc (size);
  1336.     if (ptr == 0 && size != 0)
  1337.         memory_out ();
  1338.     return ptr;
  1339. }
  1340.  
  1341. /* Change the size of an allocated block of memory `ptr' to `size' bytes,
  1342.    with error checking.
  1343.    If `ptr' is NULL, run xmalloc.
  1344.    If `size' is 0, run free and return NULL.  */
  1345.  
  1346. char *
  1347. xrealloc (ptr, size)
  1348. char *ptr;
  1349. unsigned size;
  1350. {
  1351.     if (ptr == 0)
  1352.         return xmalloc (size);
  1353.     if (size == 0) {
  1354.         free (ptr);
  1355.         return 0;
  1356.     }
  1357.     ptr = realloc (ptr, size);
  1358.     if (ptr == 0 && size != 0)
  1359.         memory_out ();
  1360.     return ptr;
  1361. }
  1362. /*-------------------------New functions for X windows -----------------*/
  1363.  
  1364. /* Main program to display the tree in an X window */
  1365.  
  1366. show_dtree(parent)
  1367.     Widget parent;
  1368.  
  1369. {
  1370.     Arg wargs[4];
  1371.     struct entry *stack[DEPTH], *branch;
  1372.     int n, top=0, *dir_index;
  1373.     int dir_node=0, dir_count=0, i;
  1374.     Widget parent_node=NULL, *Dir, arc;
  1375.     XmString label_s = NULL;    
  1376.  
  1377.     /* Find the number of directories */
  1378.     for(i=0; i < Index; i++)
  1379.         if(List[i].dir == 1) dir_count++;
  1380.  
  1381.     if((Dir = (Widget *) malloc( dir_count * sizeof(Widget))) == NULL){
  1382.         fprintf(stderr,"malloc failure\n");
  1383.             exit(1);
  1384.     }
  1385.     if((dir_index = (int *) malloc(dir_count * sizeof(int))) == NULL) {
  1386.         fprintf(stderr,"malloc failure\n");
  1387.         exit(1) ;
  1388.     }
  1389.  
  1390.     branch = &List[0];
  1391.  
  1392.     if(dir_count == 1 && branch->next == 0) {
  1393.         if(All == 0) {
  1394.         fprintf(stderr,"No subdirectories under directory %s\n",
  1395.              branch->e_name);
  1396.         fprintf(stderr,"You may want to try the -ap option\n");
  1397.         }
  1398.         else fprintf(stderr,"No files under directory %s\n", 
  1399.              branch->e_name);
  1400.         exit(0);
  1401.     }
  1402.  
  1403.     /* Distinguish between directories and files */
  1404.  
  1405.     for(;;)  {
  1406.         if(branch->dir != 0 && branch->next != 0) {
  1407.             dir_index[top] = dir_node;
  1408.             stack[top++] = branch;
  1409.             n=0;
  1410. #ifdef TREE
  1411.             XtSetArg(wargs[n], XtNsuperNode,parent_node); n++;
  1412. #endif
  1413.             label_s = XmStringCreateLtoR(branch->e_name,
  1414.                                   XmSTRING_DEFAULT_CHARSET);
  1415.             XtSetArg(wargs[n], XmNlabelString,label_s); n++;
  1416.             Dir[dir_node] = XmCreatePushButton(parent,"dir",
  1417.                                     wargs,n);
  1418.             XtManageChild(Dir[dir_node]);
  1419.             XtAddCallback(Dir[dir_node],XmNactivateCallback,
  1420.                    clickB, branch);
  1421.  
  1422. #ifndef TREE
  1423.             /* create the arc */
  1424.             if(parent_node) {
  1425.             n=0;
  1426.             XtSetArg(wargs[n], XmNarcDirection, XmDIRECTED); n++;
  1427.             XtSetArg(wargs[n], XmNto, Dir[dir_node]); n++;
  1428.             XtSetArg(wargs[n], XmNfrom, parent_node); n++;
  1429.             arc = XmCreateArc(parent, branch->e_name,wargs,n);
  1430.             XtManageChild(arc);
  1431.             }
  1432. #endif
  1433.  
  1434.             branch = &List[branch->next];
  1435.             parent_node = Dir[dir_node++];
  1436.             continue;
  1437.         }
  1438.         create_file_node(parent,branch,parent_node);
  1439.         if(branch->last) {
  1440.             while(branch->last) {
  1441.                 if(--top <= 0 ) {
  1442.                     free(Dir);
  1443.                     free(dir_index);
  1444.                     return;
  1445.                     }
  1446.                 branch = stack[top];
  1447.                 parent_node = Dir[dir_index[top-1]];
  1448.                 }
  1449.             }
  1450.         branch = &branch[1];
  1451.     }
  1452. }
  1453. /* Function that creates a widget for a node. Three types are available,
  1454.    dir, for directories , file, for files, and sym_link for
  1455.    symbolic links
  1456. */
  1457. create_file_node(pparent,bbranch,nnode)
  1458.     Widget pparent, nnode;
  1459.     struct entry *bbranch;
  1460. {
  1461.     Widget w, arc;
  1462.     Arg wargs[4];
  1463.     int n;
  1464.     char *win_type;
  1465.     XmString label_s = NULL;    
  1466.     int Gflag=1;        /* this is a gadget */
  1467.  
  1468.  
  1469.     n=0;
  1470.     label_s = XmStringCreateLtoR(bbranch->e_name,
  1471.                           XmSTRING_DEFAULT_CHARSET);
  1472.     XtSetArg(wargs[n], XmNlabelString,label_s); n++;
  1473.  
  1474.     /* Check the type of the node */
  1475.     if(bbranch->dir == 1) { 
  1476.         win_type = "dir";
  1477.         Gflag = 0;
  1478.     }
  1479. #ifdef STATS
  1480.     else if(strncmp(" l",getmode(bbranch->e_mode),2) == 0)
  1481.             {win_type = "sym_link"; Gflag = 0;}
  1482. #endif /* STATS */
  1483.     else win_type = "file";
  1484. #ifdef TREE
  1485.         XtSetArg(wargs[n], XtNsuperNode, nnode); n++; 
  1486.     w = XmCreatePushButton(pparent, win_type, wargs, n);
  1487. #else
  1488.     if(Gflag == 0)
  1489.     w = XmCreatePushButton(pparent, win_type, wargs, n);
  1490.     else
  1491.     w = XmCreatePushButtonGadget(pparent, win_type, wargs, n);
  1492. #endif
  1493.     XtManageChild(w);
  1494.     XtAddCallback(w,XmNactivateCallback,clickB,bbranch);
  1495.  
  1496. #ifndef TREE
  1497.     /* create the arcs */
  1498.     n=0;
  1499.     XtSetArg(wargs[n], XmNarcDirection, XmDIRECTED); n++;
  1500.     XtSetArg(wargs[n], XmNto, w); n++;
  1501.     XtSetArg(wargs[n], XmNfrom, nnode); n++;
  1502.     arc = XmCreateArc(pparent, bbranch->e_name,wargs,n);
  1503.     XtManageChild(arc);
  1504. #endif
  1505. }
  1506. /* Function that creates the pull-down menu when someone clicks on the 
  1507.   active node of the tree.  
  1508. */
  1509.  
  1510. show_menu(pparent, bbranch)
  1511.     Widget pparent;
  1512.     struct entry *bbranch;
  1513. {
  1514.     Widget menu ;
  1515.     Widget submenu_dir, submenu_file;
  1516.     int i;
  1517.     char *mode_name;
  1518.     Arg  wargs[4];
  1519.  
  1520.     menu = XmCreatePulldownMenu(pparent,"menu",NULL, 0);
  1521.  
  1522.     XtSetArg(wargs[0], XmNsubMenuId,menu);
  1523.     options = XtCreateManagedWidget("options",xmCascadeButtonWidgetClass,
  1524.            pparent, wargs, 1);
  1525.     w_print(options, bbranch->e_name);
  1526.     /*
  1527.     boxes[0] = XtCreateManagedWidget("title",xmLabelWidgetClass, 
  1528.            menu, NULL,0);
  1529.     XtCreateManagedWidget("separator",xmSeparatorWidgetClass, 
  1530.            menu, NULL,0);
  1531.     */
  1532. #ifdef STATS
  1533.     for(i = 1; i < 4 ; i++)
  1534.     boxes[i] =  XtCreateManagedWidget("id",xmLabelWidgetClass,
  1535.            menu, NULL,0);
  1536.     button_print(bbranch); /* print the labels on the menu */
  1537.  
  1538.     XtCreateManagedWidget("separator2",xmSeparatorWidgetClass, 
  1539.            menu, NULL,0);
  1540.     /* Create sub-menus */
  1541.  
  1542. #endif /*STATS */
  1543.  
  1544.     file_menu = XtCreateManagedWidget("File Options",
  1545.         xmCascadeButtonWidgetClass, menu, NULL,0);
  1546.     dir_menu  = XtCreateManagedWidget("Directory Options",
  1547.         xmCascadeButtonWidgetClass, menu, NULL,0);
  1548.  
  1549.     /* Create cascading sub-menus */
  1550.  
  1551.     /* If it is a file */
  1552.     submenu_file = XmCreatePulldownMenu(menu, "filesubmenu", NULL, 0);
  1553.     XtSetArg(wargs[0], XmNsubMenuId, submenu_file);
  1554.     XtSetValues(file_menu, wargs, 1);
  1555.  
  1556.     boxes[4] = XtCreateManagedWidget("view",xmPushButtonWidgetClass,
  1557.                            submenu_file, NULL,0);
  1558.         XtAddCallback(boxes[4], XmNactivateCallback,view, NULL);
  1559.         boxes[5] = XtCreateManagedWidget("topview",
  1560.             xmPushButtonWidgetClass, submenu_file, NULL,0);
  1561.         XtAddCallback(boxes[5], XmNactivateCallback,view, NULL);
  1562.         boxes[6] = XtCreateManagedWidget("edit",
  1563.             xmPushButtonWidgetClass, submenu_file, NULL,0);
  1564.         XtAddCallback(boxes[6], XmNactivateCallback,do_menu, NULL);
  1565.         boxes[7] = XtCreateManagedWidget("print",
  1566.             xmPushButtonWidgetClass, submenu_file, NULL,0);
  1567.         XtAddCallback(boxes[7], XmNactivateCallback,do_menu, NULL);
  1568.  
  1569.     /* if it a directory */
  1570.     submenu_dir = XmCreatePulldownMenu(menu, "dirsubmenu", NULL, 0);
  1571.     XtSetArg(wargs[0], XmNsubMenuId, submenu_dir);
  1572.     XtSetValues(dir_menu, wargs, 1);
  1573.         boxes[8] = XtCreateManagedWidget("show subtree",
  1574.             xmPushButtonWidgetClass, submenu_dir, NULL,0);
  1575.         XtAddCallback(boxes[8], XmNactivateCallback,do_menu, NULL);
  1576.         boxes[9] = XtCreateManagedWidget("list files",
  1577.             xmPushButtonWidgetClass, submenu_dir, NULL,0);
  1578.         XtAddCallback(boxes[9], XmNactivateCallback,do_menu, NULL);
  1579.         boxes[10] = XtCreateManagedWidget("list ../",
  1580.             xmPushButtonWidgetClass, submenu_dir, NULL,0);
  1581.         XtAddCallback(boxes[10], XmNactivateCallback,do_menu, NULL);
  1582. }
  1583. /* Not used here, but may be useful in the future !!! */
  1584. /* Copied from D. Young's book */
  1585. /*
  1586. void post_menu_handler(w, menu, event)
  1587.     Widget w, menu;
  1588.     XEvent *event;
  1589. {
  1590.     Arg wargs[10];
  1591.     int button;
  1592.  
  1593.      XtSetArg(wargs[0], XmNwhichButton, &button); 
  1594.     XtGetValues(menu, wargs, 1);
  1595.         if(event->xbutton.button == button) {
  1596.         XmMenuPosition(menu, event);
  1597.         XtManageChild(menu);
  1598.         }
  1599. }
  1600. */
  1601. /* Quick and dirty way to view a file in a pop-up window 
  1602.    Speed may improve, if one reads and displays page by page
  1603.    No check to see if the file is binary
  1604. */
  1605. void view(w, call_mydata, call_data)
  1606.     Widget w;
  1607.     caddr_t call_data, call_mydata;
  1608.  
  1609. {
  1610.     struct entry *branch;
  1611.     char *filename[MAXPATHLEN+1];  
  1612.         struct stat statbuf;         /* Information on a file. */
  1613.         int file_length;             /* Length of file.        */
  1614.         unsigned char * file_string; /* Contents of file.      */
  1615.     FILE *fp = NULL;
  1616.     Widget text, toplevel2, sw2, button, frame, main_w, menu_bar;
  1617.     Widget title;
  1618.     XmString name_string = NULL;
  1619.     char *button_name = NULL;
  1620.     int topflag=0;
  1621.     Arg    wargs[10];
  1622.     int n=0;
  1623.  
  1624.     branch = file_pointer;
  1625.     /* find which button called us */
  1626.     XtSetArg(wargs[0], XmNlabelString, &name_string);
  1627.     XtGetValues(w,wargs,1);
  1628.     XmStringGetLtoR(name_string,XmSTRING_DEFAULT_CHARSET,&button_name);
  1629.     if(strcmp("topview",button_name) == 0) topflag = 1;
  1630.  
  1631.     /* find first the correct path */
  1632.  
  1633.     strncpy(filename,branch->path_name,MAXPATHLEN);
  1634.     strcat(filename,"/");
  1635.     strcat(filename,branch->e_name);
  1636.     
  1637.  
  1638.     if ((fp = fopen(filename, "r")) == NULL) {
  1639.         fprintf(stderr,"Can't open file name %s\n",filename);
  1640.         return;
  1641.     }
  1642.      if (stat(filename, &statbuf) == 0)
  1643.            file_length = statbuf.st_size;
  1644.          else
  1645.               file_length = 1000000; /* arbitrary file length */
  1646.  
  1647.      /* read the file string */
  1648.  
  1649.      if(topflag == 1 && file_length >= 2000 ) file_length = 2000;
  1650.  
  1651.      file_string = (unsigned char *) XtMalloc((unsigned)file_length);
  1652.          fread(file_string, sizeof(char), file_length, fp);
  1653.  
  1654.      if (fclose(fp) != NULL) fprintf(stderr, "Warning: unable to close file.\n");
  1655.  
  1656.     /* Create another pop-pup top-shell with a MainWindow */
  1657.  
  1658.     toplevel2 = XtCreateApplicationShell("Dtreef",topLevelShellWidgetClass,
  1659.              NULL,0);
  1660.  
  1661.     main_w = XmCreateMainWindow(toplevel2,"mainw",NULL,0);
  1662.     XtManageChild(main_w);
  1663.     menu_bar = XmCreateMenuBar(main_w,"menu",NULL,0);
  1664.     XtManageChild(menu_bar);
  1665.     XtSetArg(wargs[0], XmNshadowType, XmSHADOW_OUT);
  1666.     frame = XmCreateFrame(main_w,"frame",wargs,1);
  1667.     XtManageChild(frame);
  1668.     XtSetArg(wargs[0], XmNscrollingPolicy, XmAUTOMATIC);
  1669.     sw2 = XtCreateManagedWidget("swindowf",
  1670.         xmScrolledWindowWidgetClass,frame, wargs,1);
  1671.     XmMainWindowSetAreas(main_w, menu_bar, NULL, NULL, NULL, frame);
  1672.     button = XmCreateCascadeButton(menu_bar, "quit",NULL,0);
  1673.     XtManageChild(button);
  1674.     XtAddCallback(button,XmNactivateCallback,quit_b_pop,toplevel2);
  1675.  
  1676.     title = XtCreateManagedWidget("title", 
  1677.                xmCascadeButtonWidgetClass, menu_bar, NULL,0);
  1678.     w_print(title, filename);
  1679.  
  1680.  
  1681.     /* Create Text widget */
  1682.     n=0;
  1683.         XtSetArg (wargs[n], XmNeditable, FALSE); n++; 
  1684.  
  1685.     text = XmCreateText(sw2, "text", wargs, n);
  1686.  
  1687.     /* added the file string to the text widget */
  1688.  
  1689.        XmTextSetString(text, file_string);
  1690.         if(file_string != NULL) XtFree(file_string);
  1691.         if(name_string != NULL) XtFree(name_string);
  1692.  
  1693.     /* Poput the text file */
  1694.  
  1695.     XtPopup(toplevel2,XtGrabNone); 
  1696.     XtManageChild(text); 
  1697. }
  1698.  
  1699. /* CallBack function of the quit button on a pop-up window */
  1700.  
  1701. void quit_b_pop(w, topshell, call_data)
  1702.     Widget w;
  1703.     Widget topshell;
  1704.     caddr_t  call_data;
  1705. {
  1706.      XtPopdown(topshell);
  1707. }
  1708.  
  1709. /* function that forks a command from the menu */
  1710. /* Needs work!!!!!
  1711. */
  1712. void do_menu(w,call_mydata,call_data)
  1713.     Widget w;
  1714.     caddr_t call_data, call_mydata;
  1715.  
  1716. {
  1717.     struct entry *branch;
  1718.     char *filename[MAXPATHLEN+1];  
  1719.     char *topdir[MAXPATHLEN+1];
  1720.     XmString name_string = NULL;
  1721.     char *button_name = NULL;
  1722.     char *lpdest=NULL, *editor = NULL;
  1723.     char  *EDITOR="EDITOR\0";
  1724.     int pid, pathl,namel;
  1725.     Arg  wargs[3];
  1726.  
  1727.     
  1728.     
  1729.     /* find which button called us */
  1730.  
  1731.     branch = file_pointer;
  1732.     XtSetArg(wargs[0], XmNlabelString, &name_string);
  1733.     XtGetValues(w,wargs,1);
  1734.     XmStringGetLtoR(name_string,XmSTRING_DEFAULT_CHARSET,&button_name);
  1735.  
  1736.  
  1737.     /* find first the correct path - append the file name 
  1738.         except for the "root" directory */
  1739.  
  1740.     strncpy(filename,branch->path_name,MAXPATHLEN);
  1741.     if(branch->next != 1) {
  1742.         strcat(filename,"/");
  1743.         strcat(filename,branch->e_name);
  1744.     }
  1745.     
  1746.     /* fork a new process */
  1747.     pid = fork();
  1748.  
  1749.     if(pid > 0) {
  1750.         /* wait((int *)0); */
  1751.         return;
  1752.     }
  1753.  
  1754.     if(pid == 0) {
  1755.     /*     for(fd = 0; fd < _NFILE; fd++) close(fd); */
  1756.         if(strcmp(button_name,"print") == 0) {
  1757.             
  1758.             lpdest = XGetDefault(XtDisplay(w),"dtree","lpdest");
  1759.             if (lpdest != NULL){
  1760.              execl("/usr/bin/lp","lp","-d",lpdest,filename,(char *)0);
  1761.             }
  1762.             else
  1763.             execl("/usr/bin/lp","lp",filename,(char *)0);
  1764.         }
  1765.         else if(strcmp(button_name,"edit") == 0) {
  1766.  
  1767.             editor = XGetDefault(XtDisplay(w),"dtree","editor");
  1768.  
  1769.             if (editor == NULL) { 
  1770.                  editor = getenv(EDITOR);
  1771.                  if(editor == NULL) 
  1772.                      editor="/usr/bin/vi";
  1773.                        execl("/usr/bin/X11/hpterm",
  1774.                             "hpterm","-e",editor,
  1775.                                   filename,(char *)0);
  1776.                  } else 
  1777.             execlp(editor,editor, filename,(char *)0);
  1778.         }
  1779.         else if(strcmp(button_name,"list files") == 0) {
  1780.               execlp("dtree", "dtree", 
  1781.                    "-a", "-l","1",filename, (char *)0);
  1782.         }
  1783.         else if(strcmp(button_name,"list ../") == 0) {
  1784.  
  1785.             /* find the parent directory */
  1786.             pathl = strlen(filename);
  1787.             namel = strlen(branch->e_name);
  1788.             strncpy(topdir,branch->path_name,pathl-namel);
  1789.  
  1790.              execlp("dtree", "dtree", "-l","1",topdir, (char *)0);
  1791.         }
  1792.             
  1793.         else
  1794.          execlp("dtree", "dtree", 
  1795.                   "-a",filename, (char *)0);
  1796.  
  1797.     fprintf(stderr,"%s command failed\n",button_name);
  1798.     }
  1799.     fprintf(stderr,"fork for %s command failed\n",button_name);
  1800. }
  1801.  
  1802. /* Function that updates the pop-up menu labels and permissions
  1803.    when someone clicks on a node.
  1804. */
  1805. void clickB( w,branch,call_data)
  1806.     Widget w;
  1807.     struct entry *branch;
  1808.     caddr_t call_data;
  1809. {
  1810.     Arg wargs[3];
  1811.     XrmValue bgcolor;
  1812.     if(branch->dir == 1) {
  1813.         XtSetSensitive(file_menu ,FALSE);
  1814.         XtSetSensitive(dir_menu ,True);
  1815.     }
  1816.     else {
  1817.         XtSetSensitive(dir_menu ,False);
  1818. #ifdef STATS
  1819.         /* Don't do anything with symb. links */
  1820.         if(strncmp(" l",getmode(branch->e_mode),2) == 0)
  1821.              XtSetSensitive(file_menu ,False);
  1822.         else
  1823. #endif /* STATS */
  1824.         XtSetSensitive(file_menu ,True);
  1825.     }
  1826.     w_print(options, branch->e_name);
  1827.  
  1828.      /* Get the background color of the activated button 
  1829.         Need to get the foreground color too
  1830.          */
  1831.      _XmSelectColorDefault (w, NULL, &bgcolor);
  1832.     XtSetArg(wargs[0], XmNbackground, *((Pixel *) bgcolor.addr));
  1833.     XtSetValues(options, wargs, 1);
  1834.     file_pointer = branch;
  1835.     button_print(branch);
  1836. }
  1837.  
  1838. /* Print a string on a widget */
  1839.  
  1840. void w_print(w, string)
  1841.     Widget w;
  1842.     char *string;
  1843. {
  1844.     XmString xmstr;
  1845.     Arg wargs[2];
  1846.  
  1847.     xmstr = XmStringLtoRCreate(string, XmSTRING_DEFAULT_CHARSET);
  1848.     XtSetArg(wargs[0], XmNlabelString, xmstr);
  1849.     XtSetValues(w,wargs, 1);
  1850. }
  1851.  
  1852. /* print the labels on the popup menu */
  1853. void button_print(branch)
  1854.     struct entry *branch;
  1855. {
  1856.     char tmp[40];
  1857.     /* w_print(boxes[0], branch->e_name); */
  1858. #ifdef STATS
  1859.     strncpy(tmp,"Mode :",40);
  1860.     strcat(tmp,getmode(branch->e_mode));
  1861.     w_print(boxes[1],tmp);
  1862.     strncpy(tmp,"User :",40);
  1863.     strcat(tmp,guid(branch->e_uid));
  1864.     w_print(boxes[2], tmp);
  1865.     strncpy(tmp,"Group:",40);
  1866.     strcat(tmp, ggid(branch->e_gid));
  1867.     w_print(boxes[3], tmp);
  1868. #endif /* STATS */
  1869. }
  1870.  
  1871. /* 
  1872.  * Copied from D. Young's book  with some changes
  1873.  * Define three callbacks. Make them static - no need 
  1874.  * to make them known outside this file.
  1875.  */
  1876. static void arm_callback(w, flag, call_data)
  1877.      Widget     w;
  1878.      int       *flag;
  1879.      XmAnyCallbackStruct *call_data; 
  1880. {
  1881.  *flag = FALSE;
  1882. }
  1883. static void activate_callback(w, flag, call_data)
  1884.      Widget     w;
  1885.      int       *flag;
  1886.      XmAnyCallbackStruct *call_data; 
  1887. {
  1888.   *flag = TRUE;
  1889. }
  1890. static void disarm_callback(w, flag, call_data)
  1891.      Widget     w;
  1892.      int       *flag;
  1893.      XmAnyCallbackStruct *call_data; 
  1894. {
  1895.   if(*flag){
  1896.     XtCloseDisplay(XtDisplay(w));
  1897.     exit(0);
  1898.   }
  1899. }
  1900.  
  1901. /* function to re-orient the graph */
  1902. #ifndef TREE
  1903. void re_orient(w, graph, call_data)
  1904.     Widget w, graph;
  1905.     caddr_t  call_data;
  1906.  
  1907. {
  1908.     Arg wargs[2];
  1909.     XtSetArg(wargs[0], XmNreorient, True);
  1910.     XtSetValues(graph, wargs, 1);
  1911. }
  1912. #endif
  1913. @EOF
  1914.  
  1915. chmod 444 dtree.c
  1916.  
  1917. echo x - Makefile
  1918. cat >Makefile <<'@EOF'
  1919. # Makefile for dtree
  1920.  
  1921. # Things that might go in DEFS:
  1922. # -DSTATS -DNEWDIR -DDIRENT -DNDIR -DSYSV
  1923. # The -DTREE flag is used to create dtree with the Tree widget
  1924. # otherwise it uses the XmGraph widget.
  1925. DEFS = -D_HPUX_SOURCE -DSTATS -DNEWDIR -DSYSV #-DDIRENT -DS_IFLNK
  1926. CFLAGS = $(DEFS) -O
  1927. LDFLAGS = 
  1928. LIBS = # For Xenix use -lx with -DNDIR
  1929. LIBS = -lmalloc -lXm -lXt -lX11 -lm
  1930.  
  1931.  
  1932. BINDIR = /usr/local/bin/X11
  1933. MANDIR = /usr/local/man/man1
  1934.  
  1935. OBJECTS_A = dtree.o Arc.o Graph.o     #using XmGraph
  1936. OBJECTS_B = dtree_tree.o Tree.o         #using D. Young's tree.
  1937.  
  1938. ARCH_FILES = dtree.1 dtree.c Makefile Dtree Tree.h TreeP.h \
  1939.              dtree-i.h Tree.c Arc.c Arc.h ArcP.h Graph.c Graph.h GraphP.h
  1940.  
  1941. ARCH_FILESB = dtree.1 dtree.c Makefile Dtree dtree-i.h Imakefile README
  1942.  
  1943.  
  1944. all: dtree_tree
  1945.  
  1946. dtree: $(OBJECTS_A)
  1947.     $(CC) -o dtree $(LDFLAGS) $(OBJECTS_A) $(LIBS)
  1948.  
  1949. dtree_tree: $(OBJECTS_B)
  1950.         $(CC) -o dtree $(LDFLAGS) $(OBJECTS_B) $(LIBS)
  1951.  
  1952. Arc.o:    Arc.c
  1953.     $(CC) -c $(CFLAGS) Arc.c +Ns4000
  1954.  
  1955. Graph.o:    Graph.c
  1956.         $(CC) -c $(CFLAGS) Graph.c +Ns4000
  1957.  
  1958. dtree_tree.o:    dtree.c
  1959.         $(CC) -o dtree_tree.o -c $(CFLAGS) -DTREE dtree.c
  1960.  
  1961. install: dtree dtree.1
  1962.     cp dtree $(BINDIR)
  1963.     cp dtree.1 $(MANDIR)
  1964.  
  1965. lint: dtree.c
  1966.     lint $(DEFS) dtree.c
  1967.  
  1968. shar: $(ARCH_FILESB)
  1969.     shar $(ARCH_FILESB) > dtree.shar_1
  1970.     shar Tree* > dtree.shar_2
  1971. dist: dtree.tar.Z
  1972.  
  1973. tar: dtree.tar.Z
  1974.  
  1975. dtree.tar.Z: $(ARCH_FILES)
  1976.     tar cf - $(ARCH_FILES) | compress > dtree.tar.Z
  1977.  
  1978. clean:
  1979.     rm -f dtree *.o core tags a.out
  1980. @EOF
  1981.  
  1982. chmod 644 Makefile
  1983.  
  1984. echo x - Dtree
  1985. cat >Dtree <<'@EOF'
  1986. #
  1987. # app-defaults file for dtree
  1988. #
  1989. dtree*geometry:                     500x500
  1990. dtree*dir.background:               Red
  1991. dtree*file.background:              Gray
  1992. dtree*sym_link.background:          Brown
  1993. dtree*quit.background:              DarkSlateBlue
  1994. dtree*options.background:        Red    
  1995. dtree*XmGraph*childSpacing:         50              #distance between levels
  1996. Mwm*Dtree*iconImage:                /usr/local/include/X11/bitmaps/dtree-i.h
  1997. Hpwm*Dtree*iconImage:               /usr/local/include/X11/bitmaps/dtree-i.h
  1998. !dtree*lpdest:              rljet           #Printer destination
  1999. !dtree*editor:                      emacsclient     #window-clever editor
  2000. !dtree*sym_link.foreground:    
  2001. @EOF
  2002.  
  2003. chmod 644 Dtree
  2004.  
  2005. echo x - dtree-i.h
  2006. cat >dtree-i.h <<'@EOF'
  2007. #define load_i_width 50
  2008. #define load_i_height 50
  2009. static char load_i_bits[] = {
  2010.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  2011.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  2012.    0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x20,
  2013.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10,
  2014.    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  2015.    0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
  2016.    0x00, 0xf8, 0x0f, 0x10, 0x00, 0x20, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
  2017.    0x20, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x20, 0x00, 0x00, 0x0f, 0x08,
  2018.    0x00, 0x00, 0x20, 0x00, 0x00, 0x09, 0x08, 0x10, 0x00, 0x20, 0x00, 0x80,
  2019.    0x08, 0x08, 0x00, 0x00, 0x20, 0x00, 0x80, 0xf8, 0x0f, 0x10, 0x00, 0x20,
  2020.    0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x10,
  2021.    0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00,
  2022.    0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0xfe,
  2023.    0x13, 0xfe, 0xe3, 0x17, 0x00, 0x20, 0x02, 0x0a, 0x02, 0x22, 0x04, 0x00,
  2024.    0x20, 0xaa, 0x0a, 0x56, 0x23, 0x14, 0x00, 0x20, 0x02, 0xfe, 0x03, 0x3e,
  2025.    0x04, 0x00, 0x20, 0xaa, 0x0a, 0xaa, 0x22, 0x14, 0x00, 0x20, 0x02, 0x0a,
  2026.    0x02, 0x22, 0x04, 0x00, 0x20, 0xfe, 0x13, 0xfe, 0xe3, 0x17, 0x00, 0x20,
  2027.    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x10,
  2028.    0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0xf8,
  2029.    0x0f, 0x10, 0x00, 0x20, 0x00, 0x40, 0x08, 0x08, 0x00, 0x00, 0x20, 0x00,
  2030.    0x80, 0x08, 0x08, 0x10, 0x00, 0x20, 0x00, 0x80, 0x08, 0x08, 0x00, 0x00,
  2031.    0x20, 0x00, 0x00, 0x0f, 0x08, 0x10, 0x00, 0x20, 0x00, 0x00, 0x08, 0x08,
  2032.    0x00, 0x00, 0x20, 0x00, 0x00, 0xf8, 0x0f, 0x10, 0x00, 0x20, 0x00, 0x00,
  2033.    0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20,
  2034.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10,
  2035.    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x55, 0x55, 0x55,
  2036.    0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  2037.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  2038.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  2039.    0x00, 0x00};
  2040. @EOF
  2041.  
  2042. chmod 644 dtree-i.h
  2043.  
  2044. echo x - Imakefile
  2045. cat >Imakefile <<'@EOF'
  2046. #Imakefile to create dtree using the "tree" widget.
  2047.  
  2048.         DEFINES = -DSTATS -DNEWDIR -DSYSV -DTREE
  2049. LOCAL_LIBRARIES = 
  2050.   SYS_LIBRARIES = -lmalloc -lXm -lXt -lX11 -lm
  2051.            SRCS = dtree.c Tree.c
  2052.            OBJS = dtree.o Tree.o
  2053.  
  2054. ComplexProgramTarget(dtree)
  2055.  
  2056.  
  2057. @EOF
  2058.  
  2059. chmod 644 Imakefile
  2060.  
  2061. echo x - README
  2062. cat >README <<'@EOF'
  2063. This version of dtree is an X extension of the program originally
  2064. written by Dave Borman. It displays on a terminal or under X11
  2065. (using Motif widgets) the tree structure of a Unix directory tree.
  2066. On a color terminal, different colors can be used for files, directories,
  2067. and symbolic links. One can select nodes of the tree, and edit them,
  2068. view them, or print them. One can also traverse nodes not fully
  2069. shown on the original tree.
  2070.  
  2071. The program uses the "tree" widget described in D. Young's book on
  2072. X window programming (code included here). The program also runs
  2073. using the XmGraph widget, but because that code is not yet stable,
  2074. the code for the XmGraph widget is not included here.
  2075. To make the program run: make dtree_tree
  2076.  
  2077. The program runs faster with the "tree" widget, but the XmGraph
  2078. widgets may provide the potential for additional capabilities, such
  2079. as: removing files from the tree, copying of files and directories, etc.
  2080.  
  2081. Potential problem: because dtree creates a PushButton widget for every file
  2082. or directory shown, you may run out of memory. It is recommended that you
  2083. start with a moderate size tree, and create new ones as needed.
  2084. Experience will show how much you can push it!!
  2085. If you have a monochrome monitor, you may want to substitute those
  2086. widgets with gadgets.
  2087.  
  2088. For example: dtree -l 2
  2089. will show the tree of your current directory up to depth 2.
  2090.          dtree -al 2
  2091. will show both files and directories up to depth 2.
  2092.  
  2093. K. Konstantinides
  2094. HP Labs
  2095. kk@hpkronos.hpl.hp.com
  2096. @EOF
  2097.  
  2098. chmod 644 README
  2099.  
  2100. exit 0
  2101.  
  2102. dan
  2103. ----------------------------------------------------
  2104. O'Reilly && Associates   argv@sun.com / argv@ora.com
  2105. Opinions expressed reflect those of the author only.
  2106.