🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: de.comp.sources.unix
1 messages
1 total messages Started by Frank Kaefer Wed, 07 Oct 1992 18:16
v01i044: tbtree - graphical directory display, Part01/01
#18
Author: Frank Kaefer
Date: Wed, 07 Oct 1992 18:16
339 lines
12045 bytes
Submitted-by: tombaker@world.std.com (Tom A Baker)
Posting-number: Volume 1, Issue 44
Archive-name: tbtree/part01

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  tbtree.c
# Wrapped by fkk@stasys on Wed Oct  7 19:12:55 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive."'
if test -f 'tbtree.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tbtree.c'\"
else
  echo shar: Extracting \"'tbtree.c'\" \(9796 characters\)
  sed "s/^X//" >'tbtree.c' <<'END_OF_FILE'
X/*- tbtree - Graphical directory display. */
X/*
X *  Usage: tbtree [directory]
X *
X *  That command will give a "tree" drawing of the Unix sub-directories
X *  below.  If no directory is specified, the current directory, ".",
X *  is used.
X */
X/*
X * This software is released to the public domain.  Please don't
X * sell it for a million dollars profit without giving me some.
X * Please leave my name and this credit in the code, or everyone
X * on the planet will forget I exist, even before I die.  Besides,
X * I know where you live.
X *
X * If you improve this program, please send me a copy.
X * tombaker@world.std.com || tabaker@aol.com || BIX as tombaker  Oct 2, 1992
X */
X/*
X * Install: Cut where it says.
X *          Compile as
X *                     % cc -o tbtree tbtree.c
X */
X/*
X * 14-JUL-89 Original.
X * 10-FEB-90 Changed the 'bugs' comment to a 'features' comment.
X * 26-JUN-90 Fixed bug in which link names are not terminated correctly.
X * 08-NOV-90 Prune of XYZZY hardwired into alternate version.
X * 02-OCT-92 Cleaned up and posted in response to call for help over
X *           the Net.
X * 05-OCT-92 stat() and lstat() now properly report errors ("You have no
X *           permission", "file no longer exists") verbosely,
X *           AND stat() ignores symbolic links which point at nonexistent
X *           files.
X *           (Get it? I fix a bug, which I probably have known about since
X *           the 1980's, three days AFTER I broadcast the source code to
X *           the world.)
X *
X * Features:
X *       Follows links.
X *           It indicates links with a "->".
X *           It DOES distinguish between a link to a file and one
X *               to a subdirectory; only the latter get displayed.
X *           It seems to follow circular links.  Eg., "xxx -> ./"
X *       System errors in stat() and lstat() result in calls to
X *            perror(), so a useful error message is provided.
X *
X * Bugs:
X *       The opendir() call still has trouble with files which
X *       are not directories; the "*UNREADABLE*" pruning results.
X *
X * Suggestions:
X *       Some pruning is indicated:
X *           Go only a specified number of levels down.
X *       It is easy to lose track of what the lines point back UP to.
X *       An interactive version would be appreciated.
X *
X *       The quick-and-dirty use of big, big arrays, instead of using
X *       dynamic allocations or the system defines, was okay because
X *       the swapper/pager can handle it and this is not that big a
X *       deal of a program.  Guess I was tired that day, but it works.
X *       (pleasenoflames: you don't like it, fix it)
X *
X * Notes:
X *    STAT - In the case of a symbolic link that points to a file that
X *        does not exist (e.g., you create a linkfile "foo" that points
X *        to a file named "foobar", but then delete "foobar", leaving
X *        "foo"), stat() returns an error flag, and sets the "errno" global
X *        to ENOENT.  This is normal, so we ignore this as a special case.
X *
X *        Other system errors will thwart tbtree, and are reported.
X *
X *    This works on Sun workstations.  Try it on your version of Unix.
X *    (If I could guarantee it would work, I'd charge you.)
X *
X *    The call to readlink() returns -1, and error = EINVAL if the
X *    file being tested is not a link.  It returns the contents of
X *    symlink in nonterminated string, and the return value is the
X *    number of characters of the link name.
X *
X *    If a link is a hard link, that means there is no symbolic link.
X *    This program just skips down the hard links like they aren't
X *    there.
X */
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X#include <string.h>
X#include <dirent.h>
X
X#define FALSE        (0)
X#define TRUE         (1)
X
X#define MAX_SUBS     (1000)
X#define MAX_COMPS    (100)
X#define MAX_COMP_LEN (100)
X#define MAX_PATH     (MAX_COMPS*(MAX_COMP_LEN+1))
X
X/*-   DATA. */
Xint   debug = FALSE;
Xint   last_line_had_no_file = FALSE;
X
X/*-   MAIN() - Process args and start top directory. */
Xmain(argc, argv)
Xint    argc;
Xchar **argv;
X{
X    switch( argc )
X    {
X    case 1:
X        show( ".",     " " );
X        break;
X    case 2:
X        show( argv[1], " " );
X        break; 
X    default:
X        fprintf(stderr,"Usage: %s [directory].\n", argv[0]);
X        break;
X    }
X}
X
X/*-   SHOW() - Display a directory and its subdirectories.  RECURSIVE. */
Xshow( path,  prefix )
Xchar *path, *prefix;
X{
X    char           *lastp;
X    DIR            *dirp;
X    struct dirent  *dp;
X    struct stat     buf;
X    char            newpath[MAX_PATH+1];
X    char            newprefix[MAX_COMPS*4+1];
X    int             num_subs = 0;
X    char            darray[MAX_SUBS][MAX_COMP_LEN+1];
X    int             i;
X    int             symsize;
X    char            sympath[MAX_PATH+1];
X
X    /*- Get the last component of directory name. */
X    lastp=strrchr( path, '/' );
X    if( lastp == NULL )
X        lastp = path;
X    else
X        lastp++;
X
X    /*- Show last component of directory name. */
X    printf("%s", lastp);
X    last_line_had_no_file = FALSE;
X
X    /*- Prune dirs ONE TWO and THREE.
X     * if(  (!strcmp(lastp,"ONE"))
X     *   || (!strcmp(lastp,"TWO"))
X     *   || (!strcmp(lastp,"THREE"))
X     *   )
X     * {
X     *     if( strcmp(lastp, "THREE"))
X     *         printf("  ");
X     *     printf("\t*PRUNED*\n");
X     *     last_line_had_no_file = FALSE;
X     *     return;
X     * }
X     */
X
X    /*- Open directory. */
X    if ((dirp = opendir(path)) == NULL)
X    {
X        /*- If can't (even after the above testing), yell and abort. */
X        /*
X         * The block below puts the message below the name.
X         *            printf("\n");
X         *            printf("%s|\n",prefix);
X         *            printf("%s*UNREADABLE*\n", prefix );
X         *            printf("%s\n", prefix );
X         *            last_line_had_no_file = TRUE;
X         * The block in use shoves it to the right, giving one line
X         *     per unreadable directory, just like directories with no
X         *     subdirectories.
X         */
X        printf("\t*UNREADABLE*\n");
X        last_line_had_no_file = FALSE;
X        return;
X    }
X    printf("\n");
X
X    /*- Read all entries. */
X    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
X    {
X        /*- Skip directory entries '.' and '..' . */
X        if (!strcmp(dp->d_name, "."))
X            continue;
X        if (!strcmp(dp->d_name, ".."))
X            continue;
X
X        /*- If entry is a directory, */
X        strcpy( newpath, path );
X        strcat( newpath, "/"  );
X        strcat( newpath, dp->d_name  );
X                                     /* See note on "STAT" in file header. */
X        if( stat(newpath,&buf) && errno!=ENOENT )
X        {
X            fprintf(stderr,"Error running stat() on \"%s\")",newpath);
X            perror("");
X        }
X        if( (buf.st_mode&S_IFDIR) == S_IFDIR )
X        {
X            /*- Add it to array. */
X            strcpy( darray[num_subs], dp->d_name );
X            num_subs++;
X        }
X    }
X
X    /*- Close directory. */
X    closedir(dirp);
X
X    /*- Call sub to sort the array, in place. */
X    sort( num_subs, darray );
X
X    /*- Line above sub-directory. */
X    if( num_subs )
X        if( !last_line_had_no_file )
X        {
X            printf("%s|\n",prefix);
X            last_line_had_no_file = TRUE;
X        }
X
X    /*- For each sub-directory ... */
X    for( i=0; i<num_subs; i++ )
X    {
X        /*- Prepare sub-directory's path. */
X        strcpy( newpath, path );
X        strcat( newpath, "/"  );
X        strcat( newpath, darray[i] );
X
X        /*- Sub-direcory's prefix string depends on ... */
X        if( (i+1) == num_subs )
X        {
X            /*- ... if sub-directory is last one ... */
X            strcpy( newprefix, prefix );
X            strcat( newprefix, "    "   );
X        }
X        else
X        {
X            /*- ... or not. */
X            strcpy( newprefix, prefix );
X            strcat( newprefix, "|   "   );
X        }
X
X        /*- If sub-directory is a symbolic link, */
X                                     /* See note on "STAT" in file header. */
X        if( lstat(newpath,&buf) && errno!=ENOENT )
X        {
X            fprintf(stderr,"Error running lstat() on \"%s\")",newpath);
X            perror("");
X        }
X        if( (buf.st_mode&S_IFLNK) == S_IFLNK )
X        {
X            /*- Get symbolic name as well. */
X            if( (symsize=readlink(newpath,sympath,MAX_PATH)) < 0 )
X            {
X                fprintf(stderr,"Error on readlink.\n");
X            }
X
X            if( (lastp=strchr(sympath, (int) ' ')) != NULL )
X                *lastp = '\0';
X
X            sympath[symsize] = '\0';
X            printf("%s+- %s -> %s\n",prefix,darray[i],sympath);
X        }
X        /*- Else, */
X        else
X        {
X            /*- Recurse to show sub-directory. */
X            printf("%s+- ",prefix);
X            show( newpath, newprefix );
X        }
X    }
X
X    /*- Space below each directory. */
X    if( num_subs )
X        if( !last_line_had_no_file )
X        {
X            printf("%s\n",prefix);
X            last_line_had_no_file = TRUE;
X        }
X
X    /*- Done. */
X}
X
X/*-   SORT() - Sort array in place. */
Xsort( n, darray )
Xint   n;
Xchar     darray[MAX_SUBS][MAX_COMP_LEN+1];
X{
X    register int i, j;
X    char         scratch[MAX_COMP_LEN+1];
X
X    /*- For each of the n-1 passes. */
X    for( i=0; i<(n-1); i++ )
X
X        /*- For each of the lowest (n-1-pass) pairs. */
X        for( j=0; j<(n-1-i); j++ )
X
X            /*- If the two are out of order. */
X            if( strcmp( darray[j], darray[j+1] ) > 0 )
X            {
X                /*- Swap them. */
X                strcpy( scratch,     darray[j]   );
X                strcpy( darray[j],   darray[j+1] );
X                strcpy( darray[j+1], scratch     );
X            }
X}
END_OF_FILE
  if test 9796 -ne `wc -c <'tbtree.c'`; then
    echo shar: \"'tbtree.c'\" unpacked with wrong size!
  fi
  # end of 'tbtree.c'
fi
echo shar: End of archive.
exit 0
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads