--- ray/src/common/getpath.c 2003/02/25 02:47:21 2.10 +++ ray/src/common/getpath.c 2003/06/26 00:58:09 2.11 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: getpath.c,v 2.10 2003/02/25 02:47:21 greg Exp $"; +static const char RCSid[] = "$Id: getpath.c,v 2.11 2003/06/26 00:58:09 schorsch Exp $"; #endif /* * getpath.c - function to search for file in a list of directories @@ -9,77 +9,172 @@ static const char RCSid[] = "$Id: getpath.c,v 2.10 200 #include "copyright.h" -#include "standard.h" +#include +#include +#ifndef _WIN32 /* XXX was NIX, do we still compile on Amiga? */ + #include + #include +#endif #include "paths.h" -#ifndef NIX -#include -extern struct passwd *getpwnam(); -#endif +#ifdef _WIN32 +static char * +core_getpath /* wrapped below: expand fname, return full path */ +#else char * -getpath(fname, searchpath, mode) /* expand fname, return full path */ -register char *fname; -register char *searchpath; -int mode; +getpath /* expand fname, return full path */ +#endif +( +register char *fname, +register char *searchpath, +int mode +) { -#ifndef NIX +#ifndef _WIN32 /* XXX was NIX, do we still compile on Amiga? */ struct passwd *pwent; #endif - static char pname[MAXPATH]; + static char pname[PATH_MAX]; register char *cp; - if (fname == NULL) - return(NULL); + if (fname == NULL) { return(NULL); } pname[0] = '\0'; /* check for full specification */ - switch (*fname) { - CASEDIRSEP: /* relative to root */ - case '.': /* relative to cwd */ - strcpy(pname, fname); - break; -#ifndef NIX - case '~': /* relative to home directory */ - fname++; - if (*fname == '\0' || ISDIRSEP(*fname)) { /* ours */ - if ((cp = getenv("HOME")) == NULL) - return(NULL); - strcpy(pname, cp); - strcat(pname, fname); - break; - } - cp = pname; /* user */ - do - *cp++ = *fname++; - while (*fname && !ISDIRSEP(*fname)); - *cp = '\0'; - if ((pwent = getpwnam(pname)) == NULL) - return(NULL); - strcpy(pname, pwent->pw_dir); - strcat(pname, fname); - break; + + if (ISABS(fname)) { /* Can't use CASEDIRSEP below on Windows */ + strncpy(pname, fname, sizeof(pname)-1); + } else { + switch (*fname) { + /* XXX This doesn't work on Windows */ + /* CASEDIRSEP: */ /* relative to root */ + case '.': /* relative to cwd */ + strncpy(pname, fname, sizeof(pname)-1); + break; + case '~': /* relative to home directory */ + fname++; + if (*fname == '\0' || ISDIRSEP(*fname)) { /* ours */ + if ((cp = getenv("HOME")) == NULL) +#ifdef _WIN32 /* Windows sometimes uses a different var name */ + if ((cp = getenv("HOMEDIR")) == NULL) #endif + return(NULL); + strncpy(pname, cp, sizeof(pname)-1); + strncat(pname, fname, sizeof(pname)-strlen(pname)-1); + break; + } +#ifndef _WIN32 /* XXX was NIX, do we still compile on Amiga? */ + /* XXX Should we request our own home directory from the + XXX system as well if the above fails? */ + /* XXX In any case, we need do the same thing on Windows... */ + cp = pname; /* user */ + do + *cp++ = *fname++; + while (*fname && !ISDIRSEP(*fname)); + *cp = '\0'; + if ((pwent = getpwnam(pname)) == NULL) + return(NULL); + strncpy(pname, pwent->pw_dir, sizeof(pname)-1); + strncat(pname, fname, sizeof(pname)-strlen(pname)-1); + break; +#endif + } } if (pname[0]) /* got it, check access if search requested */ return(searchpath==NULL||access(pname,mode)==0 ? pname : NULL); if (searchpath == NULL) { /* don't search */ - strcpy(pname, fname); + strncpy(pname, fname, sizeof(pname)-1); return(pname); } - /* check search path */ + /* check search path */ do { cp = pname; - while (*searchpath && (*cp = *searchpath++) != PATHSEP) + while (*searchpath && (*cp = *searchpath++) != PATHSEP) { cp++; - if (cp > pname && !ISDIRSEP(cp[-1])) + } + if (cp > pname && !ISDIRSEP(cp[-1])) { *cp++ = DIRSEP; - strcpy(cp, fname); + } + strncpy(cp, fname, sizeof(pname)-strlen(pname)-1); if (access(pname, mode) == 0) /* file accessable? */ return(pname); } while (*searchpath); - /* not found */ + /* not found */ return(NULL); } + + +#ifdef _WIN32 +/* This is a wrapper around the above, "emulating" access mode X_OK, + which is not supported on Windows. + If we see X_OK and the filename has no extension, then we'll remove + the X_OK from the mode, append ".exe" to the file name, and search + with the resulting string. If that fails, we'll try again with ".bat". + Theoretically, we might still not have execute rights on a file we find + like this, but that's rare enough not to be worth checking the ACLs. +*/ +char * +getpath( /* expand fname, return full path */ +register char *ffname, +register char *searchpath, +int mode +) +{ + register char *cp; + char fname[PATH_MAX]; + + if (ffname == NULL) + return(NULL); + + /* if we have a dot in the string, we assume there is a file name + extension present */ + /* XXX We'd better test for .exe/.bat/.etc explicitly */ + if (!(mode & X_OK) || (strrchr(ffname, '.') != NULL)) { + return core_getpath(ffname, searchpath, mode); + } + + /* We're looking for an executable, Windows doesn't have X_OK. */ + mode &= ~X_OK; + /* Append .exe */ + strncpy(fname, ffname, sizeof(fname)-5); + strcat(fname, ".exe"); + cp = core_getpath(fname, searchpath, mode); + if (cp != NULL) return cp; + + /* Try with .bat this time... */ + strncpy(fname, ffname, sizeof(fname)-5); + strcat(fname, ".bat"); + cp = core_getpath(fname, searchpath, mode); + return cp; +} +#endif /* _WIN32 */ + + +#ifdef TEST_MODULE +int main() +{ + char * fp; + char fmt[] = "%15s %-10s %s: %s\n"; + + fp = getpath("rayinit.cal", getenv("RAYPATH"), R_OK); + printf(fmt, "rayinit.cal", "RAYPATH", "R_OK", fp); + fp = getpath("mkillum", getenv("PATH"), X_OK); + printf(fmt, "mkillum", "PATH", "X_OK", fp); + fp = getpath("/", getenv("PATH"), W_OK); + printf(fmt, "/", "PATH", "W_OK", fp); + fp = getpath("~", getenv("PATH"), F_OK); + printf(fmt, "~", "PATH", "F_OK", fp); + printf("Undefining HOME and HOMEDIR\n"); + unsetenv("HOME"); + unsetenv("HOMEDIR"); + fp = getpath("~", getenv("PATH"), F_OK); + printf(fmt, "~", "PATH", "F_OK", fp); +#ifndef _WIN32 /* XXX was NIX, do we still compile on Amiga? */ + fp = getpath("~lp", getenv("PATH"), F_OK); + printf(fmt, "~lp", "PATH", "F_OK", fp); +#endif +} +#endif +