#include "lib.h"
#include <errno.h>
#include <stdlib.h>
#include "defs.h"
#include "posix.h"
#include "nonposix.h"
#include "relocate.h"
#if defined _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#define INSTALLPATHLEN (sizeof(INSTALLPATH) - 1)
#ifndef DEBUG
# define DEBUG 0
#endif
extern "C" const char *program_name;
char *curr_prefix = 0;
size_t curr_prefix_len = 0;
char *xdirname(char *s)
{
static const char dot[] = ".";
if (!s)
return 0;
char *p = strrchr(s, DIR_SEPS[0]);
const char *sep = &DIR_SEPS[1];
while (*sep) {
char *p1 = strrchr(s, *sep);
if (p1 && (!p || p1 > p))
p = p1;
sep++;
}
if (p)
*p = '\0';
else
s = (char *)dot;
return s;
}
char *searchpath(const char *name, const char *pathp)
{
char *path;
if (!name || !*name)
return 0;
#if DEBUG
fprintf(stderr, "searchpath: pathp: `%s'\n", pathp);
fprintf(stderr, "searchpath: trying `%s'\n", name);
#endif
if (!access (name, F_OK)) {
path = new char[path_name_max()];
#ifdef _WIN32
path = _fullpath(path, name, path_name_max());
#else
path = realpath(name, path);
#endif
#if DEBUG
fprintf(stderr, "searchpath: found `%s'\n", path);
#endif
return path;
}
size_t namelen = strlen(name);
char *p = (char *)pathp;
for (;;) {
char *end = strchr(p, PATH_SEP_CHAR);
if (!end)
end = strchr(p, '\0');
int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0;
path = new char[end - p + need_slash + namelen + 1];
memcpy(path, p, end - p);
if (need_slash)
path[end - p] = '/';
strcpy(path + (end - p) + need_slash, name);
#if DEBUG
fprintf(stderr, "searchpath: trying `%s'\n", path);
#endif
if (!access(path, F_OK)) {
#if DEBUG
fprintf(stderr, "searchpath: found `%s'\n", name);
#endif
return path;
}
a_delete path;
if (*end == '\0')
break;
p = end + 1;
}
return 0;
}
char *searchpathext(const char *name, const char *pathext, const char *pathp)
{
char *found = 0;
char *tmpathext = strsave(pathext); char *ext = strtok(tmpathext, PATH_SEP);
while (ext) {
char *namex = new char[strlen(name) + strlen(ext) + 1];
strcpy(namex, name);
strcat(namex, ext);
found = searchpath(namex, pathp);
a_delete namex;
if (found)
break;
ext = strtok(0, PATH_SEP);
}
a_delete tmpathext;
return found;
}
char *msw2posixpath(char *path)
{
char *s = path;
while (*s) {
if (*s == '\\')
*s = '/';
*s++;
}
return path;
}
void set_current_prefix()
{
char *pathextstr;
curr_prefix = new char[path_name_max()];
#ifdef _WIN32
int len = GetModuleFileName(0, curr_prefix, path_name_max());
if (len)
len = GetShortPathName(curr_prefix, curr_prefix, path_name_max());
# if DEBUG
fprintf(stderr, "curr_prefix: %s\n", curr_prefix);
# endif
#else
curr_prefix = searchpath(program_name, getenv("PATH"));
if (!curr_prefix && !strchr(program_name, '.')) { pathextstr = strsave(getenv("PATHEXT"));
if (!pathextstr)
pathextstr = strsave(PATH_EXT);
curr_prefix = searchpathext(program_name, pathextstr, getenv("PATH"));
a_delete pathextstr;
}
if (!curr_prefix)
return;
#endif
msw2posixpath(curr_prefix);
#if DEBUG
fprintf(stderr, "curr_prefix: %s\n", curr_prefix);
#endif
curr_prefix = xdirname(curr_prefix); curr_prefix = xdirname(curr_prefix); curr_prefix_len = strlen(curr_prefix);
#if DEBUG
fprintf(stderr, "curr_prefix: %s\n", curr_prefix);
fprintf(stderr, "curr_prefix_len: %d\n", curr_prefix_len);
#endif
}
char *relocatep(const char *path)
{
#if DEBUG
fprintf(stderr, "relocatep: path = %s\n", path);
fprintf(stderr, "relocatep: INSTALLPATH = %s\n", INSTALLPATH);
fprintf(stderr, "relocatep: INSTALLPATHLEN = %d\n", INSTALLPATHLEN);
#endif
if (!curr_prefix)
set_current_prefix();
if (strncmp(INSTALLPATH, path, INSTALLPATHLEN))
return strsave(path);
char *relative_path = (char *)path + INSTALLPATHLEN;
size_t relative_path_len = strlen(relative_path);
char *relocated_path = new char[curr_prefix_len + relative_path_len + 1];
strcpy(relocated_path, curr_prefix);
strcat(relocated_path, relative_path);
#if DEBUG
fprintf(stderr, "relocated_path: %s\n", relocated_path);
#endif
return relocated_path;
}
char *relocate(const char *path)
{
char *p;
if (access(path, F_OK))
p = relocatep(path);
else
p = strsave(path);
#if DEBUG
fprintf (stderr, "relocate: %s\n", p);
#endif
return p;
}