v04i099: xf -- display a list of filenames, Part02/02
Dan Heller
argv at island.uu.net
Thu Sep 7 19:27:58 AEST 1989
Submitted-by: uunet!ucbvax.Berkeley.EDU!garys%earth.cchem.Berkeley.EDU (Gary Shea)
Posting-number: Volume 4, Issue 99
Archive-name: xf/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 2)."
# Contents: dir.c dir.h x.c
# Wrapped by garys at earth on Sat Aug 5 17:58:53 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'dir.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dir.c'\"
else
echo shar: Extracting \"'dir.c'\" \(26012 characters\)
sed "s/^X//" >'dir.c' <<'END_OF_FILE'
X/*
X * dir.c --
X *
X * Routines used to acquire file names and traverse the
X * directory tree.
X *
X * Copyright 1989 Regents of the University of California
X * Permission to use, copy, modify, and distribute this
X * software and its documentation for any purpose and without
X * fee is hereby granted, provided that the above copyright
X * notice appear in all copies. The University of California
X * makes no representations about the suitability of this
X * software for any purpose. It is provided "as is" without
X * express or implied warranty.
X *
X * Author: Gary Shea, UC Berkeley, Dept. of Chemistry
X */
X
Xstatic char rcsid[] = "$Header: dir.c,v 1.3 89/07/18 00:04:01 garys Exp $";
X
X#include <ctype.h>
X#include "xf.h"
X
X/* #define DEBUG */
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DecomposePath --
X *
X * Accept a path, return a list of pointers to char
X * with the various parts of the path in it. This should
X * work for both relative and absolute pathnames.
X *
X * Results:
X * A pointer to an array of pointers to char is returned.
X * The array is null-terminated.
X *
X * Side effects:
X * Space is allocated for the array.
X *
X * Arguments:
X * path - The path to take apart.
X * kind - By-reference parameter flags relative or absolute paths.
X * parts - Number of components in the path ('/' is a component).
X *
X *----------------------------------------------------------------------
X */
X
X#define VECTOR_INC 50
X#define START 0
X#define IN_DIR 1
X#define SEP 2
X
Xchar **
XDecomposePath( char *path, PathKind *kind, int *parts )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DecomposePath()" ;
X
X char pTempString[ MAXPATHLEN + 1 ] ;
X char *pCurString = pTempString ;
X int state ;
X
X char **pVector ;
X int vecLen ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X fprintf( pErrFp, "\tpath=<%s>\n", path ) ;
X#endif
X
X /* Skip leading white space. */
X
X while ( *path != '\0' && isspace( *path ) ) ++path ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\tPost-compression:\n" );
X fprintf( pErrFp, "\tpath=<%s>\n", path ) ;
X#endif
X
X /* Take it apart, mon...
X * The only important things to look for are "/" and '\0' .
X *
X * This thing will be a state-machine.
X * START : Nothing seen yet.
X * IN_DIR : Reading the name of a dir.
X * SEP : Just saw a separator.
X */
X
X *parts = 0 ;
X state = START ;
X pVector = (char **)0 ;
X vecLen = 0 ;
X
X for ( ; ; )
X {
X
X#ifdef DEBUG
X fprintf( pErrFp,
X "\tTop: strlen=%d, state=%d\n",
X pCurString - pTempString, state ) ;
X fprintf( pErrFp,
X "\tparts=%d, vecLen=%d\n",
X *parts, vecLen ) ;
X#endif
X
X switch( state )
X {
X case START :
X if ( *path == '/' )
X {
X char *sp ;
X
X /* It's an absolute path. */
X
X *kind = AbsPath ;
X
X /* Create the vector of string pointers. */
X
X vecLen = VECTOR_INC ;
X TestAndGrow( pVector, (*parts), vecLen, VECTOR_INC, char * ) ;
X sp = malloc( 2 ) ; sp[0] = '/' ; sp[1] = '\0' ;
X pVector[ (*parts)++ ] = sp ;
X pVector[ *parts ] = (char *) 0 ;
X
X#ifdef DEBUG
X fprintf( pErrFp,
X "\t\tabsPath: Fake string <%s>\n",
X pVector[ *parts - 1 ] ) ;
X#endif
X state = SEP ;
X ++path ;
X }
X else if ( *path == '\0' )
X {
X /* A null path. */
X
X UserError( "No path specified" );
X *kind = NoPath ;
X return ( NULL ) ;
X }
X else
X {
X /* A relative path. */
X
X *kind = RelPath ;
X state = IN_DIR ;
X
X /* Save this char. */
X
X pCurString = pTempString ;
X *(pCurString++) = *(path++) ;
X *pCurString = '\0' ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\t\tSTART: Initialized temp string ptr.\n" );
X#endif
X
X }
X break ;
X
X case IN_DIR :
X if ( *path == '/' || *path == '\0' )
X {
X char *sp ;
X
X /* We just completed a dir name. Allocate
X * a string for the currently completing dir
X * name, attach it to the list of names.
X */
X
X TestAndGrow( pVector, (*parts), vecLen, VECTOR_INC, char * ) ;
X pVector[ *parts ] =
X malloc( (unsigned)(pCurString - pTempString + 1) ) ;
X strcpy( pVector[ (*parts)++ ], pTempString ) ;
X TestAndGrow( pVector, (*parts), vecLen, VECTOR_INC, char * ) ;
X pVector[ *parts ] = (char *) 0 ;
X
X#ifdef DEBUG
X fprintf( pErrFp,
X "\t\tstrLen=%d, tempStr:<%s>, newStr:<%s>\n",
X pCurString - pTempString,
X pTempString,
X pVector[ *parts - 1 ] ) ;
X#endif
X
X if ( *path == '/' )
X {
X state = SEP ;
X ++path ;
X }
X else if ( *path == '\0' )
X return( pVector ) ;
X }
X else
X {
X /* More characters for this dir name. */
X
X if ( pCurString - pTempString + 2 >= MAXPATHLEN )
X {
X sprintf( errLine, "String too long (> %d)\n",
X MAXPATHLEN ) ;
X FatalError( pLocName, errLine );
X }
X
X *(pCurString++) = *(path++) ;
X *pCurString = '\0' ;
X
X#ifdef DEBUG
X /* I wanna look at the string, mon. */
X
X fprintf( pErrFp,
X "\t\tcurStr:<%s>, strLen:%d\n",
X pTempString, pCurString - pTempString + 1 ) ;
X#endif
X }
X break ;
X
X case SEP :
X if ( *path == '/' )
X {
X /* Just ignore this... */
X
X#ifdef DEBUG
X fprintf( pErrFp, "\t\tSEP: Ignoring a '/'.\n" );
X#endif
X
X ++path ;
X
X }
X else if ( *path == '\0' )
X {
X /* Now either the pathname is just '/',
X * or we're ending on a '/'. Ending on a '/'
X * is no big deal - just ignore it.
X * If the pathname is /, then let the calling
X * program figure out that nothing's coming.
X */
X
X#ifdef DEBUG
X fprintf( pErrFp, "\t\tSEP: End of string.\n" );
X#endif
X
X return( pVector ) ;
X }
X else
X {
X /* Starting a new dir name. */
X
X pCurString = pTempString ;
X *(pCurString++) = *(path++) ;
X *pCurString = '\0' ;
X state = IN_DIR ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\t\tSEP: Initialized temp string ptr.\n" );
X#endif
X }
X break ;
X
X }
X }
X
X#ifdef DEBUG
X fprintf( pErrFp, "\tEND: Shouldn't be here...\n" ) ;
X#endif
X
X FatalError ( pLocName, "Fell through loop" );
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_AddBranch --
X *
X * Given a valid subdirectory name and a DirTree,
X * add the subdirectory to the DirTree and fill out
X * all its stuff, and make the DirTree its root.
X * If the subdir exists, return a pointer to it.
X * In this sense, both '.' and '..' are subdir's.
X *
X * Results:
X * A pointer to the new DirTree is returned, or NULL
X * if it doesn't make sense.
X *
X * Side effects:
X * A new DirTree may be allocated and filled out,
X * also the branch list in the original DirTree may be
X * extended if necessary.
X *
X * Arguments:
X * trvPtr - DirTree struct to add name below.
X * index - Index to the name in the files[] array.
X *
X *----------------------------------------------------------------------
X */
X
XDirTree *
XDirTree_AddBranch( DirTree *trvPtr, int index )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_AddBranch()" ;
X
X int branchIdx ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X#endif
X
X /*
X * Is it really a subdirectory?
X */
X
X if ( ( trvPtr->files[ index ].statMode & S_GFMT) != S_GFDIR )
X {
X int err = 0 ;
X char *errString ;
X
X if ( (trvPtr->files[ index ].statMode & S_GFMT) == S_GFLNK )
X {
X char path[ MAXPATHLEN + 1 ] ;
X struct stat statBuf ;
X
X strcpy ( path, trvPtr->fullName ) ;
X strcat ( path, trvPtr->files[index].file ) ;
X if ( stat ( path, &statBuf ) != 0 )
X OSFatalError ( pLocName, "stat() failed" ) ;
X
X if ( (statBuf.st_mode & S_GFMT) != S_GFDIR )
X {
X errString = "Link to non-directory" ;
X ++err ;
X }
X }
X else
X {
X errString = "Not a directory" ;
X ++err ;
X }
X
X if ( err )
X {
X sprintf ( errLine,
X "%s%s: %s",
X trvPtr->relName != NULL ? trvPtr->relName : trvPtr->fullName,
X trvPtr->files[index].file,
X errString ) ;
X UserError ( errLine ) ;
X return ( NULL ) ;
X }
X }
X
X /*
X * Is it one of . or .. ?
X */
X
X if ( (trvPtr->files[ index ].file)[0] == '.' )
X {
X if ( (trvPtr->files[ index ].file)[1] == '\0' )
X return ( trvPtr ) ;
X else if ( (trvPtr->files[ index ].file)[1] == '.'
X && (trvPtr->files[ index ].file)[2] == '\0' )
X return ( trvPtr->rootPtr ) ;
X }
X
X /*
X * Has it ever been opened before?
X */
X
X for ( branchIdx = 0 ; branchIdx < trvPtr->branchCnt ; ++branchIdx )
X if ( trvPtr->branches[ branchIdx ].index == index )
X break ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\tbranchIdx=%d\n", branchIdx ) ;
X#endif
X
X if ( branchIdx >= trvPtr->branchCnt )
X {
X DirTree *newDirPtr ;
X char path[ MAXPATHLEN + 1 ] ;
X
X /*
X * It hasn't been opened yet.
X * Make a DirTree struct for this subdir and
X * try to get it filled out.
X */
X
X strcpy ( path, trvPtr->fullName ) ;
X strcat ( path, trvPtr->files[index].file ) ;
X strcat ( path, "/" ) ;
X newDirPtr = DirTree_PresetNew ( StrSave( trvPtr->files[index].file ),
X StrSave( path ), TRUE, trvPtr->dirLevel + 1 ) ;
X FillFilesList ( newDirPtr ) ;
X
X if ( newDirPtr->fileCnt <= 0 )
X {
X sprintf ( errLine,
X "%s%s: Directory is empty",
X trvPtr->relName != NULL ? trvPtr->relName : trvPtr->fullName,
X trvPtr->files[index].file ) ;
X UserError ( errLine ) ;
X return ( NULL ) ;
X }
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\tnewDirPtr:\n" ) ;
X DirTree_Dump( newDirPtr ) ;
X#endif
X
X /* Now add the new branch to the list. */
X
X TestAndGrow( trvPtr->branches, trvPtr->branchCnt,
X trvPtr->branchSlots, BRANCH_SLOT_INCREMENT, BranchData ) ;
X trvPtr->branches[ trvPtr->branchCnt ].index = index ;
X trvPtr->branches[ trvPtr->branchCnt ].branchPtr = newDirPtr ;
X newDirPtr->rootPtr = trvPtr ;
X
X#ifdef DEBUG1
X fprintf ( pErrFp, "\tdirRootPtr:\n" ) ;
X DirTree_TreeDump( dirRootPtr ) ;
X#endif
X
X branchIdx = trvPtr->branchCnt++ ;
X }
X
X return ( trvPtr->branches[ branchIdx ].branchPtr ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_Alloc --
X *
X * Allocate and return a pointer to a DirTree struct.
X *
X * Results:
X * A pointer to freshly-allocated memory is returned.
X *
X * Side effects:
X * The contents of the structure are initialized.
X * See DirTree_Init().
X *
X * Arguments:
X * None.
X *
X *----------------------------------------------------------------------
X */
X
XDirTree *
XDirTree_Alloc( void )
X{
X DirTree *dp ;
X
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_Alloc()" ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X
X if ( ( dp = (DirTree *) malloc( sizeof( DirTree ) ) ) == (DirTree *)0 )
X FatalError( pLocName, "Out of Memory" ) ;
X DirTree_Init( dp ) ;
X return( dp ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_CWD --
X *
X * Build a DirTree that is the current working directory.
X *
X * Results:
X * A pointer to the new DirTree is returned.
X *
X * Side effects:
X * Lots.
X *
X *----------------------------------------------------------------------
X */
X
Xvoid
XDirTree_CWD( void )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_CWD()" ;
X
X char *getwd() ;
X char path[ MAXPATHLEN + 1 ] ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X#endif
X
X /* Get the current direcory. */
X
X if ( getwd( path ) == NULL )
X {
X perror ( "getwd" ) ;
X exit ( 1 ) ;
X }
X
X /* Now build the tree... and set the global cwdPtr in the process. */
X
X if ( ( cwdPtr = DirTree_Find ( path )) == NULL )
X exit ( 1 ) ;
X
X /* Set up the initial relative path stuff. */
X
X cwdPtr->relName = StrSave( "" ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_ClientDump --
X *
X * DirTree-tree node-dump routine for use as a callup by
X * DirTree_TreeTrav().
X *
X * Results:
X * None.
X *
X * Side effects:
X * Some i/o is done.
X *
X * Arguments:
X * dirTreePtr - DirTree struct to dump.
X * clientData - Anonymous pointer to data that will be ignored.
X *
X *----------------------------------------------------------------------
X */
X
Xvoid
XDirTree_ClientDump( DirTree *dirTreePtr, void *clientData )
X{
X DirTree_Dump( dirTreePtr ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_Dump --
X *
X * Dump the contents of a DirTree struct to the err file.
X *
X * Results:
X * None.
X *
X * Side effects:
X * The err file fills with garbage.
X *
X * Arguments:
X * dirTreePtr - Pointer to a DirTree struct.
X *
X *----------------------------------------------------------------------
X */
X
Xvoid
XDirTree_Dump( DirTree *dirTreePtr )
X{
X int i, j ;
X
X
X if ( dirTreePtr == (DirTree *)0 )
X {
X fprintf( pErrFp, "\nDirTree_Dump: null dirTreePtr\n" ) ;
X return ;
X }
X
X fprintf( pErrFp, "\nDirTree_Dump: <%s> at 0x%x\n",
X dirTreePtr->name, dirTreePtr ) ;
X fprintf( pErrFp, "\tnormal=%s, fullName=<%s>\n",
X dirTreePtr ? "true" : "false",
X dirTreePtr->fullName ) ;
X
X fprintf( pErrFp, "\tfiles list: fileCnt=%d, fileSlots=%d\n",
X dirTreePtr->fileCnt, dirTreePtr->fileSlots ) ;
X for ( i = 0 ; i < dirTreePtr->fileCnt ; ++i )
X fprintf( pErrFp, "\t\t<%s>\n", dirTreePtr->files[ i ].file ) ;
X
X fprintf( pErrFp, "\trootPtr=0x%x, branchCnt=%d, branches=0x%x\n",
X dirTreePtr->rootPtr, dirTreePtr->branchCnt, dirTreePtr->branches ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_Find --
X *
X * Given a (possibly invalid) directory name,
X * attempt to find it in the tree. If it doesn't exist,
X * nodes are constructed as needed.
X *
X * Results:
X * A pointer to the DirTree which matches the path is returned.
X *
X * Side effects:
X * Lots.
X *
X * Arguments:
X * path - The argument should be a path.
X *
X *----------------------------------------------------------------------
X */
X
XDirTree *
XDirTree_Find( char *path )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_Find()" ;
X
X PathKind kind = NoPath ;
X char **strVec ;
X int isRoot = FALSE ;
X
X int parts ;
X int curPart ;
X
X DirTree *trvPtr = NULL ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X if ( ( strVec = DecomposePath ( path, &kind, &parts ) ) == (char **) 0 )
X return ( NULL ) ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\t%s:\n",
X kind == AbsPath
X ? "Absolute"
X : kind == RelPath ? "Relative" : "NoPath" ) ;
X#endif
X
X /* If it's an absolute path, make sure the tree exists,
X * set the first part as the next one after the '/',
X * and set the traversal to begin from the DirTree root.
X * If a relative path, set the traversal to begin from
X * the cwd.
X */
X
X if ( kind == AbsPath )
X {
X /* First make sure the tree exists. */
X
X if ( dirRootPtr == NULL )
X {
X dirRootPtr = DirTree_PresetNew ( "/", "/", TRUE, 0 ) ;
X FillFilesList ( dirRootPtr ) ;
X }
X
X /* Now step through the remaining fields, if any. */
X
X trvPtr = dirRootPtr ;
X curPart = 1 ;
X }
X else
X {
X if ( cwdPtr == NULL )
X InternalError ( pLocName, "cwdPtr not initialized" ) ;
X else
X {
X trvPtr = cwdPtr ;
X curPart = 0 ;
X }
X }
X
X for ( ; curPart < parts ; ++curPart )
X {
X DirTree *newDirPtr ;
X int fileIdx ;
X int branchIdx ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\tTop of loop: curPart=%d\n", curPart ) ;
X if ( trvPtr != NULL )
X {
X fprintf ( pErrFp, "\ttrvPtr:\n" ) ;
X DirTree_Dump( trvPtr ) ;
X }
X else
X fprintf ( pErrFp, "\ttrvPtr is NULL\n" ) ;
X#endif
X
X /* Do we have the files for this dir yet? */
X
X if ( trvPtr->fileCnt <= 0 )
X InternalError ( pLocName, "No files" ) ;
X
X /* Is the sub-dir we're looking for in here?
X * I agree that this is tacky, but it's how
X * i'm doing it anyway.
X */
X
X if ( strcmp ( strVec[curPart], "." ) == 0 )
X newDirPtr = trvPtr ;
X else if ( strcmp ( strVec[curPart], ".." ) == 0 )
X newDirPtr = trvPtr->rootPtr ;
X else
X {
X for ( fileIdx = 0 ; fileIdx < trvPtr->fileCnt ; ++fileIdx )
X {
X if ( strcmp ( strVec[curPart],
X trvPtr->files[fileIdx].file ) == 0 )
X break ;
X }
X
X if ( fileIdx >= trvPtr->fileCnt )
X {
X sprintf ( errLine, "%s: No such file or directory", path ) ;
X UserError ( errLine ) ;
X return ( NULL ) ;
X }
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\tfileIdx=%d\n", fileIdx ) ;
X#endif
X
X if ( ( newDirPtr = DirTree_AddBranch( trvPtr, fileIdx )) == NULL )
X return ( NULL ) ;
X }
X
X /* If a relative path was specified, then propagate
X * the relative path into the new directory. This
X * may well be duplicated effort, but the check for
X * length means you can't really mess things up
X * (i hope).
X */
X
X if ( kind == RelPath )
X {
X char path[ MAXPATHLEN + 1 ] ;
X
X
X if ( trvPtr->relName == NULL )
X InternalError ( pLocName, "relName NULL" ) ;
X
X strcpy ( path, trvPtr->relName ) ;
X strcat ( path, strVec[curPart] ) ;
X strcat ( path, "/" ) ;
X if ( newDirPtr->relName == NULL
X || ( newDirPtr->relName != NULL
X && strlen ( path ) < strlen ( newDirPtr->relName ) ) )
X newDirPtr->relName = StrSave( path ) ;
X }
X
X trvPtr = newDirPtr ;
X }
X
X return ( trvPtr ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_FindWidget --
X *
X * Search a tree of widgets for a particular one. Any
X * of the command widgets may be searched for by Widget id,
X * by specifying the appropriate member of WidgetToFind.
X *
X * Results:
X * A pointer to the DirTree struct holding the widget is
X * returned if the search succeeds, otherwise NULL.
X *
X * Side effects:
X * None.
X *
X *----------------------------------------------------------------------
X */
X
XDirTree *
XDirTree_FindWidget( DirTree *dirTreePtr, WidgetToFind kind, Widget w )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_FindWidget()" ;
X
X int i ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X#endif
X
X if ( dirTreePtr == (DirTree *)0 ) return ( NULL ) ;
X
X if ( dirTreePtr->isDisplayed )
X {
X Widget tw ;
X
X switch ( kind )
X {
X case SetW : tw = dirTreePtr->setW ; break ;
X case UpW : tw = dirTreePtr->upComW ; break ;
X case QuitW : tw = dirTreePtr->quitComW ; break ;
X case DoneW : tw = dirTreePtr->doneComW ; break ;
X }
X
X if ( tw == w )
X return ( dirTreePtr ) ;
X }
X
X /* Recursively search each of the sub-trees. */
X
X for ( i = 0 ; i < dirTreePtr->branchCnt ; ++i )
X {
X if ( dirTreePtr->branches[ i ].branchPtr != NULL )
X {
X DirTree *dtPtr ;
X
X if ( ( dtPtr =
X DirTree_FindWidget( dirTreePtr->branches[ i ].branchPtr,
X kind, w )) != NULL )
X return ( dtPtr ) ;
X }
X }
X
X return ( NULL ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_Init --
X *
X * Initialize a DirTree struct.
X *
X * Results:
X * None.
X *
X * Side effects:
X * The contents of the struct are modified.
X *
X * Arguments:
X * dp - Pointer to a DirTree struct.
X *
X *----------------------------------------------------------------------
X */
X
Xvoid
XDirTree_Init( DirTree *dp )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_Init()" ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X dp->name = NULL ;
X dp->fullName = NULL ;
X dp->relName = NULL ;
X dp->normal = FALSE ;
X
X dp->fileCnt = 0 ;
X dp->fileSlots = 0 ;
X dp->files = NULL ;
X
X dp->rootPtr = NULL ;
X dp->isDisplayed = FALSE ;
X
X dp->branchCnt = 0 ;
X dp->branchSlots = 0 ;
X dp->branches = NULL ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_PresetNew --
X *
X * A convenience routine to create, initialize and fill in
X * some of the more commonly used fields of a DirTree.
X *
X * Results:
X * Pointer to the newly allocated DirTree is returned.
X *
X * Side effects:
X * An DirTree is allocated, DirTree_Init is called on it, some of
X * its fields are modified based on the input parameters.
X *
X * Arguments:
X * namePtr - The name of the dirTree.
X * addr - Address in memory which the dirTree refers to.
X * status - Has the address been determined yet?
X *
X *----------------------------------------------------------------------
X */
X
XDirTree *
XDirTree_PresetNew( char *name, char *fullName, int normal, int dirLevel )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_PresetNew()" ;
X
X DirTree *dp ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X fprintf( pErrFp, "\tname=<%s>, fullName=<%s>, normal=%d\n",
X name, fullName, normal ) ;
X
X /* Test to see if the conditions on fullName are met. */
X { int len = strlen ( fullName ) ;
X if ( fullName [ len - 1 ] != '/' )
X InternalError ( pLocName, "fullName not '/'-terminated" ) ;
X }
X#endif
X
X dp = DirTree_Alloc() ;
X dp->name = name ;
X dp->fullName = fullName ;
X dp->normal = normal ;
X dp->dirLevel = dirLevel ;
X
X return( dp ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_TreeDump --
X *
X * Dump the contents of the DirTree tree with the
X * given root.
X *
X * Results:
X * None.
X *
X * Side effects:
X * More garbage in the err file.
X *
X * Arguments:
X * rootPtr - Root of a DirTree tree.
X *
X *----------------------------------------------------------------------
X */
X
Xvoid
XDirTree_TreeDump( DirTree *rootPtr )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_TreeDump()" ;
X
X
X fprintf( pErrFp, "\n%s:\n", pLocName );
X DirTree_TreeTrav( rootPtr, PreOrder, DirTree_ClientDump, (void *)0 ) ;
X fprintf( pErrFp, "END DirTree_TreeDump()\n" ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DirTree_TreeTrav --
X *
X * Traverse the DirTree_Tree,
X * calling the passed in function on each node as it is
X * visited. This is a structure-hiding routine - i hope
X * it's useful!!!.
X *
X * Results:
X * None.
X *
X * Side effects:
X * The passed in fcn gets called on every node of the tree.
X *
X * Arguments:
X * dirTreePtr - Pointer to the root of the tree.
X * travMode - Whether the traversal is InOrder, PreOrder, or PostOrder.
X * NodeOp - Function that will operate on the nodes.
X * clientData - Anonymous pointer to data used by NodeOp.
X *
X *----------------------------------------------------------------------
X */
X
Xvoid
XDirTree_TreeTrav( DirTree *dirTreePtr, TreeOrder travOrder,
X void NodeOp( DirTree *nodePtr, void *clientData ),
X void *clientData )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DirTree_TreeTrav()" ;
X
X int i ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X
X if ( dirTreePtr == (DirTree *)0 ) return ;
X
X if ( travOrder == PreOrder )
X NodeOp( dirTreePtr, clientData ) ;
X
X for ( i = 0 ; i < dirTreePtr->branchCnt ; ++i )
X if ( dirTreePtr->branches[ i ].branchPtr != (DirTree *)0 )
X DirTree_TreeTrav( dirTreePtr->branches[ i ].branchPtr,
X travOrder, NodeOp, clientData ) ;
X
X if ( travOrder == PostOrder )
X NodeOp( dirTreePtr, clientData ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * FileData_Compare --
X *
X * Compare two FileData structs by strcmp()-ing the file
X * fields. This is a qsort()-callable routine and is used
X * to sort the list of files.
X *
X * Results:
X * An integer less than zero is returned if leftPtr < rightPtr,
X * 0 if they are equal,
X * an integer greater than zero is returned if leftPtr > rightPtr.
X *
X * Side effects:
X * None.
X *
X * Arguments:
X * leftPtr - Pointer to a pointer to a FileData struct.
X * rightPtr - Pointer to a pointer to a FileData struct.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic int
XFileData_Compare( FileData *leftPtr, FileData *rightPtr )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "FileData_Compare()" ;
X
X# ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X# endif
X
X return ( strcmp ( leftPtr->file, rightPtr->file ) ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * FillFilesList --
X *
X * Given a DirTree with its fullName filled in,
X * fill in its files[] list.
X *
X * Results:
X * Currently returns True, or dies if there's an error.
X *
X * Side effects:
X * Mucho space is allocated for the filenames.
X *
X * Arguments:
X * trvPtr - The DirTree to fill in.
X *
X *----------------------------------------------------------------------
X */
X
Xint
XFillFilesList ( DirTree *trvPtr )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "FillFilesList()" ;
X
X DIR *dirFp ;
X DirEnt *entPtr ;
X char *sp ;
X
X char path[ MAXPATHLEN ] ;
X int pathLen ;
X
X struct stat statBuf ;
X
X static int FileData_Compare( FileData **leftPtr, FileData **rightPtr ) ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X /* First try to open the directory in which we are sitting. */
X
X if ( ( dirFp = opendir ( trvPtr->fullName ) ) == NULL )
X InternalError ( pLocName, "opendir() failed" ) ;
X
X /* Get ready for calling lsat by making a string to tack
X * file names onto the end of.
X */
X
X strcpy ( path, trvPtr->fullName ) ;
X pathLen = strlen ( path ) ;
X
X /* Now traverse the directory getting the files. */
X
X for ( entPtr = readdir( dirFp )
X ; entPtr != (DirEnt *)0
X ; entPtr = readdir( dirFp ) )
X {
X if ( !ls_mode_a && entPtr->d_name[ 0 ] == '.' ) continue ;
X
X /* Construct a path so that lstat() may be called. */
X
X path[ pathLen ] = '\0' ;
X strcat ( &path[pathLen], entPtr->d_name ) ;
X if ( lstat ( path, &statBuf ) != 0 )
X OSFatalError ( pLocName, "lstat() failed" ) ;
X
X /* Make sure there's someplace to put the (local) name. */
X
X TestAndGrow ( trvPtr->files, trvPtr->fileCnt,
X trvPtr->fileSlots, FILE_SLOT_INCREMENT, FileData ) ;
X
X trvPtr->files[ trvPtr->fileCnt ].file = StrSave ( entPtr->d_name ) ;
X trvPtr->files[ trvPtr->fileCnt ].statMode = statBuf.st_mode ;
X
X#ifdef DEBUG1
X fprintf ( pErrFp, "\t\t%d: <%s>, statMode=0%o\n",
X trvPtr->fileCnt,
X trvPtr->files[ trvPtr->fileCnt ].file,
X trvPtr->files[ trvPtr->fileCnt ].statMode ) ;
X#endif
X
X trvPtr->fileCnt++ ;
X }
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\t%s: DONE\n", pLocName ) ;
X#endif
X
X /* Sort the files, if there are any... */
X
X if ( trvPtr->fileCnt > 0 )
X qsort ( (char *) trvPtr->files, trvPtr->fileCnt,
X sizeof(FileData), FileData_Compare ) ;
X
X return( TRUE ) ;
X}
X
END_OF_FILE
if test 26012 -ne `wc -c <'dir.c'`; then
echo shar: \"'dir.c'\" unpacked with wrong size!
fi
# end of 'dir.c'
fi
if test -f 'dir.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dir.h'\"
else
echo shar: Extracting \"'dir.h'\" \(3459 characters\)
sed "s/^X//" >'dir.h' <<'END_OF_FILE'
X/*
X * dir.h --
X *
X * Declarations of procedures and structures that directly
X * apply to the DirTree.
X *
X * Copyright 1989 Regents of the University of California
X * Permission to use, copy, modify, and distribute this
X * software and its documentation for any purpose and without
X * fee is hereby granted, provided that the above copyright
X * notice appear in all copies. The University of California
X * makes no representations about the suitability of this
X * software for any purpose. It is provided "as is" without
X * express or implied warranty.
X *
X * Author: Gary Shea (garys at earth.cchem.berkeley.edu)
X *
X * $Header: dir.h,v 1.3 89/07/18 00:05:41 garys Exp $
X */
X
X#ifndef _dir_h
X#define _dir_h
X
X/* Two kinds of paths, relative and absolute. */
X
Xtypedef enum {
X RelPath, AbsPath, NoPath
X} PathKind ;
X
X/* The dirTree struct is used to build a literal
X* directory tree of selected files. This may not
X* be all that efficient, but it makes error checking
X* and traversal easy. The individual list element
X* contains window information for its directory.
X*/
X
X# define FILE_SLOT_INCREMENT 20
X# define BRANCH_SLOT_INCREMENT 5
X
Xtypedef u_short StatMode ;
Xtypedef struct _dirTree DirTree ;
Xtypedef struct _fileData FileData ;
Xtypedef struct _branchData BranchData ;
X
Xstruct _fileData
X{
X char *file ;
X StatMode statMode ;
X} ;
X
Xstruct _branchData
X{
X DirTree *branchPtr ;
X int index ;
X} ;
X
Xstruct _dirTree
X{
X char *name ; /* Name of this component of the path. */
X char *fullName ; /* Full path name. */
X char *relName ; /* Relative path name, if any. */
X int dirLevel ; /* 0 for root, increasing towards leaves. */
X int normal ; /* Picked => wanted when TRUE. */
X
X int fileCnt ; /* Number of files in the file list. */
X int fileSlots ; /* Number of slots allocated. */
X FileData *files ; /* File info for this directory. */
X
X Widget shellW ; /* Widget info. */
X Widget frameW ;
X Widget labelW ;
X Widget msgW ;
X Widget setW ;
X Widget upComW ;
X Widget quitComW ;
X Widget doneComW ;
X Widget fileComW ;
X int isDisplayed ; /* To prevent multiple displays. */
X
X XtSetDataStruct **setPtr ; /* The set data in the set widget. */
X
X DirTree *rootPtr ; /* Pointer to node up the tree. */
X
X int branchCnt ; /* Number of sub-dir's. */
X int branchSlots ; /* Slots for sub-dir's. */
X BranchData *branches ;
X} ;
X
Xtypedef enum {
X PreOrder, PostOrder
X} TreeOrder ;
X
Xtypedef enum {
X SetW, UpW, QuitW, DoneW
X} WidgetToFind ;
X
X/* procedures */
X
Xchar **DecomposePath( char *path, PathKind *kind, int *parts ) ;
XDirTree *DirTree_AddBranch( DirTree *trvPtr, int index ) ;
XDirTree *DirTree_Alloc( void ) ;
Xvoid DirTree_CWD( void ) ;
Xvoid DirTree_ClientDump( DirTree *dirTreePtr, void *clientData ) ;
Xvoid DirTree_Dump( DirTree *dirTreePtr ) ;
XDirTree *DirTree_Find( char *path ) ;
XDirTree *DirTree_FindWidget( DirTree *dirTreePtr,
X WidgetToFind kind, Widget w ) ;
XDirTree *DirTree_GrowFiles( DirTree *dtPtr, int inc ) ;
XDirTree *DirTree_GrowBranch( DirTree *dtPtr, int inc ) ;
Xvoid DirTree_Init( DirTree *dp ) ;
XDirTree *DirTree_PresetNew( char *name,
X char *fullName, int normal, int dirLevel ) ;
Xvoid DirTree_TreeDump( DirTree *rootPtr ) ;
Xvoid DirTree_TreeTrav( DirTree *dirTreePtr, TreeOrder travOrder,
X void NodeOp( DirTree *nodePtr, void *clientData ),
X void *clientData ) ;
Xint FillFilesList ( DirTree *trvPtr ) ;
X
X#endif /* _dir_h */
X
END_OF_FILE
if test 3459 -ne `wc -c <'dir.h'`; then
echo shar: \"'dir.h'\" unpacked with wrong size!
fi
# end of 'dir.h'
fi
if test -f 'x.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'x.c'\"
else
echo shar: Extracting \"'x.c'\" \(20993 characters\)
sed "s/^X//" >'x.c' <<'END_OF_FILE'
X/*
X * x.c --
X *
X * Routines that handle the window interface.
X *
X * Copyright 1989 Regents of the University of California
X * Permission to use, copy, modify, and distribute this
X * software and its documentation for any purpose and without
X * fee is hereby granted, provided that the above copyright
X * notice appear in all copies. The University of California
X * makes no representations about the suitability of this
X * software for any purpose. It is provided "as is" without
X * express or implied warranty.
X *
X * Author: Gary Shea, UC Berkeley, Dept. of Chemistry
X */
X
Xstatic char rcsid[] = "$Header: x.c,v 1.3 89/07/18 00:04:39 garys Exp $";
X
X#include "xf.h"
X
X/* Local declarations. */
X
Xstatic void BuildDialogBox( void ) ;
X
Xstatic XtSetDataStruct **BuildSetData( DirTree *dirPtr ) ;
X
Xstatic void ConfirmButtonPushed( Widget w,
X caddr_t client_data, caddr_t call_data ) ;
Xstatic void DoneButtonPushed( Widget w,
X caddr_t client_data, caddr_t call_data ) ;
Xstatic void EnterFileName( Widget w,
X caddr_t client_data, caddr_t call_data ) ;
Xstatic void OpenDirDown( Widget w,
X caddr_t client_data, caddr_t call_data ) ;
Xstatic void OutputFileNames( DirTree *dirTreePtr,
X void *clientData ) ;
Xstatic void QuitButtonPushed( Widget w,
X caddr_t client_data, caddr_t call_data ) ;
Xstatic void UpButtonPushed( Widget w,
X caddr_t client_data, caddr_t call_data ) ;
X
X/* Information about the dialog box where file names are entered. */
X
Xstatic struct
X{
X Widget shellW ;
X Widget dialogW ;
X Widget textW ;
X Widget labelW ;
X Widget confComW ;
X char fileName[ MAXPATHLEN + 1 ] ;
X}
XdialogBox ;
X
X
X/*
X *----------------------------------------------------------------------
X *
X * BuildDialogBox --
X *
X * Create (realize but don't display) the dialog box that
X * the user can enter a filename into. It is displayed
X * when XtPopup is called.
X *
X * Results:
X * None.
X *
X * Side effects:
X * A shell widget and dialog box are instantiated, but not displayed.
X *
X * Arguments:
X * None.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XBuildDialogBox( void )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "BuildDialogBox()" ;
X
X int n ;
X Arg args[ 10 ] ;
X
X XtCallbackRec callbacks[ 5 ] = { {NULL,NULL}, {NULL,NULL} } ;
X
X char *label =
X "Enter File Name " ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X#endif
X
X /* Make a pop up shell to hold the mess. */
X
X dialogBox.shellW = XtCreatePopupShell ( "Enter Directory Name",
X applicationShellWidgetClass, topLevelW, NULL, 0 ) ;
X
X /* Make the Dialog widget that will get popped up.
X * Be sure the fileName string is blank initially.
X */
X
X strcpy ( dialogBox.fileName, "" ) ;
X
X n = 0 ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNlabel, label ) ; ++n ;
X XtSetArg( args[n], XtNmaximumLength, MAXPATHLEN ) ; ++n ;
X#endif
X XtSetArg( args[n], XtNvalue, dialogBox.fileName ) ; ++n ;
X dialogBox.dialogW = XtCreateManagedWidget ( "dialog", dialogWidgetClass,
X dialogBox.shellW, args, n ) ;
X
X /* Find the id of the Text widget holding the string. */
X
X dialogBox.textW = XtNameToWidget ( dialogBox.dialogW, "value" ) ;
X dialogBox.labelW = XtNameToWidget ( dialogBox.dialogW, "label" ) ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\tdialogW=%d, textW=%d, labelW=%d\n",
X dialogBox.dialogW, dialogBox.textW, dialogBox.labelW ) ;
X#endif
X
X callbacks[0].callback = ConfirmButtonPushed ;
X n = 0 ;
X XtSetArg( args[n], XtNcallback, callbacks ) ; ++n ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNlabel, "Confirm" ) ; ++n ;
X#endif
X dialogBox.confComW = XtCreateManagedWidget ( "confirm", commandWidgetClass,
X dialogBox.dialogW, args, n ) ;
X callbacks[0].callback = NULL ;
X
X /* Allow the user to short-circuit the stupid Dialog widget. */
X
X XtInstallAccelerators ( dialogBox.textW, dialogBox.confComW );
X XtRealizeWidget ( dialogBox.shellW ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * BuildDirBox --
X *
X * Make the widget-conglomerate that will display one dir's
X * information.
X *
X * Results:
X * The id of the applicationShellWidget that holds everything.
X *
X * Side effects:
X * Lots.
X *
X * Arguments:
X * dirPtr - DirTree that holds this dir box's info.
X *
X *----------------------------------------------------------------------
X */
X
XWidget
XBuildDirBox( DirTree *dirPtr )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "BuildDirBox()" ;
X
X int n ;
X Arg args[ 10 ] ;
X XtCallbackRec callbacks[ 5 ] = { {NULL,NULL}, {NULL,NULL} } ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X /* Make a pop up shell to hold the mess. */
X
X dirPtr->shellW = XtCreatePopupShell ( StrSave( dirPtr->fullName ),
X applicationShellWidgetClass, topLevelW, NULL, 0 ) ;
X
X /* Make the Frame widget that will hold everyone. */
X
X dirPtr->frameW = XtCreateManagedWidget ( "form", formWidgetClass,
X dirPtr->shellW, NULL, 0 ) ;
X
X /* Make the Label for the top. */
X
X n = 0 ;
X XtSetArg( args[n], XtNlabel, dirPtr->fullName ) ; ++n ;
X dirPtr->labelW = XtCreateManagedWidget ( "label", labelWidgetClass,
X dirPtr->frameW, args, n ) ;
X
X /* Make the Set to put in the middle. First get the
X * set of stuff to put in it.
X */
X
X if ( ( dirPtr->setPtr = BuildSetData( dirPtr ) ) == NULL )
X FatalError ( pLocName, "Null BuildSetData()" ) ;
X
X callbacks[0].callback = OpenDirDown ;
X n = 0 ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNdefaultColumns, 5 ) ; ++n ;
X XtSetArg( args[n], XtNcolumnSpacing, 20 ) ; ++n ;
X XtSetArg( args[n], XtNfromVert, dirPtr->labelW ) ; ++n ;
X#endif
X XtSetArg( args[n], XtNset, dirPtr->setPtr ) ; ++n ;
X XtSetArg( args[n], XtNnumberStrings, dirPtr->fileCnt ) ; ++n ;
X XtSetArg( args[n], XtNcallbackB, callbacks ) ; ++n ;
X dirPtr->setW = XtCreateManagedWidget ( "set", setWidgetClass,
X dirPtr->frameW, args, n ) ;
X callbacks[0].callback = NULL ;
X
X /* Make the Up button on the far left. */
X
X callbacks[0].callback = UpButtonPushed ;
X n = 0 ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNlabel, "Up" ) ; ++n ;
X XtSetArg( args[n], XtNfromVert, dirPtr->setW ) ; ++n ;
X XtSetArg( args[n], XtNleft, XtChainLeft ) ; ++n ;
X XtSetArg( args[n], XtNright, XtChainLeft ) ; ++n ;
X#endif
X XtSetArg( args[n], XtNcallback, callbacks ) ; ++n ;
X dirPtr->upComW = XtCreateManagedWidget ( "up", commandWidgetClass,
X dirPtr->frameW, args, n ) ;
X callbacks[0].callback = NULL ;
X
X /* Put the Quit button in the middle. */
X
X callbacks[0].callback = QuitButtonPushed ;
X n = 0 ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNlabel, "Quit" ) ; ++n ;
X XtSetArg( args[n], XtNfromVert, dirPtr->setW ) ; ++n ;
X XtSetArg( args[n], XtNfromHoriz, dirPtr->upComW ) ; ++n ;
X XtSetArg( args[n], XtNleft, XtChainLeft ) ; ++n ;
X XtSetArg( args[n], XtNright, XtChainRight ) ; ++n ;
X#endif
X XtSetArg( args[n], XtNcallback, callbacks ) ; ++n ;
X dirPtr->quitComW = XtCreateManagedWidget ( "quit", commandWidgetClass,
X dirPtr->frameW, args, n ) ;
X callbacks[0].callback = NULL ;
X
X /* Put the Done button in the middle too. */
X
X callbacks[0].callback = DoneButtonPushed ;
X n = 0 ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNlabel, "Done" ) ; ++n ;
X XtSetArg( args[n], XtNfromVert, dirPtr->setW ) ; ++n ;
X XtSetArg( args[n], XtNfromHoriz, dirPtr->quitComW ) ; ++n ;
X XtSetArg( args[n], XtNleft, XtChainLeft ) ; ++n ;
X XtSetArg( args[n], XtNright, XtChainRight ) ; ++n ;
X#endif
X XtSetArg( args[n], XtNcallback, callbacks ) ; ++n ;
X dirPtr->doneComW = XtCreateManagedWidget ( "done", commandWidgetClass,
X dirPtr->frameW, args, n ) ;
X callbacks[0].callback = NULL ;
X
X /* Put the fileName button to the right. */
X
X callbacks[0].callback = EnterFileName ;
X n = 0 ;
X#ifdef NOAPPDEFAULTS
X XtSetArg( args[n], XtNlabel, "Enter Filename" ) ; ++n ;
X XtSetArg( args[n], XtNfromVert, dirPtr->setW ) ; ++n ;
X XtSetArg( args[n], XtNfromHoriz, dirPtr->doneComW ) ; ++n ;
X XtSetArg( args[n], XtNleft, XtChainRight ) ; ++n ;
X XtSetArg( args[n], XtNright, XtChainRight ) ; ++n ;
X#endif
X XtSetArg( args[n], XtNcallback, callbacks ) ; ++n ;
X dirPtr->fileComW = XtCreateManagedWidget ( "dir_name", commandWidgetClass,
X dirPtr->frameW, args, n ) ;
X callbacks[0].callback = NULL ;
X
X XtPopup ( dirPtr->shellW, XtGrabNone ) ;
X dirPtr->isDisplayed = TRUE ;
X
X return( dirPtr->shellW ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * BuildSetData --
X *
X * Given a pointer to a DirTree struct, use its files and
X * stat info to build and initialize the XtSetDataStruct
X * array used by the Set widget.
X *
X * Results:
X * A pointer to the newly created array of XtSetDataStruct *.
X *
X * Side effects:
X * Space is allocated, strings are copied into new space,
X * the entries of the XtSetDataStruct array are initialized.
X *
X * Arguments:
X * dirPtr - Pointer to the dir struct to do this for.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic XtSetDataStruct **
XBuildSetData( DirTree *dirPtr )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "BuildSetData()" ;
X
X int i ;
X XtSetDataStruct **setPtr ;
X char s[ BUFSIZ ] ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s: in <%s>\n",
X pLocName, dirPtr->name );
X#endif
X
X /* First make sure there are some files to do this for...
X * This could be kind of weird.
X */
X
X if ( dirPtr->fileCnt == 0 )
X return ( NULL ) ;
X
X /* Make the basic array of XtSetDataStruct pointers. */
X
X if ( ( setPtr = (XtSetDataStruct **)
X calloc ( dirPtr->fileCnt, sizeof (XtSetDataStruct *)) ) == NULL )
X FatalError( pLocName, "Out of Memory (calloc)" ) ;
X
X /* For each filename, build the XtSetDataStruct and make the
X * string to be displayed... for now assume that the -F stuff
X * is desired...
X */
X
X for ( i = 0 ; i < dirPtr->fileCnt ; ++i )
X {
X XtSetDataStruct *aPtr ;
X
X if ( ( aPtr = (XtSetDataStruct *)
X malloc (sizeof (XtSetDataStruct)) ) == NULL )
X FatalError( pLocName, "out of memory" ) ;
X
X strcpy ( s, dirPtr->files[ i ].file ) ;
X if ( (dirPtr->files[ i ].statMode & S_GFMT) == S_GFDIR )
X strcat ( s, "/" ) ;
X else if ( (dirPtr->files[ i ].statMode & S_GFMT) == S_GFLNK)
X strcat ( s, "@" ) ;
X else if ( (dirPtr->files[ i ].statMode & S_GFMT) == S_GFSOCK)
X strcat ( s, "=" ) ;
X else if ( dirPtr->files[ i ].statMode & S_IXUSR
X || dirPtr->files[ i ].statMode & S_IXGRP
X || dirPtr->files[ i ].statMode & S_IXOTH )
X strcat ( s, "*" ) ;
X
X aPtr->string = StrSave( s ) ;
X aPtr->is_lit = FALSE ;
X
X setPtr[ i ] = aPtr ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\t\t%d: <%s>, is_lit=%d\n",
X i, setPtr[i]->string, setPtr[i]->is_lit ) ;
X#endif
X
X }
X
X return ( setPtr ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * ConfirmButtonPushed --
X *
X * Callback for pressing the Confirm button on the
X * filename popup.
X *
X * Results:
X * None.
X *
X * Side effects:
X * Opens a window for the input pathname, if possible.
X *
X * Arguments:
X * w - The calling widget's id.
X * client_data - Null, since no data passed to callback list.
X * call_data - Undefined by the Command widget.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XConfirmButtonPushed( Widget w, caddr_t client_data, caddr_t call_data )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "PopupConfirm()" ;
X
X char *fileNamePtr ;
X DirTree *dtPtr ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X#endif
X
X /* Get the contents of the filename string. */
X
X if ( ( fileNamePtr
X = XtDialogGetValueString ( dialogBox.dialogW ))
X == NULL )
X InternalError ( pLocName,
X "Null string from XtDialogGetValueString" ) ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\t<%s>\n", fileNamePtr ) ;
X#endif
X
X /* Have the directory tree expand as necessary. */
X
X if ( ( dtPtr = DirTree_Find ( fileNamePtr ) ) == NULL )
X return ;
X
X /* Arrange for this directory to be displayed. */
X
X if ( ! dtPtr->isDisplayed )
X BuildDirBox ( dtPtr ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * DoneButtonPushed --
X *
X * The callback for the Done button. The stored-up
X * selections are all output, and the program terminates.
X *
X * Results:
X * None.
X *
X * Side effects:
X * Output is done to the stdio, all X resources
X * are released, the program exits.
X *
X * Arguments:
X * w - The calling widget's id.
X * client_data - Null, since no data passed to callback list.
X * call_data - Undefined by the Command widget.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XDoneButtonPushed( Widget w, caddr_t client_data, caddr_t call_data )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "DoneButtonPushed()" ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X /* Have the names dumped to the stdout. */
X
X DirTree_TreeTrav ( dirRootPtr, PostOrder, OutputFileNames, NULL ) ;
X
X /* We're done, close up shop. */
X
X XtDestroyApplicationContext ( appContext ) ;
X exit ( 0 ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * EnterFileName --
X *
X * Called when the "Enter File Name" button is pushed on
X * the dirbox. Pops up the dialog widget. This is the
X * only place where the dialog widget is manipulated.
X *
X * Results:
X * None.
X *
X * Side effects:
X * The dialog widget is constructed and popped up.
X *
X * Arguments:
X * w - The calling widget's id.
X * client_data - Null, since no data passed to callback list.
X * call_data - Undefined by the Command widget.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XEnterFileName( Widget w, caddr_t client_data, caddr_t call_data )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "EnterFileName()" ;
X
X static int boxBuilt = FALSE ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X#endif
X
X if ( ! boxBuilt )
X {
X boxBuilt = TRUE ;
X BuildDialogBox() ;
X XtPopup ( dialogBox.shellW, XtGrabNone ) ;
X }
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * OpenDirDown --
X *
X * A button has been pushed that is to be interpreted
X * as a request to open the selected item as a directory.
X * This routine makes an honest effort to do so.
X *
X * Results:
X * None.
X *
X * Side effects:
X * With any luck a popup is made to display the directory.
X *
X * Arguments:
X * w - The calling widget's id.
X * client_data - Null, since no data passed to callback list.
X * call_data - XtSetReturnStruct *.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XOpenDirDown( Widget w, caddr_t client_data, caddr_t call_data )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "OpenDirDown()" ;
X
X DirTree *dtPtr, *newDirPtr ;
X char path[ MAXPATHLEN ] ;
X int branchIdx ;
X
X XtSetReturnStruct *retPtr = (XtSetReturnStruct *) call_data ;
X
X
X /* First find the DirTree struct this happened in. */
X
X if ( ( dtPtr = DirTree_FindWidget ( dirRootPtr, SetW, w )) == NULL )
X InternalError ( pLocName, "Searching for the Set widget" ) ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s:\n", pLocName ) ;
X fprintf ( pErrFp, "\tstring=<%s>, index=%d\n",
X retPtr->string, retPtr->index ) ;
X#endif
X
X /* If it's not a subdirectory, just do nothing. */
X
X if ( ( newDirPtr = DirTree_AddBranch( dtPtr, retPtr->index )) == NULL )
X return ;
X
X /* If there's a relative path name for the directory we're
X * going down from, then construct one for the directory we're
X * going down to. This keeps all 'local' references local, and
X * will be used to generate the names at 'done' time.
X */
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\trelName=0x%x\n", dtPtr->relName ) ;
X#endif
X
X if ( dtPtr->relName != NULL )
X {
X char path[ MAXPATHLEN + 1 ] ;
X
X strcpy ( path, dtPtr->relName ) ;
X strcat ( path, dtPtr->files[ retPtr->index ].file ) ;
X strcat ( path, "/" ) ;
X if ( newDirPtr->relName == NULL
X || ( newDirPtr->relName != NULL
X && strlen ( path ) < strlen ( newDirPtr->relName ) ) )
X newDirPtr->relName = StrSave( path ) ;
X }
X
X /* If it isn't being displayed already, then make
X * it show up.
X */
X
X if ( ! newDirPtr->isDisplayed ) BuildDirBox ( newDirPtr ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * OutputFileNames --
X *
X * Client routine of DirTree_TreeTrav(), this routine takes
X * a DirTree struct and outputs the names of the selected files
X * to stdout, with format depending on the availability of relName.
X *
X * Results:
X * None.
X *
X * Side effects:
X * Output to stdio.
X *
X * Arguments:
X * dirTreePtr - DirTree struct to dump the contents of.
X * clientData - Anonymous data which will be ignored.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XOutputFileNames( DirTree *dirTreePtr, void *clientData )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "OutputFileNames()" ;
X
X XtSetDataStruct **setPtr = dirTreePtr->setPtr ;
X
X int i ;
X
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\n%s: <%s>\n",
X pLocName, dirTreePtr->fullName ) ;
X#endif
X
X /* Don't bother messing around if there is nothing here. */
X
X if ( ! dirTreePtr->isDisplayed ) return ;
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\tIs displayed\n" ) ;
X#endif
X
X for ( i = 0 ; i < dirTreePtr->fileCnt ; ++i )
X {
X char path [ MAXPATHLEN + 1 ] ;
X
X if ( setPtr[i]->is_lit )
X {
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\t%d: set=<%s>, files=<%s>\n",
X i,
X setPtr[i]->string,
X dirTreePtr->files[i].file ) ;
X#endif
X
X if ( dirTreePtr->relName != NULL )
X strcpy ( path, dirTreePtr->relName ) ;
X else
X strcpy ( path, dirTreePtr->fullName ) ;
X
X strcat ( path, dirTreePtr->files[i].file ) ;
X strcat ( path, " " ) ;
X printf ( path ) ;
X }
X }
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * QuitButtonPushed --
X *
X * The callback for pushing the Quit button.
X *
X * Results:
X * None.
X *
X * Side effects:
X * Blows out of the application abruptly.
X *
X * Arguments:
X * w - The calling widget's id.
X * client_data - Null, since no data passed to callback list.
X * call_data - Undefined by the Command widget.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XQuitButtonPushed( Widget w, caddr_t client_data, caddr_t call_data )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "QuitButtonPushed()" ;
X
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X XtDestroyApplicationContext ( appContext ) ;
X exit ( 1 ) ;
X}
X
X
X/*
X *----------------------------------------------------------------------
X *
X * UpButtonPushed --
X *
X * The callback for pressing the Up button. A dir box
X * is opened on the ancestor of the directory in which
X * the button was pushed.
X *
X * Results:
X * None.
X *
X * Side effects:
X * If everthing goes well, the relative name of the
X * ancestor may be updated, and a dir box is constructed
X * and displayed.
X *
X * Arguments:
X * w - The calling widget's id.
X * client_data - Null, since no data passed to callback list.
X * call_data - Undefined by the Command widget.
X *
X *----------------------------------------------------------------------
X */
X
Xstatic void
XUpButtonPushed( Widget w, caddr_t client_data, caddr_t call_data )
X{
X char errLine[ ERRLINE_LEN ] ;
X char *pLocName = "UpButtonPushed()" ;
X
X DirTree *dtPtr ;
X
X#ifdef DEBUG
X fprintf( pErrFp, "\n%s:\n", pLocName );
X#endif
X
X /* First find the DirTree struct this happened in. */
X
X if ( ( dtPtr = DirTree_FindWidget ( dirRootPtr, UpW, w )) == NULL )
X InternalError ( pLocName, "Searching for the Up widget" ) ;
X
X /* Don't bother hanging out if this is the top of the tree...
X * can't go up from here.
X */
X
X if ( dtPtr->rootPtr == NULL ) return ;
X
X /* If there's a relative path name for the directory we're
X * going up from, then construct one for the directory we're
X * going up to. This keeps all 'local' references local, and
X * will be used to generate the names at 'done' time.
X */
X
X#ifdef DEBUG
X fprintf ( pErrFp, "\trelName=0x%x\n", dtPtr->relName ) ;
X#endif
X
X if ( dtPtr->relName != NULL )
X {
X char path[ MAXPATHLEN + 1 ] ;
X
X strcpy ( path, dtPtr->relName ) ;
X strcat ( path, "../" ) ;
X if ( dtPtr->rootPtr->relName == NULL
X || ( dtPtr->rootPtr->relName != NULL
X && strlen ( path ) < strlen ( dtPtr->rootPtr->relName ) ) )
X dtPtr->rootPtr->relName = StrSave( path ) ;
X }
X
X /* Build and display a box for the root of this directory,
X * if it hasn't been done already.
X */
X
X if ( ! dtPtr->rootPtr->isDisplayed )
X BuildDirBox ( dtPtr->rootPtr ) ;
X}
X
X
END_OF_FILE
if test 20993 -ne `wc -c <'x.c'`; then
echo shar: \"'x.c'\" unpacked with wrong size!
fi
# end of 'x.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked both archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
gary
More information about the Comp.sources.x
mailing list