| 1 | #ifndef lint | 
| 2 | static const char       RCSid[] = "$Id: getpath.c,v 2.19 2016/03/06 01:13:17 schorsch Exp $"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | *  getpath.c - function to search for file in a list of directories | 
| 6 | * | 
| 7 | *  External symbols declared in rtio.h | 
| 8 | */ | 
| 9 |  | 
| 10 | #include "copyright.h" | 
| 11 |  | 
| 12 | #include  <string.h> | 
| 13 | #include  <ctype.h> | 
| 14 |  | 
| 15 | #include  "rtio.h" | 
| 16 | #include  "paths.h" | 
| 17 |  | 
| 18 |  | 
| 19 | #if defined(_WIN32) || defined(_WIN64) | 
| 20 | static char * | 
| 21 | core_getpath    /* wrapped below: expand fname, return full path */ | 
| 22 | #else | 
| 23 | char * | 
| 24 | getpath /* expand fname, return full path */ | 
| 25 | #endif | 
| 26 | ( | 
| 27 | char  *fname, | 
| 28 | char  *searchpath, | 
| 29 | int  mode | 
| 30 | ) | 
| 31 | { | 
| 32 | static char  pname[PATH_MAX]; | 
| 33 | char uname[512]; | 
| 34 | char  *cp; | 
| 35 | int i; | 
| 36 |  | 
| 37 | if (fname == NULL) { return(NULL); } | 
| 38 |  | 
| 39 | pname[0] = '\0';                /* check for full specification */ | 
| 40 |  | 
| 41 | if (ISABS(fname)) { /* absolute path */ | 
| 42 | strlcpy(pname, fname, sizeof(pname)); | 
| 43 | } else { | 
| 44 | switch (*fname) { | 
| 45 | case '.':               /* relative to cwd */ | 
| 46 | strlcpy(pname, fname, sizeof(pname)); | 
| 47 | break; | 
| 48 | case '~':               /* relative to home directory */ | 
| 49 | fname++; | 
| 50 | cp = uname; | 
| 51 | for (i = 0; i < sizeof(uname) && *fname | 
| 52 | && !ISDIRSEP(*fname); i++) | 
| 53 | *cp++ = *fname++; | 
| 54 | *cp = '\0'; | 
| 55 | cp = gethomedir(uname, pname, sizeof(pname)); | 
| 56 | if(cp == NULL) return NULL; | 
| 57 | strlcat(pname, fname, sizeof(pname)); | 
| 58 | break; | 
| 59 | } | 
| 60 | } | 
| 61 | if (pname[0])           /* got it, check access if search requested */ | 
| 62 | return(!searchpath || access(pname,mode)==0 ? pname : NULL); | 
| 63 |  | 
| 64 | if (!searchpath) {                      /* no search */ | 
| 65 | strlcpy(pname, fname, sizeof(pname)); | 
| 66 | return(pname); | 
| 67 | } | 
| 68 | /* check search path */ | 
| 69 | do { | 
| 70 | cp = pname; | 
| 71 | while (*searchpath && (*cp = *searchpath++) != PATHSEP) | 
| 72 | cp += (cp-pname < sizeof(pname)-2); | 
| 73 | if (cp > pname && !ISDIRSEP(cp[-1])) | 
| 74 | *cp++ = DIRSEP; | 
| 75 | *cp = '\0'; | 
| 76 | strlcat(pname, fname, sizeof(pname)); | 
| 77 | if (access(pname, mode) == 0)           /* file accessable? */ | 
| 78 | return(pname); | 
| 79 | } while (*searchpath); | 
| 80 | /* not found */ | 
| 81 | return(NULL); | 
| 82 | } | 
| 83 |  | 
| 84 |  | 
| 85 | #if defined(_WIN32) || defined(_WIN64) | 
| 86 | /* This is a wrapper around the above, "emulating" access mode X_OK, | 
| 87 | which is not supported on Windows. | 
| 88 | If we see X_OK and the filename has no extension, then we'll remove | 
| 89 | the X_OK from the mode, append ".exe" to the file name, and search | 
| 90 | with the resulting string. If that fails, we'll try again with ".bat". | 
| 91 | Theoretically, we might still not have execute rights on a file we find | 
| 92 | like this, but that's rare enough not to be worth checking the ACLs. | 
| 93 | */ | 
| 94 | char * | 
| 95 | getpath(        /* expand fname, return full path */ | 
| 96 | char  *ffname, | 
| 97 | char  *searchpath, | 
| 98 | int  mode | 
| 99 | ) | 
| 100 | { | 
| 101 | char  *cp; | 
| 102 | char fname[PATH_MAX]; | 
| 103 |  | 
| 104 | if (ffname == NULL) | 
| 105 | return(NULL); | 
| 106 |  | 
| 107 | /* if we have a dot in the string, we assume there is a file name | 
| 108 | extension present */ | 
| 109 | /* XXX We'd better test for .exe/.bat/.etc explicitly */ | 
| 110 | if (!(mode & X_OK) || (strrchr(ffname, '.') != NULL)) { | 
| 111 | return core_getpath(ffname, searchpath, mode); | 
| 112 | } | 
| 113 |  | 
| 114 | /* We're looking for an executable, Windows doesn't have X_OK. */ | 
| 115 | mode &= ~X_OK; | 
| 116 | /* Append .exe */ | 
| 117 | strncpy(fname, ffname, sizeof(fname)-5); | 
| 118 | strcat(fname, ".exe"); | 
| 119 | cp = core_getpath(fname, searchpath, mode); | 
| 120 | if (cp != NULL) return cp; | 
| 121 |  | 
| 122 | /* Try with .bat this time... */ | 
| 123 | strncpy(fname, ffname, sizeof(fname)-5); | 
| 124 | strcat(fname, ".bat"); | 
| 125 | cp = core_getpath(fname, searchpath, mode); | 
| 126 | return cp; | 
| 127 | } | 
| 128 | #endif /* _WIN32 */ | 
| 129 |  | 
| 130 |  | 
| 131 | #ifdef TEST_MODULE | 
| 132 | int main() | 
| 133 | { | 
| 134 | char * fp; | 
| 135 | char fmt[] = "%15s %-10s %s: %s\n"; | 
| 136 |  | 
| 137 | fp = getpath("rayinit.cal", getenv("RAYPATH"), R_OK); | 
| 138 | printf(fmt,  "rayinit.cal",        "RAYPATH", "R_OK", fp); | 
| 139 | fp = getpath("mkillum", getenv("PATH"), X_OK); | 
| 140 | printf(fmt,  "mkillum",        "PATH", "X_OK", fp); | 
| 141 | fp = getpath("/", getenv("PATH"), W_OK); | 
| 142 | printf(fmt,  "/",        "PATH", "W_OK", fp); | 
| 143 | fp = getpath("~", getenv("PATH"), F_OK); | 
| 144 | printf(fmt,  "~",        "PATH", "F_OK", fp); | 
| 145 | printf("Undefining HOME and HOMEPATH\n"); | 
| 146 | unsetenv("HOME"); | 
| 147 | unsetenv("HOMEPATH"); | 
| 148 | fp = getpath("~", getenv("PATH"), F_OK); | 
| 149 | printf(fmt,  "~",        "PATH", "F_OK", fp); | 
| 150 | fp = getpath("~lp/blah", getenv("PATH"), F_OK); | 
| 151 | printf(fmt, "~lp/blah",         "PATH", "F_OK", fp); | 
| 152 | } | 
| 153 | #endif | 
| 154 |  |