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 <cx/string.h>
36 char* util_concat_path(const char *url_base, const char *p) {
37 cxstring base = cx_str(url_base);
42 path = cx_strn("", 0);
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 = cx_strcat(3, base, cx_strn("/", 1), path);
60 url = cx_strcat(2, base, path);
66 const char* util_resource_name(const char *url) {
67 cxstring urlstr = cx_str(url);
68 if(urlstr.length == 0) {
71 if(urlstr.ptr[urlstr.length-1] == '/') {
74 cxstring resname = cx_strrchr(urlstr, '/');
75 if(resname.length > 1) {
82 char* util_parent_path(const char *path) {
83 const char *name = util_resource_name(path);
84 size_t namelen = strlen(name);
85 size_t pathlen = strlen(path);
86 size_t parentlen = pathlen - namelen;
87 char *parent = malloc(parentlen + 1);
88 memcpy(parent, path, parentlen);
89 parent[parentlen] = '\0';
93 #define FIND_NEXT_MAX_FILES 2000
95 typedef int (*cmpfnc)(const void *, const void *);
97 int fcmp(const void *d1, const void *d2) {
98 const char **f1 = (const char **)d1;
99 const char **f2 = (const char **)d2;
100 int r = strcmp(*f1, *f2);
104 char* util_find_next_file(char *current_file) {
105 char *current_folder = util_parent_path(current_file);
106 const char *current_file_name = util_resource_name(current_file);
107 DIR *dir = opendir(current_folder);
109 fprintf(stderr, "Error: Cannot open directory '%s': %s\n", current_folder, strerror(errno));
110 free(current_folder);
116 char **files = calloc(falloc, sizeof(char*));
120 while((ent = readdir(dir))) {
121 if(ent->d_name[0] == '.') {
122 // skip '.', '..' and dot-files
127 char *abs_path = util_concat_path(current_folder, ent->d_name);
129 int r = stat(abs_path, &s);
135 // we only want regular files
136 if(!S_ISREG(s.st_mode)) {
141 if(nfiles >= falloc) {
143 if(falloc > FIND_NEXT_MAX_FILES) {
147 files = realloc(files, falloc * sizeof(char*));
149 files[nfiles] = strdup(ent->d_name);
156 qsort(files, nfiles, sizeof(char*), fcmp);
157 // search array for current file and return the successor
158 for(int i=0;i<nfiles;i++) {
160 if(!strcmp(files[i], current_file_name)) {
162 result = util_concat_path(current_folder, files[i+1]);
170 for(int i=0;i<nfiles;i++) {
174 free(current_folder);