home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume32 / tbtree / part01 < prev    next >
Encoding:
Text File  |  1992-10-14  |  14.3 KB  |  428 lines

  1. Newsgroups: comp.sources.misc
  2. From: tombaker@world.std.com (Tom A Baker)
  3. Subject:  v32i097:  tbtree - Display directory tree, Part01/01
  4. Message-ID: <1992Oct7.212222.5517@sparky.imd.sterling.com>
  5. X-Md4-Signature: 3fb2c3c4399f1cdb7828649394fee486
  6. Date: Wed, 7 Oct 1992 21:22:22 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tombaker@world.std.com (Tom A Baker)
  10. Posting-number: Volume 32, Issue 97
  11. Archive-name: tbtree/part01
  12. Environment: SunOS
  13.  
  14. This is tbtree, a "tree" program for Unix. This program allows the
  15. user to get a visual idea of where things are on their system.
  16.                                    
  17. This runs on Sun machines.  As I comment within, try it on your
  18. Unix; you have nothing to lose, and it looks pretty portable.
  19.  
  20. Please see the README for more information.
  21.  
  22. If you improve it, please send me a copy.
  23. tombaker@world.std.com || tabaker@aol.com || BIX as tombaker
  24.  
  25. --------- cut here -----------
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then feed it
  28. # into a shell via "sh file" or similar.  To overwrite existing files,
  29. # type "sh file -c".
  30. # Contents:  README tbtree.c
  31. # Wrapped by kent@sparky on Wed Oct  7 16:12:59 1992
  32. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  33. echo If this archive is complete, you will see the following message:
  34. echo '          "shar: End of archive."'
  35. if test -f 'README' -a "${1}" != "-c" ; then 
  36.   echo shar: Will not clobber existing file \"'README'\"
  37. else
  38.   echo shar: Extracting \"'README'\" \(2350 characters\)
  39.   sed "s/^X//" >'README' <<'END_OF_FILE'
  40. XAN ORIGINAL POSTING was in response to a recent request in this group
  41. Xfor a "tree" program for Unix; a system manager wanted to get
  42. Xa visual idea of where things were on his/her new system.
  43. X                                   
  44. X[last minute note: Thanks for sending me your updates!  When I get a chance,
  45. X I'll try to integrate them and repost them. - tb]
  46. X
  47. X
  48. XCHANGES IN THIS POSTING:
  49. X
  50. X    1) In the case of a symbolic link that points to a file that
  51. X       does not exist (e.g., you create a linkfile "foo" that points
  52. X       to a file named "foobar", but then delete "foobar", leaving
  53. X       "foo"):
  54. X
  55. X       ORIGINAL VERSION:
  56. X            "Error on stat." would appear on standard error.
  57. X
  58. X       THIS VERSION:
  59. X            Nothing happens; tbtree recognizes the "Not There" error.
  60. X
  61. X    2) In the case of tbtree being invoked on, or descending into,
  62. X       a directory for which you have no "search" (or "execute")
  63. X       permissions.
  64. X
  65. X       ORIGINAL VERSION:
  66. X            "Error on stat." would appear on standard error.
  67. X            The directory is skipped.
  68. X
  69. X       THIS VERSION:
  70. X            "Error running stat() on xyzzy: No permission" (or an
  71. X            equivalent) would appear on standard error, as the
  72. X            system's "Print Error" ("perror()") function is used.
  73. X            (And where "xyzzy" is the directory's path.)
  74. X
  75. X            The directory is skipped.
  76. X
  77. X    3) As a result, errors in general for the stat() and lstat()
  78. X       calls are better reported.
  79. X
  80. X    4) EXTRA FEATURE:  If there is(are) a directory name which usually
  81. X       you can't stand descending into (say you have a whole extra hard
  82. X       disk mounted as a subdirectory in more than one place), you
  83. X       can "uncomment" a small block herein where I show how to hard-
  84. X       code a "prune".  Yes, it should be a command line option; but
  85. X       think about it ... if there is such a name on your system (there
  86. X       are three on mine) then you will know about it when you install
  87. X       this.
  88. X
  89. X       Do like I did: compile once as "tbtree", then install the prune
  90. X       and call it "tbtree_prune".  Or make it whatever way you like.
  91. X
  92. XThis has run on Sun machines.  As I comment within, try it on your
  93. XUnix; you have nothing to lose, and it looks pretty portable.
  94. X
  95. XIf you improve it, please send me a copy.
  96. Xtombaker@world.std.com || tabaker@aol.com || BIX as tombaker
  97. END_OF_FILE
  98.   if test 2350 -ne `wc -c <'README'`; then
  99.     echo shar: \"'README'\" unpacked with wrong size!
  100.   fi
  101.   # end of 'README'
  102. fi
  103. if test -f 'tbtree.c' -a "${1}" != "-c" ; then 
  104.   echo shar: Will not clobber existing file \"'tbtree.c'\"
  105. else
  106.   echo shar: Extracting \"'tbtree.c'\" \(9796 characters\)
  107.   sed "s/^X//" >'tbtree.c' <<'END_OF_FILE'
  108. X/*- tbtree - Graphical directory display. */
  109. X/*
  110. X *  Usage: tbtree [directory]
  111. X *
  112. X *  That command will give a "tree" drawing of the Unix sub-directories
  113. X *  below.  If no directory is specified, the current directory, ".",
  114. X *  is used.
  115. X */
  116. X/*
  117. X * This software is released to the public domain.  Please don't
  118. X * sell it for a million dollars profit without giving me some.
  119. X * Please leave my name and this credit in the code, or everyone
  120. X * on the planet will forget I exist, even before I die.  Besides,
  121. X * I know where you live.
  122. X *
  123. X * If you improve this program, please send me a copy.
  124. X * tombaker@world.std.com || tabaker@aol.com || BIX as tombaker  Oct 2, 1992
  125. X */
  126. X/*
  127. X * Install: Cut where it says.
  128. X *          Compile as
  129. X *                     % cc -o tbtree tbtree.c
  130. X */
  131. X/*
  132. X * 14-JUL-89 Original.
  133. X * 10-FEB-90 Changed the 'bugs' comment to a 'features' comment.
  134. X * 26-JUN-90 Fixed bug in which link names are not terminated correctly.
  135. X * 08-NOV-90 Prune of XYZZY hardwired into alternate version.
  136. X * 02-OCT-92 Cleaned up and posted in response to call for help over
  137. X *           the Net.
  138. X * 05-OCT-92 stat() and lstat() now properly report errors ("You have no
  139. X *           permission", "file no longer exists") verbosely,
  140. X *           AND stat() ignores symbolic links which point at nonexistent
  141. X *           files.
  142. X *           (Get it? I fix a bug, which I probably have known about since
  143. X *           the 1980's, three days AFTER I broadcast the source code to
  144. X *           the world.)
  145. X *
  146. X * Features:
  147. X *       Follows links.
  148. X *           It indicates links with a "->".
  149. X *           It DOES distinguish between a link to a file and one
  150. X *               to a subdirectory; only the latter get displayed.
  151. X *           It seems to follow circular links.  Eg., "xxx -> ./"
  152. X *       System errors in stat() and lstat() result in calls to
  153. X *            perror(), so a useful error message is provided.
  154. X *
  155. X * Bugs:
  156. X *       The opendir() call still has trouble with files which
  157. X *       are not directories; the "*UNREADABLE*" pruning results.
  158. X *
  159. X * Suggestions:
  160. X *       Some pruning is indicated:
  161. X *           Go only a specified number of levels down.
  162. X *       It is easy to lose track of what the lines point back UP to.
  163. X *       An interactive version would be appreciated.
  164. X *
  165. X *       The quick-and-dirty use of big, big arrays, instead of using
  166. X *       dynamic allocations or the system defines, was okay because
  167. X *       the swapper/pager can handle it and this is not that big a
  168. X *       deal of a program.  Guess I was tired that day, but it works.
  169. X *       (pleasenoflames: you don't like it, fix it)
  170. X *
  171. X * Notes:
  172. X *    STAT - In the case of a symbolic link that points to a file that
  173. X *        does not exist (e.g., you create a linkfile "foo" that points
  174. X *        to a file named "foobar", but then delete "foobar", leaving
  175. X *        "foo"), stat() returns an error flag, and sets the "errno" global
  176. X *        to ENOENT.  This is normal, so we ignore this as a special case.
  177. X *
  178. X *        Other system errors will thwart tbtree, and are reported.
  179. X *
  180. X *    This works on Sun workstations.  Try it on your version of Unix.
  181. X *    (If I could guarantee it would work, I'd charge you.)
  182. X *
  183. X *    The call to readlink() returns -1, and error = EINVAL if the
  184. X *    file being tested is not a link.  It returns the contents of
  185. X *    symlink in nonterminated string, and the return value is the
  186. X *    number of characters of the link name.
  187. X *
  188. X *    If a link is a hard link, that means there is no symbolic link.
  189. X *    This program just skips down the hard links like they aren't
  190. X *    there.
  191. X */
  192. X#include <stdio.h>
  193. X#include <sys/types.h>
  194. X#include <sys/stat.h>
  195. X#include <errno.h>
  196. X#include <string.h>
  197. X#include <dirent.h>
  198. X
  199. X#define FALSE        (0)
  200. X#define TRUE         (1)
  201. X
  202. X#define MAX_SUBS     (1000)
  203. X#define MAX_COMPS    (100)
  204. X#define MAX_COMP_LEN (100)
  205. X#define MAX_PATH     (MAX_COMPS*(MAX_COMP_LEN+1))
  206. X
  207. X/*-   DATA. */
  208. Xint   debug = FALSE;
  209. Xint   last_line_had_no_file = FALSE;
  210. X
  211. X/*-   MAIN() - Process args and start top directory. */
  212. Xmain(argc, argv)
  213. Xint    argc;
  214. Xchar **argv;
  215. X{
  216. X    switch( argc )
  217. X    {
  218. X    case 1:
  219. X        show( ".",     " " );
  220. X        break;
  221. X    case 2:
  222. X        show( argv[1], " " );
  223. X        break; 
  224. X    default:
  225. X        fprintf(stderr,"Usage: %s [directory].\n", argv[0]);
  226. X        break;
  227. X    }
  228. X}
  229. X
  230. X/*-   SHOW() - Display a directory and its subdirectories.  RECURSIVE. */
  231. Xshow( path,  prefix )
  232. Xchar *path, *prefix;
  233. X{
  234. X    char           *lastp;
  235. X    DIR            *dirp;
  236. X    struct dirent  *dp;
  237. X    struct stat     buf;
  238. X    char            newpath[MAX_PATH+1];
  239. X    char            newprefix[MAX_COMPS*4+1];
  240. X    int             num_subs = 0;
  241. X    char            darray[MAX_SUBS][MAX_COMP_LEN+1];
  242. X    int             i;
  243. X    int             symsize;
  244. X    char            sympath[MAX_PATH+1];
  245. X
  246. X    /*- Get the last component of directory name. */
  247. X    lastp=strrchr( path, '/' );
  248. X    if( lastp == NULL )
  249. X        lastp = path;
  250. X    else
  251. X        lastp++;
  252. X
  253. X    /*- Show last component of directory name. */
  254. X    printf("%s", lastp);
  255. X    last_line_had_no_file = FALSE;
  256. X
  257. X    /*- Prune dirs ONE TWO and THREE.
  258. X     * if(  (!strcmp(lastp,"ONE"))
  259. X     *   || (!strcmp(lastp,"TWO"))
  260. X     *   || (!strcmp(lastp,"THREE"))
  261. X     *   )
  262. X     * {
  263. X     *     if( strcmp(lastp, "THREE"))
  264. X     *         printf("  ");
  265. X     *     printf("\t*PRUNED*\n");
  266. X     *     last_line_had_no_file = FALSE;
  267. X     *     return;
  268. X     * }
  269. X     */
  270. X
  271. X    /*- Open directory. */
  272. X    if ((dirp = opendir(path)) == NULL)
  273. X    {
  274. X        /*- If can't (even after the above testing), yell and abort. */
  275. X        /*
  276. X         * The block below puts the message below the name.
  277. X         *            printf("\n");
  278. X         *            printf("%s|\n",prefix);
  279. X         *            printf("%s*UNREADABLE*\n", prefix );
  280. X         *            printf("%s\n", prefix );
  281. X         *            last_line_had_no_file = TRUE;
  282. X         * The block in use shoves it to the right, giving one line
  283. X         *     per unreadable directory, just like directories with no
  284. X         *     subdirectories.
  285. X         */
  286. X        printf("\t*UNREADABLE*\n");
  287. X        last_line_had_no_file = FALSE;
  288. X        return;
  289. X    }
  290. X    printf("\n");
  291. X
  292. X    /*- Read all entries. */
  293. X    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
  294. X    {
  295. X        /*- Skip directory entries '.' and '..' . */
  296. X        if (!strcmp(dp->d_name, "."))
  297. X            continue;
  298. X        if (!strcmp(dp->d_name, ".."))
  299. X            continue;
  300. X
  301. X        /*- If entry is a directory, */
  302. X        strcpy( newpath, path );
  303. X        strcat( newpath, "/"  );
  304. X        strcat( newpath, dp->d_name  );
  305. X                                     /* See note on "STAT" in file header. */
  306. X        if( stat(newpath,&buf) && errno!=ENOENT )
  307. X        {
  308. X            fprintf(stderr,"Error running stat() on \"%s\")",newpath);
  309. X            perror("");
  310. X        }
  311. X        if( (buf.st_mode&S_IFDIR) == S_IFDIR )
  312. X        {
  313. X            /*- Add it to array. */
  314. X            strcpy( darray[num_subs], dp->d_name );
  315. X            num_subs++;
  316. X        }
  317. X    }
  318. X
  319. X    /*- Close directory. */
  320. X    closedir(dirp);
  321. X
  322. X    /*- Call sub to sort the array, in place. */
  323. X    sort( num_subs, darray );
  324. X
  325. X    /*- Line above sub-directory. */
  326. X    if( num_subs )
  327. X        if( !last_line_had_no_file )
  328. X        {
  329. X            printf("%s|\n",prefix);
  330. X            last_line_had_no_file = TRUE;
  331. X        }
  332. X
  333. X    /*- For each sub-directory ... */
  334. X    for( i=0; i<num_subs; i++ )
  335. X    {
  336. X        /*- Prepare sub-directory's path. */
  337. X        strcpy( newpath, path );
  338. X        strcat( newpath, "/"  );
  339. X        strcat( newpath, darray[i] );
  340. X
  341. X        /*- Sub-direcory's prefix string depends on ... */
  342. X        if( (i+1) == num_subs )
  343. X        {
  344. X            /*- ... if sub-directory is last one ... */
  345. X            strcpy( newprefix, prefix );
  346. X            strcat( newprefix, "    "   );
  347. X        }
  348. X        else
  349. X        {
  350. X            /*- ... or not. */
  351. X            strcpy( newprefix, prefix );
  352. X            strcat( newprefix, "|   "   );
  353. X        }
  354. X
  355. X        /*- If sub-directory is a symbolic link, */
  356. X                                     /* See note on "STAT" in file header. */
  357. X        if( lstat(newpath,&buf) && errno!=ENOENT )
  358. X        {
  359. X            fprintf(stderr,"Error running lstat() on \"%s\")",newpath);
  360. X            perror("");
  361. X        }
  362. X        if( (buf.st_mode&S_IFLNK) == S_IFLNK )
  363. X        {
  364. X            /*- Get symbolic name as well. */
  365. X            if( (symsize=readlink(newpath,sympath,MAX_PATH)) < 0 )
  366. X            {
  367. X                fprintf(stderr,"Error on readlink.\n");
  368. X            }
  369. X
  370. X            if( (lastp=strchr(sympath, (int) ' ')) != NULL )
  371. X                *lastp = '\0';
  372. X
  373. X            sympath[symsize] = '\0';
  374. X            printf("%s+- %s -> %s\n",prefix,darray[i],sympath);
  375. X        }
  376. X        /*- Else, */
  377. X        else
  378. X        {
  379. X            /*- Recurse to show sub-directory. */
  380. X            printf("%s+- ",prefix);
  381. X            show( newpath, newprefix );
  382. X        }
  383. X    }
  384. X
  385. X    /*- Space below each directory. */
  386. X    if( num_subs )
  387. X        if( !last_line_had_no_file )
  388. X        {
  389. X            printf("%s\n",prefix);
  390. X            last_line_had_no_file = TRUE;
  391. X        }
  392. X
  393. X    /*- Done. */
  394. X}
  395. X
  396. X/*-   SORT() - Sort array in place. */
  397. Xsort( n, darray )
  398. Xint   n;
  399. Xchar     darray[MAX_SUBS][MAX_COMP_LEN+1];
  400. X{
  401. X    register int i, j;
  402. X    char         scratch[MAX_COMP_LEN+1];
  403. X
  404. X    /*- For each of the n-1 passes. */
  405. X    for( i=0; i<(n-1); i++ )
  406. X
  407. X        /*- For each of the lowest (n-1-pass) pairs. */
  408. X        for( j=0; j<(n-1-i); j++ )
  409. X
  410. X            /*- If the two are out of order. */
  411. X            if( strcmp( darray[j], darray[j+1] ) > 0 )
  412. X            {
  413. X                /*- Swap them. */
  414. X                strcpy( scratch,     darray[j]   );
  415. X                strcpy( darray[j],   darray[j+1] );
  416. X                strcpy( darray[j+1], scratch     );
  417. X            }
  418. X}
  419. END_OF_FILE
  420.   if test 9796 -ne `wc -c <'tbtree.c'`; then
  421.     echo shar: \"'tbtree.c'\" unpacked with wrong size!
  422.   fi
  423.   # end of 'tbtree.c'
  424. fi
  425. echo shar: End of archive.
  426. exit 0
  427. exit 0 # Just in case...
  428.