2 * Copyright 2022 Olaf Wintermann
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
33 #include <ucx/string.h>
36 char* util_concat_path(const char *url_base, const char *p) {
37 sstr_t base = sstr((char*)url_base);
40 path = sstr((char*)p);
45 int add_separator = 0;
46 if(base.length != 0 && base.ptr[base.length-1] == '/') {
47 if(path.ptr[0] == '/') {
51 if(path.length == 0 || path.ptr[0] != '/') {
58 url = sstrcat(3, base, sstr("/"), path);
60 url = sstrcat(2, base, path);
66 char* util_resource_name(char *url) {
67 sstr_t urlstr = sstr(url);
68 if(urlstr.ptr[urlstr.length-1] == '/') {
71 sstr_t resname = sstrrchr(urlstr, '/');
72 if(resname.length > 1) {
79 char* util_parent_path(const char *path) {
80 char *name = util_resource_name((char*)path);
81 size_t namelen = strlen(name);
82 size_t pathlen = strlen(path);
83 size_t parentlen = pathlen - namelen;
84 char *parent = malloc(parentlen + 1);
85 memcpy(parent, path, parentlen);
86 parent[parentlen] = '\0';
90 #define FIND_NEXT_MAX_FILES 2000
92 typedef int (*cmpfnc)(const void *, const void *);
94 int fcmp(const void *d1, const void *d2) {
95 const char **f1 = (const char **)d1;
96 const char **f2 = (const char **)d2;
97 int r = strcmp(*f1, *f2);
101 char* util_find_next_file(char *current_file) {
102 char *current_folder = util_parent_path(current_file);
103 char *current_file_name = util_resource_name(current_file);
104 DIR *dir = opendir(current_folder);
106 fprintf(stderr, "Error: Cannot open directory '%s': %s\n", current_folder, strerror(errno));
107 free(current_folder);
113 char **files = calloc(falloc, sizeof(char*));
117 while((ent = readdir(dir))) {
118 if(ent->d_name[0] == '.') {
119 // skip '.', '..' and dot-files
124 char *abs_path = util_concat_path(current_folder, ent->d_name);
126 int r = stat(abs_path, &s);
132 // we only want regular files
133 if(!S_ISREG(s.st_mode)) {
138 if(nfiles >= falloc) {
140 if(falloc > FIND_NEXT_MAX_FILES) {
144 files = realloc(files, falloc * sizeof(char*));
146 files[nfiles] = strdup(ent->d_name);
153 qsort(files, nfiles, sizeof(char*), fcmp);
154 // search array for current file and return the successor
155 for(int i=0;i<nfiles;i++) {
157 if(!strcmp(files[i], current_file_name)) {
159 result = util_concat_path(current_folder, files[i+1]);
167 for(int i=0;i<nfiles;i++) {
171 free(current_folder);