static char *
pathfind( char const * path,
char const * fname,
char const * mode );
#include "compat.h"
#ifndef HAVE_PATHFIND
#if defined(__windows__) && !defined(__CYGWIN__)
static char *
pathfind( char const * path,
char const * fname,
char const * mode )
{
return strdup(fname);
}
#else
static char * make_absolute(char const * string, char const * dot_path);
static char * canonicalize_pathname(char * path);
static char * extract_colon_unit(char * dir, char const * string, int * p_index);
static char *
pathfind( char const * path,
char const * fname,
char const * mode )
{
int p_index = 0;
int mode_bits = 0;
char * res_path = NULL;
char zPath[ AG_PATH_MAX + 1 ];
if (strchr( mode, 'r' )) mode_bits |= R_OK;
if (strchr( mode, 'w' )) mode_bits |= W_OK;
if (strchr( mode, 'x' )) mode_bits |= X_OK;
for (;;) {
DIR * dirP;
char * colon_unit = extract_colon_unit( zPath, path, &p_index );
if (colon_unit == NULL)
break;
dirP = opendir( colon_unit );
if (dirP == NULL)
continue;
for (;;) {
struct dirent *entP = readdir( dirP );
if (entP == (struct dirent *)NULL)
break;
if (strcmp(entP->d_name, fname) == 0) {
char * abs_name = make_absolute(fname, colon_unit);
if (access(abs_name, mode_bits) >= 0) {
res_path = canonicalize_pathname(abs_name);
}
free(abs_name);
break;
}
}
closedir( dirP );
if (res_path != NULL)
break;
}
return res_path;
}
static char *
make_absolute( char const * string, char const * dot_path )
{
char * result;
int result_len;
if (!dot_path || *string == '/') {
result = strdup( string );
if (result == NULL) {
return NULL;
}
} else {
if (dot_path && dot_path[0]) {
result = malloc( 2 + strlen( dot_path ) + strlen( string ) );
if (result == NULL) {
return NULL;
}
strcpy( result, dot_path );
result_len = (int)strlen(result);
if (result[result_len - 1] != '/') {
result[result_len++] = '/';
result[result_len] = '\0';
}
} else {
result = malloc( 3 + strlen( string ) );
if (result == NULL) {
return NULL;
}
result[0] = '.'; result[1] = '/'; result[2] = '\0';
result_len = 2;
}
strcpy( result + result_len, string );
}
return result;
}
static char *
canonicalize_pathname( char *path )
{
int i, start;
char stub_char, *result;
result = strdup( path );
if (result == NULL) {
return NULL;
}
stub_char = (*path == '/') ? '/' : '.';
i = 0;
while (result[i]) {
while (result[i] != '\0' && result[i] != '/')
i++;
start = i++;
if (!result[start])
break;
while (result[i] == '/')
i++;
#if !defined (apollo)
if ((start + 1) != i)
#else
if ((start + 1) != i && (start != 0 || i != 2))
#endif
{
strcpy( result + start + 1, result + i );
i = start + 1;
}
if (start > 0 && result[start - 1] == '\\')
continue;
if ((start && !result[i])
|| (result[i] == '.' && !result[i+1])) {
result[--i] = '\0';
break;
}
if (result[i] == '.') {
if (result[i + 1] == '/') {
strcpy( result + i, result + i + 1 );
i = (start < 0) ? 0 : start;
continue;
}
if (result[i + 1] == '.' &&
(result[i + 2] == '/' || !result[i + 2])) {
while (--start > -1 && result[start] != '/')
;
strcpy( result + start + 1, result + i + 2 );
i = (start < 0) ? 0 : start;
continue;
}
}
}
if (!*result) {
*result = stub_char;
result[1] = '\0';
}
return result;
}
static char *
extract_colon_unit(char * pzDir, char const * string, int * p_index)
{
char * pzDest = pzDir;
int ix = *p_index;
if (string == NULL)
return NULL;
if ((unsigned)ix >= strlen( string ))
return NULL;
{
char const * pzSrc = string + ix;
while (*pzSrc == ':') pzSrc++;
for (;;) {
char ch = (*(pzDest++) = *(pzSrc++));
switch (ch) {
case ':':
pzDest[-1] = NUL;
case NUL:
goto copy_done;
}
if ((unsigned long)(pzDest - pzDir) >= AG_PATH_MAX)
break;
} copy_done:;
ix = (int)(pzSrc - string);
}
if (*pzDir == NUL)
return NULL;
*p_index = ix;
return pzDir;
}
#endif
#endif