/* WhereAmI
 *
 * A category of Application that provides methods for finding the
 * application executable and executable directory.
 *
 * Copyright 1991, 1992 Scott Hess.  This source code may be
 * redistributed and modified without restriction.  Well, one
 * restriction - do not claim that you wrote it.
 *
 * Scott Hess
 * 12901 Upton Avenue South, #326
 * Burnsville, MN  55337
 * (612) 895-1208
 * scott@gac.edu
 * shess@ssesco.com
 */
#import "WhereAmI.h"
#import <appkit/defaults.h>
#import <sys/param.h>
#import <libc.h>
#import <strings.h>

@implementation Application (WhereAmI)
int whereAmIReference=0;
-(NXAtom)whoAmI
{
    static NXAtom whoAmI=NULL;
    static BOOL beenHere;
    
    if( !beenHere) {
        char buf[ MAXPATHLEN+1]="";
	char linkbuf[ MAXPATHLEN+1];
	int len, links;

	/* First, trace the file that is in NXArgv[ 0].
	 * If it starts with '/', it's an absolute pathname and thus truth.
	 * Else, check to see if it is relative to the working directory.
	 * Else, look on the path for it.
	 */
	if( NXArgv[ 0][ 0]=='/') {
	    strcpy( buf, NXArgv[ 0]);
	} else if( access( NXArgv[ 0], F_OK)==0) {
	    if( getwd( buf)) {
	        strcat( buf, "/");
		strcat( buf, NXArgv[ 0]);
	    }
	} else {
	    const char *pathList=getenv( "PATH");
	    if( pathList) {
	        while( *pathList) {
		    const char *colon=index( pathList, ':');
		    if( colon) {
		        strncpy( buf, pathList, colon-pathList);
			buf[ colon-pathList]=0;
			pathList=colon+1;
		    } else {
		        strcpy( buf, pathList);
			pathList+=strlen( pathList);
		    }
		    strcat( buf, "/");
		    strcat( buf, NXArgv[ 0]);
		    if( access( buf, F_OK)==0) {
		        break;
		    }
		}
	    }
	    if( !pathList || *pathList==0) {
	        buf[ 0]='\0';
	    }
	}
	
	/* Now, trace the file through symbolic links to where it _really_ is.
	 * Note that symbolic links can be multiple.
	 * Give up after tracing through 8 links (assume a cycle).
	 */
	for( links=0; links<8 && (len=readlink( buf, linkbuf, MAXPATHLEN))!=-1; links++) {
	    linkbuf[ len]='\0';
	    if( linkbuf[ 0]=='/') {
	        strcpy( buf, linkbuf);
	    } else {
	        char *p=linkbuf;
		for( ;;) {
		    char *s=rindex( buf, '/');
		    if( s) {
		        *s='\0';
		    }
		    if( strncmp( p, "../", 3)) {
		        break;
		    }
		    p+=3;
		}
		strcat( buf, "/");
		strcat( buf, p);
	    }
	}
	if( links==8) {
	    buf[ 0]='\0';
	}
	
	if( !access( buf, X_OK)) {
	    whoAmI=NXUniqueString( buf);
	}
        beenHere=YES;
    }
    return whoAmI;
}
-(NXAtom)whereAmI
{
    static NXAtom whereAmI=NULL;
    static BOOL beenHere=NO;
    
    if( !beenHere) {
	/* Just get the executable path, and then strip off the
	 * executable's name.
	 */
        NXAtom who=[self whoAmI];
	if( who) {
	    char buf[ MAXPATHLEN+1]="";
	    char *i;
	    strcpy( buf, who);
	    i=rindex( buf, '/');
	    if( i) {
	        *i='\0';
	    }
	    if( buf[ 0]) {
	        whereAmI=NXUniqueString( buf);
	    } else {
		whereAmI="";
	    }
	}

        beenHere=YES;
    }
    return whereAmI;
}
-(const char *)whereIs:(const char *)file path:(char *)result
{
    /* Get the directory the application resides in.
     * Append the file part.
     * Attempt to verify the file's existance.
     */
    if( result) {
	NXAtom where=[self whereAmI];
	if( where) {
	    strcpy( result, where);
	    strcat( result, "/");
	    if( file) {
		strcat( result, file);
	    }
	    if( !access( result, F_OK)) {
		return result;
	    }
	    return NULL;
	}
    }
    *result='\0';
    return NULL;
}
@end
