void separatePath(const char* path, char* dirname, char* basename, char* extension) { if (!path) { return; } char* dotPoint = strrchr(path, '.'); char* separatorPoint = strnrstr(path, PATH_SEP, strlen(path)); if (separatorPoint) { if (dirname) { ptrdiff_t len = separatorPoint - path; if (PATH_MAX <= len) { len = PATH_MAX - 1; } else if (!len) { len = 1; } strncpy(dirname, path, len); dirname[len] = '\0'; } path = separatorPoint + 1; } else if (dirname) { strcpy(dirname, "."); } if (basename) { size_t len; if (dotPoint) { len = dotPoint - path; } else { len = strlen(path); } if (PATH_MAX <= len) { len = PATH_MAX - 1; } strncpy(basename, path, len); basename[len] = '\0'; } if (extension) { if (dotPoint) { ++dotPoint; size_t len = strlen(dotPoint); if (PATH_MAX <= len) { len = PATH_MAX - 1; } strncpy(extension, dotPoint, len); extension[len] = '\0'; } else { extension[0] = '\0'; } } }
struct VFile* VDirFindNextAvailable(struct VDir* dir, const char* basename, const char* infix, const char* suffix, int mode) { if (!dir) { return 0; } dir->rewind(dir); struct VDirEntry* dirent; size_t prefixLen = strlen(basename); size_t infixLen = strlen(infix); char path[PATH_MAX]; unsigned next = 0; while ((dirent = dir->listNext(dir))) { const char* filename = dirent->name(dirent); const char* dotPoint = strrchr(filename, '.'); size_t len = strlen(filename); if (dotPoint) { len = (dotPoint - filename); } const char* separator = strnrstr(filename, infix, len); if (!separator) { continue; } len = separator - filename; if (len != prefixLen) { continue; } if (strncmp(filename, basename, prefixLen) == 0) { int nlen; separator += infixLen; snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix); unsigned increment; if (sscanf(separator, path, &increment, &nlen) < 1) { continue; } len = strlen(separator); if (nlen < (ssize_t) len) { continue; } if (next <= increment) { next = increment + 1; } } } snprintf(path, PATH_MAX - 1, "%s%s%u%s", basename, infix, next, suffix); path[PATH_MAX - 1] = '\0'; return dir->openFile(dir, path, mode); }
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) { char path[PATH_MAX]; path[PATH_MAX - 1] = '\0'; char realPrefix[PATH_MAX]; realPrefix[PATH_MAX - 1] = '\0'; if (!dir) { if (!realPath) { return 0; } const char* separatorPoint = strrchr(realPath, '/'); const char* dotPoint; size_t len; if (!separatorPoint) { strcpy(path, "./"); separatorPoint = realPath; dotPoint = strrchr(realPath, '.'); } else { path[0] = '\0'; dotPoint = strrchr(separatorPoint, '.'); if (separatorPoint - realPath + 1 >= PATH_MAX - 1) { return 0; } len = separatorPoint - realPath; strncat(path, realPath, len); path[len] = '\0'; ++separatorPoint; } if (dotPoint - realPath + 1 >= PATH_MAX - 1) { return 0; } if (dotPoint >= separatorPoint) { len = dotPoint - separatorPoint; } else { len = PATH_MAX - 1; } strncpy(realPrefix, separatorPoint, len); realPrefix[len] = '\0'; prefix = realPrefix; dir = VDirOpen(path); } if (!dir) { // This shouldn't be possible return 0; } dir->rewind(dir); struct VDirEntry* dirent; size_t prefixLen = strlen(prefix); size_t infixLen = strlen(infix); unsigned next = 0; while ((dirent = dir->listNext(dir))) { const char* filename = dirent->name(dirent); char* dotPoint = strrchr(filename, '.'); size_t len = strlen(filename); if (dotPoint) { len = (dotPoint - filename); } const char* separator = strnrstr(filename, infix, len); if (!separator) { continue; } len = separator - filename; if (len != prefixLen) { continue; } if (strncmp(filename, prefix, prefixLen) == 0) { int nlen; separator += infixLen; snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix); unsigned increment; if (sscanf(separator, path, &increment, &nlen) < 1) { continue; } len = strlen(separator); if (nlen < (ssize_t) len) { continue; } if (next <= increment) { next = increment + 1; } } } snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix); path[PATH_MAX - 1] = '\0'; return dir->openFile(dir, path, mode); }