#include "xbcomm.h"

int inPipe[ 2 ], outPipe[ 2 ], errPipe[ 2 ];
FILE *toProc, *fromProc, *errProc;


/* Returns a char* copy.  Allocates sufficient space to contain the string */
/* given as argument, copy the argument string, and returns a pointer to   */
/* the copy.								   */
char *copyString( val )
char *val;
{
    char *str;
    	if ( val IS NULL )
	    str = NULL;
    	else
    	{
   	    str = (char *)malloc( strlen( val ) + 1 );
   	    strcpy( str, val );
    	}
        return( str );
}

/* Resets a char* pointer to a new value.  Allocates sufficient space to   */
/* contain the string given as argument, copy the argument string, and 	   */
/* gives back the new  pointer, which now contains the copy. 		   */
VOIDPARM setString( str, val )
char **str;
char *val;
{
	/* to be most correct, this should free any space that's already */
	/* taken up by str - which it doesn't yet */
    	if ( val IS NULL )
	    *str = NULL;
    	else
    	{
   	    *str = (char *)malloc( strlen( val ) + 1 );
   	    strcpy( *str, val );
    	}
}

/* Returns a char* concatenation of str1 (which may be null) with str2.    */
/* Iff str1 is not null, str3 is used as a separating string (which may be */
/* null) between str1 and str2.  Allocates sufficient space to contain the */
/* string(s) given as arguments, performs the concatenation, and returns a */
/* pointer to the concatenated string.					   */
char *addString( str1, str2, str3 )
char *str1, *str2, *str3;
{
    char *str;

    	if ( str1 IS NULL )
   	     str = copyString( str2 );
	else
	{
    	    if ( str3 IS NULL )
	    {
   	         str = (char *)malloc( strlen( str1 ) + strlen( str2 ) + 1 );
   	         sprintf( str, "%s%s", str1, str2 );
	    }
    	    else
    	    {
   	         str = (char *)malloc( strlen( str1 ) + strlen( str2 ) 
				         + strlen( str3 ) + 1 );
   	         sprintf( str, "%s%s%s", str1, str3, str2 );
    	    }
	}
        return( str );
}

/* Determine if b is contained in a, if so return a pointer to the 	   */
/* occurrence of b in a. 						   */
char *stringIn( a, b )
char *a;
char *b;
{
    int	aLen=strlen( a );
    int	bLen=strlen( b );
    char *ap=a;

	if ( aLen < bLen )
		return( NULL );
	while ( strlen( ap ) >= bLen )
	{
	    if ( NOT strncmp( ap, b, bLen ) )
		return( ap );
	    ap++;
	}
	return( NULL );
}

char *getAnswer( VOIDPARM )
{
    char ans[ 256 ], inpt;
    int count;

	fflush( stdout );
	count = 0;
	ans[ count ] = NULLTERM;
	while ( read( 0, &inpt, 1 ) > 0 )
	{
	    if ( inpt IS EOL )
	    {
		ans[ count ] = NULLTERM;
		break;
	    }
	    else
		ans[ count ] = inpt;
	    count++;
	}
	printf( "\n" );
	return( copyString( ans ) );
}

/* Return the "root" part of the filename (max 10 characters)*/
boolean getRootName( VOIDPARM )
{
    int	nameLen, charPos, scriptPos, tmpChar;

	fileName = theFile;
	nameLen = strlen( theFile );
	charPos = nameLen - 1;
	while ( charPos )
	{
	    tmpChar = theFile[ charPos ];
	    if ( tmpChar IS SLASH )
	    {
		fileName = copyString( theFile + charPos + 1 );
	    	break;
	    }
	    charPos--;
	}
	nameLen = strlen( fileName );
	charPos = nameLen - 1;
	while ( charPos )
	{
	    tmpChar = fileName[ charPos ];
	    if ( tmpChar IS DOT )
	    	break;
	    charPos--;
	}
	if ( charPos IS 0 )
	{
	    fileRoot = fileName;
	    scriptPos = nameLen;
	}
	else
	{
	    fileRoot = (char *)malloc( charPos + 1 );
	    strncpy( fileRoot, fileName, charPos );
	    fileRoot[ charPos ] = NULLTERM;
	    scriptPos = charPos;
	}
	if ( scriptPos > 8 )
	    scriptPos = 8;
	scriptRoot = (char *)malloc( scriptPos + 1 );
	strncpy( scriptRoot, fileName, scriptPos );
	scriptRoot[ scriptPos ] = NULLTERM;
	partRoot = (char *)malloc( scriptPos + 1 );
	strncpy( partRoot, fileName, scriptPos - 1 );
	partRoot[ scriptPos - 1 ] = EQUALSIGN;
	partRoot[ scriptPos ] = NULLTERM;
	return( TRUE );
}

boolean verifyEnvPath( var )
char *var;
{
    char *envPath;

	envPath = (char *)getenv( var );
	return( ( envPath ISNT NULL ) AND ( strlen( envPath ) ISNT 0 ) );
}

char *descPath( VOIDPARM )
{
    char testPath[ MAXPATHLEN ];
    char *envPath;

	sprintf( testPath, "%s.dsc", fileRoot );
	if ( fileExists( testPath ) )
	    return( fileRoot );
	envPath = (char *)getenv( "DSCDIR" );	
	if ( envPath ISNT NULL AND strlen( envPath ) )
	{
	    sprintf( testPath, "%s/%s.dsc", envPath, fileRoot );
	    if ( noConfirm OR fileExists( testPath ) )
	    	return( addString( envPath, fileRoot, "/" ) );
	    else
		return( addString( tmpDir, fileRoot, "/" ) );
	}
	else
	    return( addString( tmpDir, fileRoot, "/" ) );
}



#define fileIsFile( fil )   						    \
    ( ( ( fil ).st_mode AND_ S_IFREG ) AND NOT    			    \
      ( ( fil ).st_mode AND_ ( S_IFREG XOR_ S_IFLNK ) ) )

/* Determine the existance of a file of a specified type.  Returns TRUE	   */
/* iff the file exists and is of the type(s) specified.			   */
boolean fileExists( name )
char *name;
{
    boolean statFailed;
    struct stat dirStat;

	statFailed = stat( name, &dirStat );
	if ( NOT statFailed )
	{
    	    if ( fileIsFile( dirStat ) )
		return( TRUE );
	}
	return( FALSE );
}


/* Create a DE - allocates and nulls out a DE structure and returns a 	   */
/* pointer to that structure.						   */
static DirEntry *cDE( dirName, fileName )
char *dirName, *fileName;
{
    DirEntry *newDE;

	newDE = (DirEntry *)malloc( sizeof( DirEntry ) );
	rDEName( newDE, addString( dirName, fileName, "/" ) );
	nDE( newDE ) = NULL;
	lDE( newDE ) = NULL;
	return( newDE );
}

/* Delete an existing DE.  Free up the space it used.			   */
VOIDPARM kDE( theDE )
DirEntry *theDE;
{

	free( gDEName( theDE ) );
	nDE( theDE ) = NULL;
	lDE( theDE ) = NULL;
	free( theDE );
}

/* Add a DE to the end of an existing linked list of varying size.	   */
static VOIDPARM aDEDE( parentDE, childDE )
DirEntry *parentDE, *childDE;
{
    DirEntry *tmpDE;

	if ( DEBUG_PROC )
	   printf( "Adding DE %s to DE %s...\n", 
	   	   gDEName( childDE ), gDEName( parentDE ) );

	if ( ( tmpDE = lDE( parentDE ) ) IS NULL )
	    nDE( parentDE ) = childDE;
	else
	    nDE( tmpDE ) = childDE;
	if ( ( tmpDE = lDE( childDE ) ) IS NULL )
	    lDE( parentDE ) = childDE;
	else
	    lDE( parentDE ) = tmpDE;
}


/* Return a sorted linked list of "DirEntry" structures, representing the   */
/* directory entries of the specified type in the specified directory.	   */

static int comparator( dl1, dl2 )
DirEntry **dl1, **dl2;
{
	if ( gDEName( *dl1 ) IS NULL )
	    /* dl1 should be BEFORE dl2 */
	    return( -1 );
	else if ( gDEName( *dl2 ) IS NULL )
	    /* dl1 should be AFTER dl2 */
	    return( 1 );
	else
	    return( strcmp( gDEName( *dl1 ), gDEName( *dl2 ) ) );
}

static DirEntry *sortDEs( currList )
DirEntry *currList;
{
    DirEntry *DETable[ 512 ];
    int index, count=0;
    char lastEntry[ MAXPATHLEN ];
    DirEntry *result=NULL;

	if ( currList IS NULL )
	    return( currList );
	/* first, put the current link list into an array for sorting... */
	while ( currList ISNT NULL )
	{
	    DETable[ count++ ] = currList;
	    currList = nDE( currList );
	}
	DETable[ count ] = NULL;
	/* ...sort... */
	qsort( (char *)DETable, count, sizeof( DirEntry * ), comparator );
	/* ...then put the sorted array back into a linked list */
	/* "lastEntry" is used to delete any duplicates... */
	lastEntry[ 0 ] = NULLTERM;
	if ( DEBUG_PROC )
	    printf( "Sorted list follows:\n" );
	for ( index = 0; index < count; index++ )
	{
	    if ( DEBUG_PROC )
	        printf( "%s...", gDEName( DETable[ index ] ) );
	    nDE( DETable[ index ] ) = NULL;
	    lDE( DETable[ index ] ) = NULL;
	    if ( ( lastEntry[ 0 ] IS NULLTERM ) OR 
		    ( ( gDEName( DETable[ index ] ) ISNT NULL ) AND
		    ( strcmp( lastEntry, gDEName( DETable[ index ] ) ) ) ) )
	    {
	    	if ( DEBUG_PROC )
		    printf( "\n" );
	        if ( result IS NULL )
		    result = DETable[ index ];
	        else
		    aDEDE( result, DETable[ index ] );
	    }
	    else if ( DEBUG_PROC )
		printf( "ELIMINATED\n" );
	    if ( gDEName( DETable[ index ] ) IS NULL )
	        strcpy( lastEntry, "(null)" );
	    else
	        strcpy( lastEntry, gDEName( DETable[ index ] ) );
	}
	if ( DEBUG_PROC )
	    printf( "End of sorted list.\n" );
	topDECnt = count;
	return( result );
	
}

VOIDPARM dirList( searchPatt )
char *searchPatt;
{
    char dirName[ MAXPATHLEN + 2 ];
    DirEntry *newDE, *currList=NULL;
    DIR *theDir;
    struct dirent *dirEntry;
    struct stat dirStat;
    char tmpStr[ 1024 ], filePath[ 1024 ];
    char *fname;

/*
	if ( NOT strcmp( tmpDir, "." ) )
	{
#ifdef SYSV
	    if ( (char *)getcwd( dirName, MAXPATHLEN ) IS NULL )
	    {
	    	printf( "ERROR: Couldn't get current working directory\n" );
	    	exit( -1 );
	    }
#else
	    if ( (char *)getwd( dirName ) IS NULL )
	    {
	    	printf( 
		"ERROR: Couldn't get current working directory because:\n%s\n", 
			dirName );
	    	exit( -1 );
	    }
#endif
	}
	else */
	    sprintf( dirName, "%s", tmpDir );
	theDir = opendir( dirName );
	while ( ( dirEntry = readdir( theDir ) ) ISNT NULL )
	{
	    newDE = NULL;
	    fname = dirEntry->d_name;
	    if ( DEBUG_PROC )
	        printf( "This directory entry: '%s'\n", fname );
	    if ( NOT ( strcmp( fname, "." ) AND
		    strcmp( fname, ".." ) ) )
		continue;
	    if ( NOT stringIn( fname, searchPatt ) )
		continue;
	    sprintf( filePath, "%s/%s", dirName, fname );
	    if ( stat( filePath, &dirStat ) )
	    {
		sprintf( tmpStr, "\nERROR:  Couldn't find file '%s'", 
			filePath );
	        perror( tmpStr );
	    }
	    else if ( ( newDE IS NULL ) AND fileIsFile( dirStat ) )
	        newDE = cDE( dirName, fname );
	    if ( newDE ISNT NULL )
	    {
		if ( currList IS NULL )
		    currList = newDE;
		else
		    aDEDE( currList, newDE );
	    }
	}
	closedir( theDir );
	topDE = sortDEs( currList );
}

#define sendToProc( whatToSend, result )				    \
{									    \
    ( result) = fprintf( toProc, "%s;\n", whatToSend );			    \
    fflush( toProc );							    \
    if ( ( result ) > 0 )						    \
	( result ) = 0;							    \
}

char *shellResult( theCommand, returnVal )
char *theCommand;
int *returnVal;
{
    int n;
    boolean notDone;
    char buf[ BUFSIZ ];
    char *realCommand;
    char *retPtr, *result;

	result = NULL;
	/* sprintf( realCommand, "%s; echo \"<xStatx>: $?\"", theCommand ); */
	realCommand = (char *)malloc( strlen( "; echo \"<xStatx>: $?\"" ) +
				      strlen( theCommand ) + 1 );
	sprintf( realCommand, "%s; echo \"<xStatx>: $?\"", theCommand );
	if ( DEBUG_PROC )
	    printf( "Slave shell about to execute '%s'\n", realCommand );
	sendToProc( realCommand, *returnVal );
	/* command completed - get stdout and stderr info */
	notDone = TRUE;
	while ( notDone )
	{
	    while ( ( n = read( inPipe[ 0 ], buf, BUFSIZ ) ) > 0 )
	    {
	        buf[ n ] = NULLTERM;
		if ( DEBUG_PROC )
	            printf( "From shell output '%s'\n", buf );
		if ( ( ( retPtr = stringIn( buf, "<xStatx>:" ) ) ISNT NULL ) AND
			( sscanf( retPtr, "<xStatx>: %d", returnVal ) IS 1 ) )
		{
		    /* got the return status - command is done */
		    notDone = FALSE;
		    retPtr[ 0 ] = NULLTERM;
		}
		if ( DEBUG_PROC )
	            printf( "(Modified) shell output '%s' (length %d)\n", 
			     buf, strlen( buf ) );
		if ( strlen( buf ) )
                {
		    if ( DEBUG_PROC )
            	        printf( "There WAS output!!\n" );
		    result = addString( result, buf, " " );
		    if ( DEBUG_PROC )
	                printf( "result is '%s'\n", result );
		}
	    }
	    /* ...still waiting for proper return status... */
	}
	/* Pass anything from shell's standard error */
	/* to our standard error */
	while ( ( n = read( errPipe[ 0 ], buf, BUFSIZ ) ) > 0 )
	{
	    buf[ n ] = '\0';
	    if ( DEBUG_PROC )
	        printf( "From shell error '%s'\n", buf );
	}
	return( result );
}


VOIDPARM closePipes( VOIDPARM )
{
	if ( toProc ISNT NULL )
            fclose( toProc );
	if ( fromProc ISNT NULL )
            fclose( fromProc );
	if ( errProc ISNT NULL )
            fclose( errProc );
	if ( inPipe[ 0 ] ISNT -1 )
	    close( inPipe[ 0 ] );
	if ( inPipe[ 1 ] ISNT -1 )
	    close( inPipe[ 1 ] );
	if ( outPipe[ 0 ] ISNT -1 )
	    close( outPipe[ 0 ] );
	if ( outPipe[ 1 ] ISNT -1 )
	    close( outPipe[ 1 ] );
	if ( errPipe[ 0 ] ISNT -1 )
	    close( errPipe[ 0 ] );
	if ( errPipe[ 1 ] ISNT -1 )
	    close( errPipe[ 1 ] );
}

boolean openTopShell( VOIDPARM )
{

	if ( DEBUG_PROC )
	    printf( "Opening top-level shell...\n" );
	/* set up pipes to standard in, out, and error */
        if ( pipe( inPipe ) IS -1 )
        {
	    if ( DEBUG_PROC )
	        printf( "Error opening up inPipe...\n" );
	    printf( "ERROR:  cannot open slave shell...\n" );
	    return( FALSE );
        }
        if ( pipe( outPipe ) IS -1 )
        {
	    if ( DEBUG_PROC )
	        printf( "Error opening up outPipe...\n" );
	    closePipes();
	    printf( "ERROR:  cannot open slave shell...\n" );
	    return( FALSE );
        }
        if ( pipe( errPipe ) IS -1 )
        {
	    if ( DEBUG_PROC )
	        printf( "Error opening up errPipe...\n" );
	    closePipes();
	    printf( "ERROR:  cannot open slave shell...\n" );
	    return( FALSE );
        }
        
	/* open from file descriptors */
        toProc = fdopen( outPipe[ 1 ], "w" );
        fromProc = fdopen( inPipe[ 0 ], "r" );
        errProc = fdopen( errPipe[ 0 ], "r" );
        
        if ( NOT ( toProc AND fromProc AND errProc ) )
        {
	    if ( DEBUG_PROC )
	        printf( "Error opening up process pipes...\n" );
	    closePipes();
	    printf( "ERROR:  cannot open slave shell...\n" );
	    return( FALSE );
        }
        
	/* make parent non-blocking */
        fcntl( fileno( toProc ), F_SETFL, O_NDELAY );
        fcntl( fileno( fromProc ), F_SETFL, O_NDELAY );
        fcntl( fileno( errProc ), F_SETFL, O_NDELAY );
        
        if ( fork() IS 0 )
        {
	    system( "sleep 5" );
        
	    /* redirect standard input */
	    close( outPipe[ 1 ] );
	    close( fileno( stdin ) );
	    dup( outPipe[ 0 ] );
	    close( outPipe[ 0 ] );
        
	    /* redirect standard error */
	    close( errPipe[ 0 ] );
	    close( fileno( stderr ) );
	    dup( errPipe[ 1 ] );
	    close( errPipe[ 1 ] );
            
	    /* redirect standard output */
	    close( inPipe[ 0 ] );
	    close( fileno( stdout ) );
	    dup( inPipe[ 1 ] );
	    close( inPipe[ 1 ] );
        
	    /* exec the shell! */
	    execl( "/bin/sh", "sh", "-s", NULL );
	    if ( DEBUG_PROC )
	        /* Will NEVER get here unless the exec fails */
	        printf( "Couldn't start 'sh -s'\n" );
	    printf( "ERROR:  cannot open slave shell...\n" );
	    exit( 0 );
        }
        
	/* close the stuff we don't need as parent */
        close( outPipe[ 0 ] );
        close( inPipe[ 1 ] );
        close( errPipe[ 1 ] );
	return( TRUE );
}

boolean closeTopShell( VOIDPARM )
{
    int result;

	sendToProc( "exit", result );
	system( "sleep 2" ); /* give the shell a chance to respond */
	if ( DEBUG_PROC )
	    printf( "Closing top-level shell...\n" );
	closePipes();
	return( result IS 0 );
}

/* Read a line from a file - return the line and the last character read.  */
int lineRead( src, dst )
FILE *src;
char dst[];
{
    char *lPtr;
    int c;

	dst[ 0 ] = NULLTERM;
	lPtr = dst;
	while ( ( ( c = getc( src ) ) ISNT EOL ) AND ( c ISNT EOF ) )
	    *lPtr++ = (char)c;
	*lPtr = NULLTERM;
	return( c );
}

char *utilInPath( util, shouldBitch )
char *util;
boolean shouldBitch;
{
    static char *path;
    char *this, *next, *suggestion;
    char tmpPath[ MAXPATHLEN ], tmpFile[ MAXPATHLEN ];

	if ( path IS NULL )
	    path = (char *)getenv( "PATH" );
	/* Now the fun begins... search through the PATH setting to */
	/* find out if the given utility is accessible... */
	this = path;
	suggestion = NULL;
	while ( this )
	{
	    if ( ( next = (char *)strchr( this, ':' ) ) AND 
		( next > this ) ) 
	    {
  	        /* Extract out the current PATH element. */
    	        strncpy( tmpPath, this, next - this );
    	        tmpPath[ next - this ] = '\0';
    	        next += 1;
	    }
	    else if ( next IS NULL ) 
	    {
    	        /* We are on the last element of the PATH variable. */
    	        strcpy( tmpPath, this );
    	        tmpPath[ strlen( this ) ] = '\0';
	    }
	    else 
	    {
    	        /* If a ":" is present without a PATH element, a "." */
	        /* is implied. */
    	        tmpPath[ 0 ] = '\0';
    	        next += 1;
	    }
	    if ( tmpPath[ 0 ] ISNT NULLTERM )
		sprintf( tmpFile, "%s/%s", tmpPath, util );
	    else
		sprintf( tmpFile, "%s", util );
            /* Is it there? */
            if ( fileExists( tmpFile ) )
	    	suggestion = addString( suggestion, tmpFile, " or " );
	    this = next;
        }
	if ( ( suggestion == NULL ) AND shouldBitch )
    	    printf( 
	    "ERROR:  Can't find '%s' in the current path!  Aborting...\n",
		    util );
	return( suggestion );

}

VOIDPARM suggest( util, switches )
char *util, *switches;
{
    char *suggestion;

	if ( suggestion = utilInPath( util, FALSE ) )
	{
	    if ( switches )
		printf( "\t(%s {with %s option(s)} might be a good setting...)\n", 
			suggestion, switches );
	    else
		printf( "\t(%s might be a good setting...)\n", suggestion );
	}
	else
	{
	    if ( switches )
		printf( "\t(I'd suggest '%s %s' - but it's apparently not available...)\n", 
			util, switches );
	    else
		printf( "\t(I'd suggest '%s' - but it's apparently not available...)\n", util );
	}
}



syntax highlighted by Code2HTML, v. 0.9.1