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