int physfs_util_binrelative_add_to_searchpath(const char *newDir, int appendToPath) { #define BATSP_STRSIZE 1000 const char *const basedir = PHYSFS_getBaseDir(); if (basedir && newDir) { char c; int ndpos = 0; int dpos = 0; const char *const sep = PHYSFS_getDirSeparator(); int seplen = strlen(sep); char newname[BATSP_STRSIZE]; int dotdotcount = 0; newname[BATSP_STRSIZE-1] = '\0'; /* a safeguard... */ if ('/' == newDir[0]) { /* if newDir has been formulated like an absolute path then leave it relative to the pwd rather than the basedir, but still do the unix-directory-like munging. */ ++ndpos; } else { strncpy(&newname[dpos], basedir, BATSP_STRSIZE-1); dpos += strlen(basedir); } do { c = newDir[ndpos]; /* spot '../' or '..[END OF STRING]' */ if (0 == dotdotcount) { if ('.' == c) { ++dotdotcount; } else { dotdotcount = 0; } } else if (1 == dotdotcount) { if ('.' == c) { ++dotdotcount; } else { dotdotcount = 0; } } else if (2 == dotdotcount) { if ('\0' == c || '/' == c) { ++dotdotcount; } else { dotdotcount = 0; } } /* if we saw a '..' in the newDir then strip two directory levels off of newname (one to get rid of '..' and another to get rid of the preceding path segment that it nullifies). */ if (3 == dotdotcount) { int seen_seps = 0; /* iterate backwards past a dirseparator, until the character after the dirseparator preceding that one. */ --dpos; while (dpos >= (1 + seplen) && ! (1 == seen_seps && 0 == strncmp(sep,&newname[dpos - seplen],seplen)) ) { if (0 == strncmp(sep,&newname[dpos],seplen)) { /* just passed a separator while iterating backwards */ ++seen_seps; } --dpos; } dotdotcount = 0; } else { /* we didn't see '..' (yet); copy path chararcter as usual. */ if ('/' != c) { if (dpos < BATSP_STRSIZE-1) { newname[dpos] = c; ++dpos; } } else { /* it's a path separator (treat multiple successive slashes as one); put the system-dependant separator into newname. */ if (ndpos >= 1 && '/' != newDir[ndpos-1]) { int i = 0; while (sep[i] != '\0') { if (dpos < BATSP_STRSIZE-1) { newname[dpos] = sep[i]; ++dpos; } ++i; } } } } ++ndpos; } while ('\0' != c); newname[dpos] = '\0'; /* be very confident that we've written the string terminator... */ /*fprintf(stderr, "adding '%s'\n", newname);*/ return PHYSFS_addToSearchPath(newname, appendToPath); } else { return PHYSFS_addToSearchPath(newDir, appendToPath); } #undef BATSP_STRSIZE }