home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume18 / xdtree / part01 / xdtree.c < prev   
Encoding:
C/C++ Source or Header  |  1992-07-20  |  40.4 KB  |  1,511 lines

  1. /*
  2.  *    DTREE - Print the tree structure of a directory
  3.  *    4/7/83 name was changed from TREE to DTREE
  4.  *    9/7/83 mods for 4.1c and 4.2 dirctory structure added
  5.  *
  6.  *    Dave Borman, Digital Unix Engineering Group
  7.  *        decvax!borman
  8.  *    Originally written at St. Olaf College, Northfield MN.
  9.  *    Copyright (c) 1983 by Dave Borman
  10.  *    All rights reserved
  11.  *    This program may not be sold, but may be distributed
  12.  *    provided this header is included.
  13.  *
  14.  *    Usage:    xdtree [-aDfghHlNpstvx] [-c line-length] [directory...]
  15.  *    Flags:    -a) include non-directory entries in listing
  16.  *        -D) sort tree with directories at the top
  17.  *        -f) sort tree with files at the top
  18.  *        -g) same as S, but use group name instead of user name
  19.  *              -h) help
  20.  *        -H) display a header at top
  21.  *        -S) print stats with each listing
  22.  *            if both g & S flags are given, both owner and
  23.  *            group will be printed
  24.  *        -N) do not sort the tree
  25.  *        -p) include files starting with a '.' (except "." & "..")
  26.  *        -s) use shorter stats. Implies -S if -g isn't given.
  27.  *              -t) Use terminal mode (no X windows)
  28.  *        -v) variable length columns off
  29.  *        -x) do not cross mounted file systems.
  30.  *        -c length) set max column length to "length"
  31.  *        -l level) search up to the specified "level".
  32.  */
  33.  
  34.  /*     Modified by      Ed Arnold      CSU-CS   (csu-cs!arnold)     3-5-84
  35.   *
  36.   *     Allows symbolic links to both directories and individual files.
  37.   *     With a '-S' or '-aS' option, links are denoted with a 'l' in front of 
  38.   *     file or directory permissions. In all other instances both links to 
  39.   *     directories and files are represented just as files are. Contents of
  40.   *     linked directories are not printed due to the possibility of 
  41.   *     recursively linked directories.
  42.   *
  43.   *     Big directory name option added by:
  44.   *                      Mike Vevea      CSU-CS (csu-cs!vevea)      3-22-84
  45.   *
  46.   *    Toggle sense of -v (running 4.2), and eliminate some extraneous
  47.   *        print info    Mike Meyer Energy Analysts (mwm@ea)    4/17/84
  48.   *
  49.   *    Fix the exit status to correctly indicate what happened.
  50.   *                Mike Meyer Energy Analysts (mwm@ea)    4/23/84
  51.   *
  52.   *    Change MAX to INITIAL_ELEM to fix conflict on Suns,
  53.   *    fix incorrect default value for Clength when -v not given,
  54.   *    add -H option to print header with date and description of tree,
  55.   *    remove -b option (useless) and simplify array access,
  56.   *    use getopt to parse options, fix usage message,
  57.   *    use getwd instead of opening a pipe to pwd,
  58.   *    make error messages more informative,
  59.   *    use strncpy instead of sprintf for speed,
  60.   *    move function declarations to top of file,
  61.   *    comment out junk after #else and #endif,
  62.   *    make symbolic link configuring automatic,
  63.   *    check all error returns from malloc and realloc,
  64.   *    add System V/Xenix/Unos compatibility,
  65.   *    remove definition of rindex.
  66.   *        David MacKenzie <djm@eng.umd.edu> 12/20/89
  67.   *
  68.   *    Modified to display the tree on X11 windows using the Motif
  69.   *    widgets and the Tree widget described by D.Young in his book,
  70.   *     "The X Window System, Programming and applications with Xt,
  71.   *     OSF/MOTIF EDITION", Prentice Hall, 1990.
  72.   *     Clicking on the "active" node pops-up a menu with the Mode, and Group
  73.   *     and User IDs. Clicking on "view" pops up a window with the whole
  74.   *     contents of the file. Clicking on "topview" shows the top
  75.   *    of the file only (2000 bytes).
  76.   *     On the tree, files, directories, and symbolic links can be
  77.   *     shown with different colors.
  78.   *     Changed some options so there is no conflict with X-window
  79.   *    options ( -d to -D, and -n to -N).
  80.   *    Added the -t and -h options. Changed the -l option to -S
  81.   *     Added the "-l level" option.
  82.   *    Konstantinos Konstantinides, Hewlett-Packard Laboratories
  83.   *     konstantinos_konstantinides@hplabs.hp.com  3/23/90
  84.   *
  85.   *     Copyright: HEWLETT-PACKARD, 1990
  86.   *     Motif is a trademark of Open Software Foundation, Inc.
  87.   *     X Window System is a trademark of the Massachusetts Institute of
  88.   *     Technology
  89.   *
  90.   *    Added support for both the Tree and XmGraph widgets
  91.   *    K. Konstantinides 4/16/90
  92.   *
  93.   *     Rewrote the user interface, renamed program from dtree to xdtree
  94.   *     K. Konstantinides 4/30/92
  95.   */
  96.  
  97. /* Compile-time options:
  98.  *
  99.  * STATS    leave undefined to remove stats, giving more core space
  100.  * and thus the ability to tree larger tree structures on PDP 11/70s.
  101.  *
  102.  * NEWDIR    directory structure a la Berkeley 4.1c or 4.2
  103.  *
  104.  * NDIR        use <sys/ndir.h> instead of <sys/dir.h>
  105.  * NEWDIR must be defined as well.
  106.  *
  107.  * DIRENT    use Posix directory library.
  108.  * NEWDIR must be defined as well.
  109.  *
  110.  * SYSV        use getcwd instead of getwd, strrchr instead of rindex.
  111.  */
  112. void re_orient();
  113. void disarm_callback();
  114. void activate_callback();
  115. void arm_callback();
  116. void clickB();
  117. void w_print();
  118. void button_print();
  119. void pop_data();
  120. void view();
  121. void quit_b();
  122. void quit_b_pop();
  123. void do_menu(), stoggle(), htoggle(), gtoggle(), print_tree();
  124.  
  125. static    char Sccsid[]="@(#)xdtree.c    2.0    4/30/92";
  126.  
  127. #ifdef S_IFLNK
  128. static  char Rcsid[] ="$Header: xdtree.c,v 2.1 92/04/30 18:01:12 kk Exp $";
  129. #endif /* S_IFLNK */
  130.  
  131. #include    <stdio.h>
  132. #include    <sys/types.h>
  133. #include    <sys/stat.h>
  134. #include    <time.h>
  135. #include    <string.h>
  136. #include    <stdlib.h>
  137.  
  138. /* Include files for X windows */
  139. #include <X11/Intrinsic.h>
  140. #include <X11/Shell.h>
  141. #include <X11/StringDefs.h>
  142. #include <Xm/Xm.h>
  143. #include <Xm/Label.h>
  144. #include <Xm/PushB.h>
  145. #include <Xm/PushBG.h>
  146. #include <Xm/CascadeB.h>
  147. #include <Xm/RowColumn.h>
  148. #include <Xm/ScrolledW.h>
  149. #include <Xm/Separator.h>
  150. #include <Xm/MainW.h>
  151. #include <Xm/Frame.h>
  152. #include <Xm/Form.h>
  153. #include <Xm/Text.h>
  154. #include <Xm/ToggleB.h>
  155. #include "Tree.h"
  156.  
  157. /* Original Defs */
  158. #ifdef    STATS
  159. # include    <pwd.h>
  160. # include    <grp.h>
  161. #endif    /* STATS */
  162.  
  163. #ifdef    NEWDIR
  164. # if    DIRENT
  165. #  include    <dirent.h>
  166. #  define    direct    dirent
  167. # else
  168. #  if    NDIR
  169. #   include    <sys/ndir.h>
  170. #  else
  171. #   include    <sys/dir.h>
  172. #  endif
  173. # endif /* DIRENT */
  174. #else
  175. # include    <sys/dir.h>
  176. #endif    /* NEWDIR */
  177.  
  178. /* default column length when -v is given */
  179. #ifdef unos
  180. #define DEFCOLWID    30
  181. #else
  182. #define DEFCOLWID       14
  183. #endif
  184.  
  185. #include    <sys/param.h>    /* for MAXPATHLEN */
  186. #ifndef MAXPATHLEN
  187. # ifdef LPNMAX        /* Xenix from stdio.h */
  188. #  define MAXPATHLEN (LPNMAX - 1)
  189. # else
  190. #  include <limits.h>    /* try somewhere else */
  191. #  define MAXPATHLEN PATH_MAX
  192. # endif
  193. #endif
  194.  
  195. #ifndef MAXNAMLEN    /* defined with NEWDIR routines */
  196. # ifdef LFNMAX        /* Xenix again */
  197. #  define MAXNAMLEN (LFNMAX - 1)
  198. # else
  199. #  define MAXNAMLEN      DEFCOLWID
  200. # endif
  201. #endif
  202.  
  203. #define    DEPTH 10    /* maximum depth that dtree will go */
  204. #define    INITIAL_ELEM    100    /* initial # of elements for list of files */
  205.  
  206. #define    FFIRST    2    /* sort files first */
  207. #define DFIRST    1    /* sort directories first */
  208. #define    FAIL    -1    /* failure return status of sys calls */
  209. #define    GREATER    1    /* return value of strcmp if arg1 > arg2 */
  210. #define    LESSTHAN -1    /* return value of strcmp if arg1 < arg2 */
  211. #define    SAME    0    /* return value of strcmp if arg1 == arg2 */
  212.  
  213. #ifdef    STATS
  214. char *getmode();
  215. char *guid();
  216. char *ggid();
  217. struct passwd *getpwuid();
  218. struct group *getgrgid();
  219. #endif /* STATS */
  220.  
  221. #ifdef    SYSV
  222. #define    rindex    strrchr
  223. #endif /* SYSV */
  224.  
  225. char *getwd();
  226. char *rindex();
  227. /* 
  228. int qsort();
  229. char *malloc();
  230. char *realloc();
  231. */
  232. long time();
  233.  
  234. int compar();            /* comparison routine for qsort */
  235. char *xmalloc();
  236. char *xrealloc();
  237.  
  238. #ifdef    SYSV
  239. #define getwd(buf) getcwd((buf), MAXPATHLEN + 1)
  240. #endif /* SYSV */
  241.  
  242. int    Index = 0;        /* current element of list[]    */
  243. int     CLength = 0;        /* max length of a column       */
  244. int    All = 0;        /* all != 0; list non-directory entries */
  245. int    File_dir = 0;        /* flag for how to sort */
  246. int    Sort = 1;        /* flag to cause sorting of entries */
  247. int    Point = 1;        /* skip point files if set    */
  248. int    Header = 0;        /* print verbose header */
  249. int    Maxes[DEPTH];        /* array keeps track of max length in columns */
  250. int    Level = 0;        /* counter for how deep we are    */
  251. int    Device;            /* device that we are starting tree on */
  252. int    Xdev = 1;        /* set to allow crossing of devices */
  253. int    Varspaces = 1;        /* set to allow compaction of column width */
  254. #ifdef    STATS
  255. int    Gflag = 0;        /* set for group stats instead of owner */
  256. int    Longflg = 0;        /* set for long listing */
  257. int    Compact = 0;        /* set for shortened long listing */
  258. #endif    /* STATS */
  259. #undef Status
  260. struct    stat Status;
  261. #ifdef  S_IFLNK
  262. struct  stat Lstat;   /* stat of link, if there is one */
  263. #endif  /* S_IFLNK */
  264.  
  265. struct entry {
  266.     int next;            /* index to next element in list */
  267.                     /* could be a ptr, but realloc() */
  268.                     /* might screw us then */
  269. #ifdef    STATS
  270.     off_t    e_size;            /* size in blocks */
  271.     unsigned short    e_mode;        /* file mode */
  272.     short    e_uid;            /* uid of owner */
  273.     short    e_gid;            /* gid of owner */
  274. #endif    /* STATS */
  275.     unsigned short dir : 1;        /* entry is a directory */
  276.     unsigned short last : 1;    /* last entry in the dir. */
  277.     unsigned short dev : 1;        /* set if same device as top */
  278.     unsigned short end : 13;    /* index of last subdir entry*/
  279.     char    e_name[MAXNAMLEN + 1];    /* name from directory entry */
  280.     char    path_name[MAXPATHLEN + 1]; /* path name */
  281. } *List, *SaveList;
  282.  
  283. unsigned Size;                /* how big of space we've malloced */
  284.  
  285. char    *Spaces;    /* used for output */
  286. char    Buf1[BUFSIZ];    /* buffers for stdio stuff.  We don't want    */
  287. #ifndef NEWDIR
  288. char    Buf2[BUFSIZ];    /* anyone calling malloc, because then        */
  289.             /* realloc() will have to move the whole list    */
  290. #endif
  291. #define FS(str) (void) fprintf(stderr,str)
  292.  
  293. help()
  294. {
  295.                     fprintf(stderr,
  296. #ifdef    STATS
  297.         "Usage: xdtree [-aDfghHlNpstvx] [-c linelength] [directory ... ]\n"
  298. #else    /* STATS */
  299.         "Usage: xdtree [-aDfhHNptvx] [-c linelength] [directory ... ]\n"
  300. #endif    /* STATS */
  301.                         );
  302. FS("   options  -a) include non-directory entries in listing\n");
  303. FS("            -D) sort tree with directories at the top\n");
  304. FS("            -f) sort tree with files at the top\n");
  305. FS("            -h) help - prints this message\n");
  306. FS("            -H) display a header at top\n");
  307. FS("            -x) do not cross mounted file systems.\n");
  308. FS("            -p) include files starting with a . (except . and ..)\n");
  309. FS("            -N) do not sort the tree\n");
  310. FS("            -t) Use terminal mode, don't display on an X window\n\n");
  311. FS("            -l level) Search only up to the specified level \n\n");
  312. FS("            Valid only if -t is used. Under default mode, a click on a \n");
  313. FS("            node pops up a menu with mode, user and group ids.\n\n");
  314. FS("            -S) print stats with each listing\n");
  315. FS("                if both g & S flags are given, both owner and\n");
  316. FS("                group will be printed\n");
  317. FS("            -g) same as S, but use group name instead of user name \n");
  318. FS("            -s) use shorter stats. Implies -S if -g isn't given.\n");
  319. FS("            -v) variable length columns \n");
  320. FS("            -c length) set max column length to -length-\n");
  321. FS("  X-Window version 2.0 4/30/92 \n");
  322. }
  323. int newlevel = DEPTH;
  324. Widget boxes[12], options;
  325. Widget submenu_file, submenu_dir,file_menu, dir_menu;
  326. struct entry *file_pointer;
  327. int S_flag = FALSE;
  328. int H_flag=FALSE;
  329. int g_flag=FALSE;
  330.  
  331.  
  332. main(argc, argv)
  333. char    **argv;
  334. int    argc;
  335. {
  336.     extern int optind;
  337.     extern char *optarg;
  338.     register int i;
  339.     char    top[MAXPATHLEN + 1];    /* array for treetop name */
  340.     char    home[MAXPATHLEN + 1];    /* starting dir for multiple trees */
  341.     char    *ptr;
  342.  
  343.     Widget toplevel;
  344.     Widget sw, tree, q_button, w_button;
  345.     Widget menu_bar, frame, main_w, title;
  346.     Arg    wargs[10],arg[15];
  347.     int    flagX=1;            /* use X windows as default */
  348.     Widget quit_menu, exit_b, reorient;
  349.     int really_quit, n;
  350.  
  351.     setbuf(stdout, Buf1);
  352.  
  353.     while ((i = getopt (argc, argv,
  354. #ifdef STATS
  355.                 "haDfgHl:NpsSvxtc:"
  356. #else
  357.                 "haDfHl:Npvxtc:"
  358. #endif /* STATS */
  359.                 )) != EOF) {
  360.         switch (i) {
  361.                 case 'a':
  362.                     All = 1;
  363.                     break;
  364.                 case 'c':
  365.                     CLength = atoi(optarg);
  366.                     if (CLength > MAXNAMLEN)
  367.                         CLength = MAXNAMLEN;
  368.                     else if (CLength < 1)
  369.                         CLength = DEFCOLWID;
  370.                     break;
  371.                 case 'l':
  372.                     newlevel = atoi(optarg);
  373.                     if(newlevel > DEPTH) {
  374.                     newlevel = DEPTH;
  375.                     fprintf(stderr,"Warning: Depth is limited by DEPTH=%d\n",newlevel);
  376.                     }
  377.                     break;
  378.                 case 'D':
  379.                     File_dir = DFIRST;
  380.                     break;
  381.                 case 'f':
  382.                     File_dir = FFIRST;
  383.                     break;
  384.                 case 'H':
  385.                     Header = 1;
  386.                     break;
  387.                 case 'N':
  388.                     Sort = 0;
  389.                     break;
  390.                 case 'p':
  391.                     Point = 0;
  392.                     break;
  393.                 case 'v':
  394.                     Varspaces = 0;
  395.                     break;
  396.                 case 'x':
  397.                     Xdev = 0;
  398.                     break;
  399.                 case 't':
  400.                     flagX = 0;
  401.                     break;
  402.  
  403.                 case 'h':
  404.                     help();
  405.                     exit(0);
  406. #ifdef    STATS
  407.                 case 'g':
  408.                     Gflag = 1;
  409.                     break;
  410.                 case 'S':
  411.                     Longflg = 1;
  412.                     break;
  413.                 case 's':
  414.                     Compact = 1;
  415.                     break;
  416. #endif    /* STATS */
  417.                 default:
  418.                     help();
  419.                     exit(FAIL);
  420.                 }
  421.     }
  422. #ifdef    STATS
  423.     if (Compact && !Gflag)
  424.         Longflg = 1;
  425. #endif    /* STATS */
  426.     if (CLength == 0)
  427.         CLength = Varspaces ? MAXNAMLEN : DEFCOLWID;
  428.  
  429.     /* Establish where we are (our home base...) */
  430.     if (getwd(home) == 0) {
  431.         fprintf(stderr,
  432.             "xdtree: Cannot get initial directory: %s\n", home);
  433.         exit(1);
  434.     }
  435.  
  436.     Spaces = xmalloc(MAXNAMLEN+2);
  437.     for(i = 0; i <= MAXNAMLEN; i++)
  438.         Spaces[i] = ' ';
  439.     Spaces[i] = '\0';
  440.  
  441.     /* Get initial Storage space */
  442.     Size = sizeof(struct entry) * INITIAL_ELEM;
  443.     SaveList = (struct entry *)xmalloc(Size);
  444.  
  445.     /* adjust for no specified directory */
  446.     if (optind == argc )
  447.         if(optind > 1) argv[--optind] = ".";
  448.         else { argv[1] = ".", optind = 1; argc = 2;}
  449.  
  450.     if (Header)
  451.         print_date();
  452.  
  453.     /* walk down the rest of the args, treeing them one at at time */
  454.     for (; optind < argc; optind++) {
  455.         if (chdir(home) == -1) {
  456.             fprintf(stderr, "xdtree: Cannot change to initial directory ");
  457.             perror(home);
  458.             exit(1);
  459.         }
  460.         strncpy (top, argv[optind], MAXPATHLEN);
  461.  
  462.         if (chdir(top) == FAIL) {
  463.             fprintf(stderr, "xdtree: Cannot change to top directory ");
  464.             perror(top);
  465.             continue;
  466.         } else if (getwd(top) == 0) {
  467.             fprintf(stderr,"xdtree: Cannot get current directory: %s\n", top);
  468.             continue;
  469.         }
  470.  
  471.         List = SaveList; Index = 0;
  472.         getwd(List[0].path_name);
  473.         ptr = rindex(top, '/');
  474.  
  475.         if (!ptr || *++ptr == '\0')
  476.             strncpy(List[Index].e_name, top, MAXNAMLEN);
  477.         else
  478.             strncpy(List[Index].e_name, ptr, MAXNAMLEN);
  479.  
  480.         if(stat(top, &Status) == FAIL) {
  481.             fprintf(stderr, "xdtree: Cannot stat directory ");
  482.             perror(top);
  483.             continue;
  484.         }
  485.         Device = Status.st_dev;
  486.         List[0].dir = 1;
  487.         List[0].last = 1;
  488.         List[0].next = 1;
  489. #ifdef    STATS
  490.         List[0].e_mode = Status.st_mode;
  491.         List[0].e_uid = Status.st_uid;
  492.         List[0].e_gid = Status.st_gid;
  493.         List[0].e_size = Status.st_size;
  494. #endif    /* STATS */
  495.         Index = 1;
  496.         for (i = 1; i < DEPTH; i++)
  497.             Maxes[i] = 0;
  498.         Maxes[0] = stln(List[0].e_name);
  499.         Level = 1;
  500.  
  501.         /* Don't waste time if there is no display */
  502.         if(flagX == 1)
  503.         toplevel = XtInitialize(argv[0], "XDtree", NULL, 0, &argc, argv);
  504.  
  505.         fprintf(stderr,"Started searching....Please wait \n");
  506.         /* search the tree */
  507.         List[0].end = t_search(top, &List[0]);
  508.  
  509.         if (Index == 1)                /* empty tree */
  510.             List[0].next = 0;
  511.  
  512.         if (Header) {
  513.         if (All)
  514.             printf("\nDirectory structure and contents of %s\n", top);
  515.         else
  516.             printf("\nDirectory structure of %s\n", top);
  517.         if (Point)
  518.             printf("(excluding entries that begin with '.')\n");
  519.         }
  520.  
  521.         if(flagX == 0) pt_tree();
  522.         else {
  523.  
  524.     /* Create a Form, with button options and a Frame window
  525.        Put on the Frame, a ScrolledWindow and the Tree window
  526.        The Top has a quit button and the directory Name
  527.     */
  528.             fprintf(stderr,"Opening display now...Please wait\n");
  529.  
  530.             /* main window */
  531.             n=0;
  532.             main_w = XtCreateManagedWidget(NULL, xmFormWidgetClass,
  533.                            toplevel, wargs, n);
  534.  
  535.              n=0;
  536.                        XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
  537.                XtSetArg(arg[n], XmNtopAttachment, XmATTACH_FORM); n++;
  538.                XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
  539.              menu_bar = XmCreateMenuBar(main_w,"menu",arg,n); 
  540.              XtManageChild(menu_bar);
  541.  
  542.  
  543.             /* quit button */
  544.  
  545.             quit_menu = XmCreatePulldownMenu(menu_bar,
  546.                     "quit_menu",NULL,0);
  547.             XtSetArg(wargs[0], XmNsubMenuId,quit_menu);
  548.             q_button = XmCreateCascadeButton(menu_bar, 
  549.                            "quit",wargs,1);
  550.             XtManageChild(q_button);
  551.  
  552.                w_button =XtCreateManagedWidget("warning",
  553.                 xmLabelWidgetClass,quit_menu, NULL,0);
  554.         w_print(w_button,"Don't exit unless all children are dead\n");
  555.                exit_b = XtCreateManagedWidget("Exit", 
  556.                   xmPushButtonWidgetClass, quit_menu, NULL, 0);
  557.                XtAddCallback(exit_b, XmNarmCallback, 
  558.                 arm_callback, &really_quit);
  559.                XtAddCallback(exit_b, XmNdisarmCallback, 
  560.                 disarm_callback, &really_quit);
  561.                XtAddCallback(exit_b, XmNactivateCallback, 
  562.                 activate_callback, &really_quit);     
  563.  
  564.             /* Create the options buttons */
  565.             file_pointer = &List[0];
  566.             show_menu(main_w,file_pointer,menu_bar); 
  567.  
  568.                        title = XtCreateManagedWidget("title",
  569.                xmCascadeButtonWidgetClass, menu_bar, NULL,0);
  570.                XtSetArg(wargs[0],XmNmenuHelpWidget, title);
  571.                XtSetValues(menu_bar, wargs, 1);
  572.                        w_print(title,top);
  573.  
  574.             /* frame */
  575.             n=0;
  576.             XtSetArg(arg[n], XmNshadowType, XmSHADOW_OUT); n++;
  577.             XtSetArg(arg[n], XmNtopWidget, submenu_file); n++;
  578.         XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  579.         XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
  580.         XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
  581.         XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  582.             frame = XmCreateFrame(main_w,"frame",arg,n);
  583.             XtManageChild(frame);
  584.  
  585.             XtSetArg(wargs[0], XmNscrollingPolicy, XmAUTOMATIC);
  586.             sw = XtCreateManagedWidget("swindow",
  587.                 xmScrolledWindowWidgetClass, frame, wargs, 1);
  588.  
  589.  
  590.             /* Tree widget */
  591.             tree = XtCreateManagedWidget("tree",XstreeWidgetClass,
  592.                     sw, NULL,0);
  593.             show_dtree(tree);
  594.             clickB(options,file_pointer,NULL);
  595.             XtRealizeWidget(toplevel);
  596.             XtMainLoop();
  597.         }
  598.         
  599.     }
  600.     exit(0) ;
  601. }
  602.  
  603.  
  604. t_search(dir, addrs)
  605. char *dir;
  606. struct    entry *addrs;
  607. {
  608.     int    bsort;            /* index to begin sort */
  609.     int    stmp;            /* save temporary index value */
  610.     struct entry *sstep;        /* saved step in list */
  611.     int    nitems;            /* # of items in this directory */
  612. #ifdef    NEWDIR
  613.     DIR    *dirp;            /* pointer to directory */
  614. #else
  615.     FILE    *dirp;
  616. #endif
  617.     char    sub[MAXNAMLEN+1];    /* used for subdirectory names */
  618.     int    i;
  619. #ifdef    NEWDIR
  620.     struct direct *dp;
  621. #else
  622.     struct direct dirent;
  623.     struct direct *dp = &dirent;
  624. #endif    /* NEWDIR */
  625.     int    n_subs = 0;
  626.     int    tmp = 0;
  627.  
  628. #ifdef    NEWDIR
  629.     dirp = opendir(".");
  630. #else
  631.     dirp = fopen(".", "r");
  632. #endif    /* NEWDIR */
  633.     if (dirp == NULL) {
  634.         fprintf(stderr, "xdtree: Cannot open directory ");
  635.         perror(dir);
  636.         return(0);
  637.     }
  638. #ifndef    NEWDIR
  639.     setbuf(dirp, Buf2);
  640. #endif    /* NEWDIR */
  641.  
  642.     bsort = Index;
  643.     sstep = &List[bsort]; /* initialize sstep for for loop later on */
  644.     nitems = Index;
  645.     /* get the entries of the directory that we are interested in */
  646. #ifndef    NEWDIR
  647.     while (fread((char *)(dp), sizeof(struct direct), 1, dirp) == 1) {
  648. #else
  649.     while ((dp = readdir(dirp)) != NULL) {
  650. #endif    /* NEWDIR */
  651.  
  652.         if (dp->d_ino
  653. #ifdef unos
  654.             == -1
  655. #else
  656.             == 0
  657. #endif /* unos */
  658.             || (strcmp(dp->d_name, ".") == SAME)
  659.             || (strcmp(dp->d_name, "..") == SAME)
  660.             || (Point && dp->d_name[0] == '.'))
  661.                 continue;
  662.  
  663.         strncpy(sub, dp->d_name, MAXNAMLEN);
  664. #ifdef S_IFLNK
  665.         if (lstat(sub,&Lstat) == FAIL) {
  666.             fprintf(stderr, "xdtree: In directory %s, cannot lstat entry ", dir);
  667.             perror(sub);
  668.             continue;
  669.                 }
  670. #endif /* S_IFLNK */
  671.         if (stat(sub, &Status) == FAIL) {
  672.             fprintf(stderr, "xdtree: In directory %s, cannot stat entry ", dir);
  673.             perror(sub);
  674.             continue;
  675.         }
  676. #ifdef S_IFLNK
  677.         if (((Lstat.st_mode & S_IFMT) == S_IFLNK)  &&
  678.             ((Status.st_mode & S_IFMT) == S_IFDIR)) 
  679.                 List[Index].dir = 0;    
  680.         else if ((((Lstat.st_mode & S_IFMT) == S_IFLNK) &&
  681.             ((Status.st_mode & S_IFMT) != S_IFDIR)) && (All)) 
  682.                         List[Index].dir = 0;
  683. #endif /* S_IFLNK */
  684.         else if ((Status.st_mode & S_IFMT) == S_IFDIR)
  685.             List[Index].dir = 1;
  686.         else if (All)
  687.             List[Index].dir = 0;
  688.         else
  689.             continue;
  690.         strncpy(List[Index].e_name, dp->d_name, MAXNAMLEN);
  691.         getwd(List[Index].path_name);
  692.         List[Index].last = 0;
  693.         List[Index].end = 0;
  694. #ifdef S_IFLNK
  695.         if ((Lstat.st_mode & S_IFMT) == S_IFLNK) {
  696.              List[Index].dev = (Device == Lstat.st_dev);
  697.              List[Index].e_mode = Lstat.st_mode;
  698.              List[Index].e_uid = Lstat.st_uid;
  699.              List[Index].e_gid = Lstat.st_gid;
  700.              List[Index].e_size = Lstat.st_size;
  701.                 }
  702.                 else {
  703. #endif /* S_IFLNK */
  704.              List[Index].dev = (Device == Status.st_dev);
  705. #ifdef STATS
  706.              List[Index].e_mode = Status.st_mode;
  707.              List[Index].e_uid = Status.st_uid;
  708.              List[Index].e_gid = Status.st_gid;
  709.              List[Index].e_size = Status.st_size;
  710. #endif /* STATS */
  711. #ifdef S_IFLNK
  712.                 }
  713. #endif /* S_IFLNK */
  714.         if (stln(List[Index].e_name) > Maxes[Level])
  715.             Maxes[Level] = stln(List[Index].e_name);
  716.         ++Index;
  717.         if (Index*sizeof(struct entry) >= Size) {
  718.             Size += 20*sizeof(struct entry);
  719.             List = (struct entry *)xrealloc((char *)List, Size);
  720.         }
  721.     }
  722. #ifdef    NEWDIR
  723.     closedir(dirp);
  724. #else
  725.     fclose(dirp);
  726. #endif    /* NEWDIR */
  727.  
  728.     nitems = Index - nitems;    /* nitems now contains the # of */
  729.                     /* items in this dir, rather than */
  730.                     /* # total items before this dir */
  731.  
  732.     if (Sort)
  733.         qsort(&List[bsort], nitems, sizeof(struct entry), compar);
  734.  
  735.     List[Index-1].last = 1;    /* mark last item for this dir */
  736.     n_subs = nitems;
  737.     stmp = Index;
  738.  
  739.     /* now walk through, and recurse on directory entries */
  740.     /* sstep was initialized above */
  741.  
  742.     for (i = 0; i < nitems; sstep = &List[stmp - nitems+(++i)]) {
  743.         if (sstep->dir && (Level < newlevel) && (Xdev || sstep->dev)) {
  744.             sstep->next = Index;
  745.             strncpy(sub, sstep->e_name, MAXNAMLEN);
  746.             tmp = n_subs;
  747.             Level++;
  748.             if (chdir(sub) == FAIL) {
  749.                 fprintf(stderr,
  750.                     "xdtree: Cannot change to directory %s/", dir);
  751.                 perror(sub);
  752.             } else {
  753.                 n_subs += t_search(sub, sstep);
  754.                 if (chdir("..") == FAIL) {
  755.                     fprintf(stderr,
  756.                         "xdtree: %s/%s lacks '..' entry\n",dir, sub);
  757.                     exit(1);
  758.                 }
  759.             }
  760.             --Level;
  761.             if (n_subs - tmp <= 0)
  762.                 sstep->next = 0;
  763.             else
  764.                 --n_subs;
  765.         }
  766.         else
  767.             sstep->next = 0;
  768.     }
  769.     addrs->end = (unsigned)n_subs;
  770.     return(n_subs);
  771. }
  772.  
  773. /*
  774.  *    comparison routine for qsort
  775.  */
  776.  
  777. compar(a, b)
  778. struct entry *a, *b;
  779. {
  780.     if (!File_dir)        /* straight alphabetical */
  781.         return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
  782.  
  783.     /* sort alphabetically if both dirs or both not dirs */
  784.  
  785.     if ((a->dir && b->dir) || (!a->dir && !b->dir))
  786.         return(strncmp(a->e_name, b->e_name, MAXNAMLEN));
  787.  
  788.     if (File_dir == FFIRST) {    /* sort by files first */
  789.         if (a->dir)
  790.             return(GREATER);
  791.         else
  792.             return(LESSTHAN);
  793.     }
  794.  
  795.     if (a->dir)            /* sort by dir first */
  796.         return(LESSTHAN);
  797.     else
  798.         return(GREATER);
  799. }
  800.  
  801.  
  802. pt_tree()
  803. {
  804.     register int    i,j;
  805.     struct entry *l;
  806.     struct entry *hdr[DEPTH];
  807.     int posit[DEPTH];        /* array of positions to print dirs */
  808.     int con[DEPTH];            /* flags for connecting up tree */
  809.     char    flag = 0;        /* flag to leave blank line after dir */
  810.     struct    entry *stack[DEPTH];    /* save positions for changing levels */
  811.     int    top = 0;        /* index to top of stack */
  812.     int    count = 1;        /* count of line of output */
  813.  
  814.     Level = 0;            /* initialize Level */
  815.  
  816.     /* this loop appends each entry with dashes or spaces, for */
  817.     /* directories or files respectively */
  818.  
  819.     for (i = 0; i < Index; i++) {
  820.         for (j = 0; j < MAXNAMLEN; j++) {
  821.             if (!List[i].e_name[j])
  822.                 break;
  823.         }
  824.         if (List[i].dir) {
  825.             for (; j < MAXNAMLEN; j++)
  826.                 List[i].e_name[j] = '-';
  827.         } else {
  828.             for (; j < MAXNAMLEN; j++)
  829.                 List[i].e_name[j] = ' ';
  830.         }
  831.     }
  832.  
  833.     /* adjust the Maxes array according to the flags */
  834.  
  835.     for (i = 0; i < DEPTH; i++) {
  836.         if (Varspaces) {
  837.             if (Maxes[i] > CLength )
  838.                 Maxes[i] = CLength;
  839.         } else
  840.             Maxes[i] = CLength;
  841.     }
  842.  
  843.     /* clear the connective and position flags */
  844.  
  845.     for (i = 0; i < DEPTH; i++)
  846.         con[i] = posit[i] = 0;
  847.  
  848.     /* this is the main loop to print the tree structure. */
  849.     l = &List[0];
  850.     j = 0;
  851.     for (;;) {
  852.         /* directory entry, save it for later printing */
  853.         if (l->dir != 0 && l->next != 0) {
  854.             hdr[Level] = l;
  855.             posit[Level] = count + (l->end + 1)/2 - 1;
  856.             flag = 1;
  857.             stack[top++] = l;
  858.             l = &List[l->next];
  859.             ++Level;
  860.             continue;
  861.         }
  862.  
  863. #ifdef    STATS
  864.     do_it_again:
  865. #endif    /* STATS */
  866.         /* print columns up to our entry */
  867.         for (j = 0; j < (flag ? Level-1 : Level); j++) {
  868.             if (!flag && posit[j] && posit[j] <= count) {
  869.                 /* time to print it */
  870.                 if (hdr[j]->e_name[CLength-1] != '-')
  871.                     hdr[j]->e_name[CLength-1] = '*';
  872.                 printf("|-%.*s",Maxes[j],hdr[j]->e_name);
  873.                 posit[j] = 0;
  874.                 if (hdr[j]->last != 0)
  875.                     con[j] = 0;
  876.                 else
  877.                     con[j] = 1;
  878. #ifdef    STATS
  879.                 if (Gflag || Longflg) {
  880.                     if ((i = j+1) <= Level)
  881.                     printf("| %.*s", Maxes[i], Spaces);
  882.                     for (i++; i <= Level; i++) {
  883.                     printf("%c %.*s",
  884.                         (con[i] ? '|' : ' '),
  885.                         Maxes[i], Spaces);
  886.                     }
  887.                     if (!Compact) {
  888.                     printf("%s ", getmode(hdr[j]->e_mode));
  889.                     if (Longflg)
  890.                        printf("%8.8s ",guid(hdr[j]->e_uid));
  891.                     if (Gflag)
  892.                        printf("%8.8s ",ggid(hdr[j]->e_gid));
  893.                     printf("%7ld\n",
  894.                         (hdr[j]->e_size+511L)/512L);
  895.                     } else {
  896.                     printf(" %04o ",hdr[j]->e_mode & 07777);
  897.                     if (Longflg)
  898.                         printf("%5u ", hdr[j]->e_uid);
  899.                     if (Gflag)
  900.                         printf("%5u ", hdr[j]->e_gid);
  901.                     printf("%7ld\n",
  902.                         (hdr[j]->e_size+511L)/512L);
  903.                     }
  904.                     goto do_it_again;
  905.                 }
  906. #endif    /* STATS */
  907.             } else
  908.                 printf("%c %.*s", (con[j] ? '|' : ' '),
  909.                     Maxes[j], Spaces);
  910.         }
  911.         if (flag) {    /* start of directory, so leave a blank line */
  912.             printf(con[j] ? "|\n" : "\n");
  913.             flag = 0;
  914.             continue;
  915.         } else {
  916.                 /* normal file name, print it out */
  917.             if (l->e_name[CLength-1] != '-' &&
  918.                 l->e_name[CLength-1] != ' ')
  919.                 l->e_name[CLength-1] = '*';
  920.             printf("|-%.*s",Maxes[Level],l->e_name);
  921.             if (l->last) {
  922.                 con[j] = 0;
  923.             } else {
  924.                 con[j] = 1;
  925.             }
  926. #ifdef    STATS
  927.             if (Gflag || Longflg) {
  928.                 if (Compact) {
  929.                     printf(" %04o ", l->e_mode & 07777);
  930.                     if (Longflg)
  931.                         printf("%5u ", l->e_uid);
  932.                     if (Gflag)
  933.                         printf("%5u ", l->e_gid);
  934.                     printf("%7ld",
  935.                         (l->e_size+511L)/512L);
  936.                 } else {
  937.                     printf("%s ", getmode(l->e_mode));
  938.                     if (Longflg)
  939.                         printf("%8.8s ",guid(l->e_uid));
  940.                     if (Gflag)
  941.                         printf("%8.8s ",ggid(l->e_gid));
  942.                     printf("%7ld",
  943.                         (l->e_size+511L)/512L);
  944.                 }
  945.             }
  946. #endif    /* STATS */
  947.         }
  948.         printf("\n");
  949.  
  950.         if (l->last) {
  951.             /* walk back up */
  952.             while (l->last) {
  953.                 --Level;
  954.                 if (--top <= 0)
  955.                     return;
  956.                 l = stack[top];
  957.             }
  958.         }
  959.         l = &l[1];
  960.         ++count;
  961.     }
  962. }
  963.  
  964. #ifdef    STATS
  965.  
  966. char *
  967. guid(uid)
  968. short uid;
  969. {
  970.     static char tb[10];
  971.     struct passwd *pswd;
  972.  
  973.     pswd = getpwuid(uid);
  974.     if (pswd == NULL)
  975.         sprintf(tb,"%u", uid);
  976.     else
  977.         sprintf(tb, "%8s", pswd->pw_name);
  978.     return(tb);
  979. }
  980.  
  981. char *
  982. ggid(gid)
  983. short gid;
  984. {
  985.     static char tb[10];
  986.     struct group *grp;
  987.  
  988.     grp = getgrgid(gid);
  989.     if (grp == NULL)
  990.         sprintf(tb,"%u", gid);
  991.     else
  992.         sprintf(tb, "%8s", grp->gr_name);
  993.     return(tb);
  994. }
  995.  
  996. /* take the mode and make it into a nice character string */
  997.  
  998. char    *
  999. getmode(p_mode)
  1000. unsigned short p_mode;
  1001. {
  1002.     static char a_mode[16];
  1003.     register int    i = 0, j = 0;
  1004.  
  1005.     a_mode[j++] = ' ';
  1006.  
  1007.     switch (p_mode & S_IFMT) {
  1008. #ifdef S_IFLNK
  1009.     case S_IFLNK:
  1010.         a_mode[j++] = 'l';
  1011.         break;
  1012. #endif /* S_IFLNK */
  1013.     case S_IFDIR:
  1014.         a_mode[j++] = 'd';
  1015.         break;
  1016. #ifdef    S_IFMPC        /* defined in stat.h if you have MPX files */
  1017.     case S_IFMPC:
  1018.         a_mode[j-1] = 'm';
  1019.         /* FALL THROUGH */
  1020. #endif    /* S_IFMPC */
  1021.     case S_IFCHR:
  1022.         a_mode[j++] = 'c';
  1023.         break;
  1024. #ifdef    S_IFMPB        /* defined in stat.h if you have MPX files */
  1025.     case S_IFMPB:
  1026.         a_mode[j-1] = 'm';
  1027.         /* FALL THROUGH */
  1028. #endif    /* S_IFMPB */
  1029.     case S_IFBLK:
  1030.         a_mode[j++] = 'b';
  1031.         break;
  1032.     case S_IFREG:
  1033.     default:
  1034.         a_mode[j++] = (p_mode & S_ISVTX) ? 't' : ' ';
  1035.         break;
  1036.     }
  1037.     a_mode[j++] = ' ';
  1038.     for( i = 0;i<3;i++ ) {
  1039.         a_mode[j++] = (p_mode<<(3*i) & S_IREAD) ? 'r' : '-';
  1040.         a_mode[j++] = (p_mode<<(3*i) & S_IWRITE) ? 'w' : '-';
  1041.         a_mode[j++] = (i<2 && (p_mode<<i & S_ISUID)) ? 's' :
  1042.                   ((p_mode<<(3*i) & S_IEXEC ) ? 'x' : '-');
  1043.         a_mode[j++] = ' ';
  1044.     }
  1045.     a_mode[j] = '\0';
  1046.     return(a_mode);
  1047. }
  1048. #endif
  1049.  
  1050. /* like strlen, but returns length up to MAXNAMLEN-1 */
  1051. stln(st)
  1052. register char *st;
  1053. {
  1054.     register int t;
  1055.  
  1056.     for (t=0; t<MAXNAMLEN-1; ++t)
  1057.         if (!st[t])
  1058.             return (++t);
  1059.     return (++t);
  1060. }
  1061.  
  1062. print_date()
  1063. {
  1064.     long now;
  1065.  
  1066.     time(&now);
  1067.     printf ("%s", ctime(&now));
  1068. }
  1069.  
  1070. void
  1071. memory_out()
  1072. {
  1073.     fprintf(stderr, "xdtree: Virtual memory exhausted\n");
  1074.     exit(1);
  1075. }
  1076.  
  1077. /* Allocate `size' bytes of memory dynamically, with error checking.  */
  1078.  
  1079. char *
  1080. xmalloc (size)
  1081. unsigned size;
  1082. {
  1083.     char *ptr;
  1084.  
  1085.     ptr = malloc (size);
  1086.     if (ptr == 0 && size != 0)
  1087.         memory_out ();
  1088.     return ptr;
  1089. }
  1090.  
  1091. /* Change the size of an allocated block of memory `ptr' to `size' bytes,
  1092.    with error checking.
  1093.    If `ptr' is NULL, run xmalloc.
  1094.    If `size' is 0, run free and return NULL.  */
  1095.  
  1096. char *
  1097. xrealloc (ptr, size)
  1098. char *ptr;
  1099. unsigned size;
  1100. {
  1101.     if (ptr == 0)
  1102.         return xmalloc (size);
  1103.     if (size == 0) {
  1104.         free (ptr);
  1105.         return 0;
  1106.     }
  1107.     ptr = realloc (ptr, size);
  1108.     if (ptr == 0 && size != 0)
  1109.         memory_out ();
  1110.     return ptr;
  1111. }
  1112. /*-------------------------New functions for X windows -----------------*/
  1113.  
  1114. /* Main program to display the tree in an X window */
  1115.  
  1116. show_dtree(parent)
  1117.     Widget parent;
  1118.  
  1119. {
  1120.     Arg wargs[4];
  1121.     struct entry *stack[DEPTH], *branch;
  1122.     int n, top=0, *dir_index;
  1123.     int dir_node=0, dir_count=0, i;
  1124.     Widget parent_node=NULL, *Dir, arc;
  1125.     XmString label_s = NULL;    
  1126.  
  1127.     /* Find the number of directories */
  1128.     for(i=0; i < Index; i++)
  1129.         if(List[i].dir == 1) dir_count++;
  1130.  
  1131.     if((Dir = (Widget *) malloc( dir_count * sizeof(Widget))) == NULL){
  1132.         fprintf(stderr,"malloc failure\n");
  1133.             exit(1);
  1134.     }
  1135.     if((dir_index = (int *) malloc(dir_count * sizeof(int))) == NULL) {
  1136.         fprintf(stderr,"malloc failure\n");
  1137.         exit(1) ;
  1138.     }
  1139.  
  1140.     branch = &List[0];
  1141.  
  1142.     if(dir_count == 1 && branch->next == 0) {
  1143.         if(All == 0) {
  1144.         fprintf(stderr,"No subdirectories under directory %s\n",
  1145.              branch->e_name);
  1146.         fprintf(stderr,"You may want to try the -ap option\n");
  1147.         }
  1148.         else fprintf(stderr,"No files under directory %s\n", 
  1149.              branch->e_name);
  1150.         exit(0);
  1151.     }
  1152.  
  1153.     /* Distinguish between directories and files */
  1154.  
  1155.     for(;;)  {
  1156.         if(branch->dir != 0 && branch->next != 0) {
  1157.             dir_index[top] = dir_node;
  1158.             stack[top++] = branch;
  1159.             n=0;
  1160.             XtSetArg(wargs[n], XtNsuperNode,parent_node); n++;
  1161.             label_s = XmStringCreateLtoR(branch->e_name,
  1162.                                   XmSTRING_DEFAULT_CHARSET);
  1163.             XtSetArg(wargs[n], XmNlabelString,label_s); n++;
  1164.             Dir[dir_node] = XmCreatePushButton(parent,"dir",
  1165.                                     wargs,n);
  1166.             XtManageChild(Dir[dir_node]);
  1167.             XtAddCallback(Dir[dir_node],XmNactivateCallback,
  1168.                    clickB, branch);
  1169.  
  1170.             branch = &List[branch->next];
  1171.             parent_node = Dir[dir_node++];
  1172.             continue;
  1173.         }
  1174.         create_file_node(parent,branch,parent_node);
  1175.         if(branch->last) {
  1176.             while(branch->last) {
  1177.                 if(--top <= 0 ) {
  1178.                     free(Dir);
  1179.                     free(dir_index);
  1180.                     return;
  1181.                     }
  1182.                 branch = stack[top];
  1183.                 parent_node = Dir[dir_index[top-1]];
  1184.                 }
  1185.             }
  1186.         branch = &branch[1];
  1187.     }
  1188. }
  1189. /* Function that creates a widget for a node. Three types are available,
  1190.    dir, for directories , file, for files, and sym_link for
  1191.    symbolic links
  1192. */
  1193. create_file_node(pparent,bbranch,nnode)
  1194.     Widget pparent, nnode;
  1195.     struct entry *bbranch;
  1196. {
  1197.     Widget w, arc;
  1198.     Arg wargs[4];
  1199.     int n;
  1200.     char *win_type;
  1201.     XmString label_s = NULL;    
  1202.     int Gflag=1;        /* this is a gadget */
  1203.  
  1204.  
  1205.     n=0;
  1206.     label_s = XmStringCreateLtoR(bbranch->e_name,
  1207.                           XmSTRING_DEFAULT_CHARSET);
  1208.     XtSetArg(wargs[n], XmNlabelString,label_s); n++;
  1209.  
  1210.     /* Check the type of the node */
  1211.     if(bbranch->dir == 1) { 
  1212.         win_type = "dir";
  1213.         Gflag = 0;
  1214.     }
  1215. #ifdef STATS
  1216.     else if(strncmp(" l",getmode(bbranch->e_mode),2) == 0)
  1217.             {win_type = "sym_link"; Gflag = 0;}
  1218. #endif /* STATS */
  1219.     else win_type = "file";
  1220.         XtSetArg(wargs[n], XtNsuperNode, nnode); n++; 
  1221.     w = XmCreatePushButton(pparent, win_type, wargs, n);
  1222.     XtManageChild(w);
  1223.     XtAddCallback(w,XmNactivateCallback,clickB,bbranch);
  1224.  
  1225. }
  1226. /* Function that creates the pull-down menu when someone clicks on the 
  1227.   active node of the tree.  
  1228. */
  1229.  
  1230. show_menu(pparent, bbranch, top_widget)
  1231.     Widget pparent,top_widget;
  1232.     struct entry *bbranch;
  1233. {
  1234.     Widget menu ;
  1235.     Widget submenu_mode,submenu_print;
  1236.     Widget print, S_toggle,plabel,H_toggle,g_toggle;
  1237.     int i,n;
  1238.     char *mode_name;
  1239.     Arg  wargs[4];
  1240.     Arg  arg[15];
  1241.  
  1242.     n=0;
  1243.      XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
  1244.      XtSetArg(arg[n], XmNtopWidget, top_widget); n++;
  1245.     XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  1246.     submenu_mode = XtCreateManagedWidget("menu_file", 
  1247.                          xmRowColumnWidgetClass, pparent, arg,n);
  1248.  
  1249.         n=0;
  1250.     XtSetArg(arg[n], XmNleftWidget, submenu_mode); n++;
  1251.     XtSetArg(arg[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  1252.      XtSetArg(arg[n], XmNtopWidget, top_widget); n++;
  1253.     XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  1254.     submenu_file = XtCreateManagedWidget("menu_mode",
  1255.                             xmRowColumnWidgetClass, pparent, arg,n);
  1256.  
  1257.         n=0;
  1258.     XtSetArg(arg[n], XmNleftWidget, submenu_file); n++;
  1259.     XtSetArg(arg[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  1260.      XtSetArg(arg[n], XmNtopWidget, top_widget); n++;
  1261.     XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  1262.     submenu_dir = XtCreateManagedWidget("menu_dir",
  1263.                             xmRowColumnWidgetClass, pparent, arg,n);
  1264.  
  1265.         n=0;
  1266.     XtSetArg(arg[n], XmNleftWidget, submenu_dir); n++;
  1267.     XtSetArg(arg[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  1268.      XtSetArg(arg[n], XmNtopWidget, top_widget); n++;
  1269.     XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  1270.     submenu_print = XtCreateManagedWidget("printer",
  1271.                             xmRowColumnWidgetClass, pparent, arg,n);
  1272.  
  1273.     options = XtCreateManagedWidget("options",xmLabelWidgetClass,
  1274.            submenu_mode, wargs, 1);
  1275.     w_print(options, bbranch->e_name);
  1276.  
  1277.     plabel = XtCreateManagedWidget("plabel",xmLabelWidgetClass,
  1278.            submenu_print, wargs, 1);
  1279.     w_print(plabel, "Print-Tree Options");
  1280.     /*
  1281.     boxes[0] = XtCreateManagedWidget("title",xmLabelWidgetClass, 
  1282.            submenu_mode, NULL,0);
  1283.         */
  1284.     XtCreateManagedWidget("separator2",xmSeparatorWidgetClass, 
  1285.            submenu_mode, NULL,0);
  1286.     /*
  1287.     XtCreateManagedWidget("separator",xmSeparatorWidgetClass, 
  1288.            submenu_print, NULL,0);
  1289.         */
  1290. #ifdef STATS
  1291.     for(i = 1; i < 4 ; i++)
  1292.     boxes[i] =  XtCreateManagedWidget("id",xmLabelWidgetClass,
  1293.            submenu_mode, NULL,0);
  1294.     boxes[11] = XtCreateManagedWidget("id",xmLabelWidgetClass,
  1295.                submenu_mode, NULL,0);
  1296.     button_print(bbranch); /* print the labels on the menu */
  1297.         
  1298.     
  1299.  
  1300.     /* Create sub-menus */
  1301.  
  1302. #endif /*STATS */
  1303.  
  1304.     file_menu = XtCreateManagedWidget("File Options",
  1305.         xmLabelWidgetClass, submenu_file, NULL,0);
  1306.     dir_menu  = XtCreateManagedWidget("Directory Options",
  1307.         xmLabelWidgetClass, submenu_dir, NULL,0);
  1308.  
  1309.     /* If it is a file */
  1310.     /*submenu_file = XtCreateManagedWidget(menu, "filesubmenu", NULL, 0);*/
  1311.  
  1312.     boxes[4] = XtCreateManagedWidget("view",xmPushButtonWidgetClass,
  1313.                            submenu_file, NULL,0);
  1314.         XtAddCallback(boxes[4], XmNactivateCallback,view, NULL);
  1315.         boxes[5] = XtCreateManagedWidget("topview",
  1316.             xmPushButtonWidgetClass, submenu_file, NULL,0);
  1317.         XtAddCallback(boxes[5], XmNactivateCallback,view, NULL);
  1318.         boxes[6] = XtCreateManagedWidget("edit",
  1319.             xmPushButtonWidgetClass, submenu_file, NULL,0);
  1320.         XtAddCallback(boxes[6], XmNactivateCallback,do_menu, NULL);
  1321.         boxes[7] = XtCreateManagedWidget("print",
  1322.             xmPushButtonWidgetClass, submenu_file, NULL,0);
  1323.         XtAddCallback(boxes[7], XmNactivateCallback,do_menu, NULL);
  1324.  
  1325.     /* if it a directory */
  1326.         boxes[8] = XtCreateManagedWidget("show subtree",
  1327.             xmPushButtonWidgetClass, submenu_dir, NULL,0);
  1328.         XtAddCallback(boxes[8], XmNactivateCallback,do_menu, NULL);
  1329.         boxes[9] = XtCreateManagedWidget("list files",
  1330.             xmPushButtonWidgetClass, submenu_dir, NULL,0);
  1331.         XtAddCallback(boxes[9], XmNactivateCallback,do_menu, NULL);
  1332.         boxes[10] = XtCreateManagedWidget("list ../",
  1333.             xmPushButtonWidgetClass, submenu_dir, NULL,0);
  1334.         XtAddCallback(boxes[10], XmNactivateCallback,do_menu, NULL);
  1335.  
  1336.         /* print command */
  1337.         print = XtCreateManagedWidget("print tree",
  1338.                      xmPushButtonWidgetClass, submenu_print, NULL,0);
  1339.         XtAddCallback(print, XmNactivateCallback,print_tree, NULL);
  1340.  
  1341.         S_toggle = XtCreateManagedWidget("Print Stats. (-S)",
  1342.                      xmToggleButtonWidgetClass, submenu_print, NULL,0);
  1343.         XtAddCallback(S_toggle, XmNvalueChangedCallback,stoggle, NULL);
  1344.  
  1345.         H_toggle = XtCreateManagedWidget("Print Header (-H)",
  1346.                      xmToggleButtonWidgetClass, submenu_print, NULL,0);
  1347.         XtAddCallback(H_toggle, XmNvalueChangedCallback,htoggle, NULL);
  1348.  
  1349.         g_toggle = XtCreateManagedWidget("Use Group Name (-g)",
  1350.                      xmToggleButtonWidgetClass, submenu_print, NULL,0);
  1351.         XtAddCallback(g_toggle, XmNvalueChangedCallback,gtoggle, NULL);
  1352. }
  1353. /* Not used here, but may be useful in the future !!! */
  1354. /* Copied from D. Young's book */
  1355. /*
  1356. void post_menu_handler(w, menu, event)
  1357.     Widget w, menu;
  1358.     XEvent *event;
  1359. {
  1360.     Arg wargs[10];
  1361.     int button;
  1362.  
  1363.      XtSetArg(wargs[0], XmNwhichButton, &button); 
  1364.     XtGetValues(menu, wargs, 1);
  1365.         if(event->xbutton.button == button) {
  1366.         XmMenuPosition(menu, event);
  1367.         XtManageChild(menu);
  1368.         }
  1369. }
  1370. */
  1371. /* Quick and dirty way to view a file in a pop-up window 
  1372.    Speed may improve, if one reads and displays page by page
  1373.    No check to see if the file is binary
  1374. */
  1375. void view(w, call_mydata, call_data)
  1376.     Widget w;
  1377.     caddr_t call_data, call_mydata;
  1378.  
  1379. {
  1380.     struct entry *branch;
  1381.     char *filename[MAXPATHLEN+1];  
  1382.         struct stat statbuf;         /* Information on a file. */
  1383.         int file_length;             /* Length of file.        */
  1384.         unsigned char * file_string; /* Contents of file.      */
  1385.     FILE *fp = NULL;
  1386.     Widget text, toplevel2, sw2, button, frame, outer;
  1387.     Widget title;
  1388.     XmString name_string = NULL;
  1389.     char *button_name = NULL;
  1390.     int topflag=0;
  1391.     Arg    wargs[10];
  1392.     Arg     arg[10];
  1393.     int n=0;
  1394.  
  1395.     branch = file_pointer;
  1396.     /* find which button called us */
  1397.     XtSetArg(wargs[0], XmNlabelString, &name_string);
  1398.     XtGetValues(w,wargs,1);
  1399.     XmStringGetLtoR(name_string,XmSTRING_DEFAULT_CHARSET,&button_name);
  1400.     if(strcmp("topview",button_name) == 0) topflag = 1;
  1401.  
  1402.     /* find first the correct path */
  1403.  
  1404.     strncpy(filename,branch->path_name,MAXPATHLEN);
  1405.     strcat(filename,"/");
  1406.     strcat(filename,branch->e_name);
  1407.     
  1408.  
  1409.     if ((fp = fopen(filename, "r")) == NULL) {
  1410.         fprintf(stderr,"Can't open file name %s\n",filename);
  1411.         return;
  1412.     }
  1413.      if (stat(filename, &statbuf) == 0)
  1414.            file_length = statbuf.st_size;
  1415.          else
  1416.               file_length = 1000000; /* arbitrary file length */
  1417.  
  1418.      /* read the file string */
  1419.  
  1420.      if(topflag == 1 && file_length >= 2000 ) file_length = 2000;
  1421.  
  1422.      file_string = (unsigned char *) XtMalloc((unsigned)file_length);
  1423.          fread(file_string, sizeof(char), file_length, fp);
  1424.  
  1425.      if (fclose(fp) != NULL) fprintf(stderr, "Warning: unable to close file.\n");
  1426.  
  1427.     /* Create another pop-pup top-shell with a MainWindow */
  1428.  
  1429.     toplevel2 = XtCreateApplicationShell("Dtreef",topLevelShellWidgetClass,
  1430.              NULL,0);
  1431.  
  1432.     n=0;
  1433.     outer = XtCreateManagedWidget(NULL, xmFormWidgetClass,
  1434.                toplevel2, wargs, n);
  1435.  
  1436.     n=0;
  1437.     XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
  1438.     XtSetArg(arg[n], XmNtopAttachment, XmATTACH_FORM); n++;
  1439.     XtSetArg(arg[n], XmNlabelString, XmStringCreate("Quit",
  1440.                       XmSTRING_DEFAULT_CHARSET)); n++;
  1441.     button = XtCreateManagedWidget("button", xmPushButtonWidgetClass,
  1442.                                     outer, arg, n);
  1443.  
  1444.     XtAddCallback(button,XmNactivateCallback,quit_b_pop,toplevel2);
  1445.  
  1446.        n=0;
  1447.        XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
  1448.        XtSetArg(arg[n], XmNtopAttachment, XmATTACH_FORM); n++;
  1449.        XtSetArg(arg[n], XmNlabelString, XmStringCreate(filename, 
  1450.                    XmSTRING_DEFAULT_CHARSET)); n++;
  1451.       title = XtCreateManagedWidget("title",
  1452.                              xmLabelWidgetClass, outer, arg,n);
  1453.  
  1454.     n=0;
  1455.     XtSetArg(arg[n], XmNtopWidget, button); n++;
  1456.     XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  1457.         XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
  1458.     XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
  1459.     XtSetArg(arg[n], XmNshadowType, XmSHADOW_OUT); n++;
  1460.     XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  1461.     frame = XtCreateManagedWidget("frame", xmFrameWidgetClass, 
  1462.                    outer, arg,n);
  1463.  
  1464.     n=0;
  1465.     XtSetArg(wargs[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
  1466.     sw2 = XtCreateManagedWidget("swindowf",
  1467.         xmScrolledWindowWidgetClass,frame, wargs,n);
  1468.  
  1469.  
  1470.     /* Create Text widget */
  1471.     n=0;
  1472.     XtSetArg (wargs[n], XmNcolumns, 85); n++;
  1473.         XtSetArg (wargs[n], XmNeditable, FALSE); n++; 
  1474.  
  1475.     text = XmCreateText(sw2, "text", wargs, n);
  1476.  
  1477.     /* added the file string to the text widget */
  1478.  
  1479.        XmTextSetString(text, file_string);
  1480.         if(file_string != NULL) XtFree(file_string);
  1481.         if(name_string != NULL) XtFree(name_string);
  1482.  
  1483.     /* Poput the text file */
  1484.  
  1485.     XtPopup(toplevel2,XtGrabNone); 
  1486.     XtManageChild(text); 
  1487. }
  1488.  
  1489. /* CallBack function of the quit button on a pop-up window */
  1490.  
  1491. void quit_b_pop(w, topshell, call_data)
  1492.     Widget w;
  1493.     Widget topshell;
  1494.     caddr_t  call_data;
  1495. {
  1496.      XtPopdown(topshell);
  1497. }
  1498.  
  1499. /* function that forks a command from the menu */
  1500. /* Needs work!!!!!
  1501. */
  1502. void do_menu(w,call_mydata,call_data)
  1503.     Widget w;
  1504.     caddr_t call_data, call_mydata;
  1505.  
  1506. {
  1507.     struct entry *branch;
  1508.     char *filename[MAXPATHLEN+1];  
  1509.     char *topdir[MAXPATHLEN+1];
  1510.     XmString name_string = NULL;
  1511.