argv@island.uu.net (Dan Heller) (09/07/89)
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@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@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