#define HTS_BUILDING_LIBRARY
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "os.h"
#ifndef PATH_MAX
# define PATH_MAX 1024
#endif
#include "open_trace_file.h"
#include "misc.h"
#include "../htslib/hfile.h"
#include "../htslib/hts_log.h"
#include "../htslib/hts.h"
static int is_file(char *fn) {
struct stat buf;
if ( stat(fn,&buf) ) return 0;
return S_ISREG(buf.st_mode);
}
char *tokenise_search_path(const char *searchpath) {
char *newsearch;
unsigned int i, j;
size_t len;
char path_sep = HTS_PATH_SEPARATOR_CHAR;
if (!searchpath)
searchpath="";
newsearch = (char *)malloc((len = strlen(searchpath))+5);
if (!newsearch)
return NULL;
for (i = 0, j = 0; i < len; i++) {
if (i < len-1 && searchpath[i] == ':' && searchpath[i+1] == ':') {
newsearch[j++] = ':';
i++;
continue;
}
if (path_sep == ':') {
if ((i == 0 || (i > 0 && searchpath[i-1] == ':')) &&
(!strncmp(&searchpath[i], "http:", 5) ||
!strncmp(&searchpath[i], "https:", 6) ||
!strncmp(&searchpath[i], "ftp:", 4) ||
!strncmp(&searchpath[i], "|http:", 6) ||
!strncmp(&searchpath[i], "|https:", 7) ||
!strncmp(&searchpath[i], "|ftp:", 5) ||
!strncmp(&searchpath[i], "URL=http:", 9) ||
!strncmp(&searchpath[i], "URL=https:",10)||
!strncmp(&searchpath[i], "URL=ftp:", 8))) {
do {
newsearch[j++] = searchpath[i];
} while (i<len && searchpath[i++] != ':');
if (searchpath[i] == ':')
i++;
if (searchpath[i]=='/')
newsearch[j++] = searchpath[i++];
if (searchpath[i]=='/')
newsearch[j++] = searchpath[i++];
do {
newsearch[j++] = searchpath[i++];
} while (i<len && searchpath[i] != ':' && searchpath[i] != '/');
newsearch[j++] = searchpath[i++];
if (searchpath[i] == ':')
i++;
}
}
if (searchpath[i] == path_sep) {
if (j && newsearch[j-1] != 0)
newsearch[j++] = 0;
} else {
newsearch[j++] = searchpath[i];
}
}
if (j)
newsearch[j++] = 0;
newsearch[j++] = '.';
newsearch[j++] = '/';
newsearch[j++] = 0;
newsearch[j++] = 0;
return newsearch;
}
static char *expand_path(const char *file, char *dirname, int max_s_digits);
mFILE *find_file_url(const char *file, char *url) {
char *path = NULL, buf[8192];
mFILE *mf = NULL;
ssize_t len;
hFILE *hf = NULL;
path = expand_path(file, url, 1);
if (!path)
return NULL;
if (!(hf = hopen(path, "r"))) {
if (errno != ENOENT)
hts_log_warning("Failed to open reference \"%s\": %s", path, strerror(errno));
goto fail;
}
if (NULL == (mf = mfcreate(NULL, 0)))
goto fail;
while ((len = hread(hf, buf, sizeof(buf))) > 0) {
if (mfwrite(buf, len, 1, mf) <= 0) {
hclose_abruptly(hf);
goto fail;
}
}
if (hclose(hf) < 0 || len < 0) {
hts_log_warning("Failed to read reference \"%s\": %s", path, strerror(errno));
goto fail;
}
free(path);
mrewind(mf);
return mf;
fail:
mfdestroy(mf);
free(path);
return NULL;
}
static char *expand_path(const char *file, char *dirname, int max_s_digits) {
size_t len = strlen(dirname);
size_t lenf = strlen(file);
char *cp, *path;
path = malloc(len+lenf+2); if (!path) {
hts_log_error("Out of memory");
return NULL;
}
if (dirname[len-1] == '/')
len--;
if (*file == '/' || (len==1 && *dirname == '.')) {
memcpy(path, file, lenf + 1);
} else {
char *path_end = path;
*path = 0;
while ((cp = strchr(dirname, '%'))) {
char *endp;
long l = strtol(cp+1, &endp, 10);
if (*endp != 's' || endp - cp - 1 > max_s_digits) {
strncpy(path_end, dirname, (endp+1)-dirname);
path_end += (endp+1)-dirname;
dirname = endp+1;
continue;
}
strncpy(path_end, dirname, cp-dirname);
path_end += cp-dirname;
if (l) {
strncpy(path_end, file, l);
path_end += MIN(strlen(file), l);
file += MIN(strlen(file), l);
} else {
strcpy(path_end, file);
path_end += strlen(file);
file += strlen(file);
}
len -= (endp+1) - dirname;
dirname = endp+1;
}
strncpy(path_end, dirname, len);
path_end += MIN(strlen(dirname), len);
*path_end = 0;
if (*file) {
*path_end++ = '/';
strcpy(path_end, file);
}
}
return path;
}
static mFILE *find_file_dir(const char *file, char *dirname) {
char *path;
mFILE *mf = NULL;
path = expand_path(file, dirname, INT_MAX);
if (!path)
return NULL;
if (is_file(path))
mf = mfopen(path, "rbm");
free(path);
return mf;
}
mFILE *open_path_mfile(const char *file, char *path, char *relative_to) {
char *newsearch;
char *ele;
mFILE *fp;
if (!path)
path = getenv("RAWDATA");
if (NULL == (newsearch = tokenise_search_path(path)))
return NULL;
for (ele = newsearch; *ele; ele += strlen(ele)+1) {
char *ele2;
if (*ele == '|') {
ele2 = ele+1;
} else {
ele2 = ele;
}
if (0 == strncmp(ele2, "URL=", 4)) {
if ((fp = find_file_url(file, ele2+4))) {
free(newsearch);
return fp;
}
} else if (!strncmp(ele2, "http:", 5) ||
!strncmp(ele2, "https:", 6) ||
!strncmp(ele2, "ftp:", 4)) {
if ((fp = find_file_url(file, ele2))) {
free(newsearch);
return fp;
}
} else if ((fp = find_file_dir(file, ele2))) {
free(newsearch);
return fp;
}
}
free(newsearch);
if (relative_to) {
char *cp;
char relative_path[PATH_MAX+1];
strcpy(relative_path, relative_to);
if ((cp = strrchr(relative_path, '/')))
*cp = 0;
if ((fp = find_file_dir(file, relative_path)))
return fp;
}
return NULL;
}
char *find_path(const char *file, const char *path) {
char *newsearch;
char *ele;
char *outpath = NULL;
if (!path)
path = getenv("RAWDATA");
if (NULL == (newsearch = tokenise_search_path(path)))
return NULL;
for (ele = newsearch; *ele; ele += strlen(ele)+1) {
char *ele2 = (*ele == '|') ? ele+1 : ele;
if (!strncmp(ele2, "URL=", 4) ||
!strncmp(ele2, "http:", 5) ||
!strncmp(ele2, "https:", 6) ||
!strncmp(ele2, "ftp:", 4)) {
continue;
} else {
outpath = expand_path(file, ele2, INT_MAX);
if (is_file(outpath)) {
free(newsearch);
return outpath;
} else {
free(outpath);
}
}
}
free(newsearch);
return NULL;
}