Krolyxon
Commit 391e6e7

Branches

Refs →

nsxivutil.c

325 lines · 6.3 KB · C

1/* sxiv: util.c
2 * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA.
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <errno.h>
25
26#include "options.h"
27#include "util.h"
28
29enum {
30 DNAME_CNT = 512,
31 FNAME_LEN = 1024
32};
33
34void cleanup();
35
36void* s_malloc(size_t size) {
37 void *ptr;
38
39 if (!(ptr = malloc(size)))
40 die("could not allocate memory");
41 return ptr;
42}
43
44void* s_realloc(void *ptr, size_t size) {
45 if (!(ptr = realloc(ptr, size)))
46 die("could not allocate memory");
47 return ptr;
48}
49
50char* s_strdup(char *s) {
51 char *d = NULL;
52
53 if (s) {
54 if (!(d = malloc(strlen(s) + 1)))
55 die("could not allocate memory");
56 strcpy(d, s);
57 }
58 return d;
59}
60
61void warn(const char* fmt, ...) {
62 va_list args;
63
64 if (!fmt || options->quiet)
65 return;
66
67 va_start(args, fmt);
68 fprintf(stderr, "sxiv: warning: ");
69 vfprintf(stderr, fmt, args);
70 fprintf(stderr, "\n");
71 va_end(args);
72}
73
74void die(const char* fmt, ...) {
75 va_list args;
76
77 if (!fmt)
78 return;
79
80 va_start(args, fmt);
81 fprintf(stderr, "sxiv: error: ");
82 vfprintf(stderr, fmt, args);
83 fprintf(stderr, "\n");
84 va_end(args);
85
86 cleanup();
87 exit(1);
88}
89
90int min_int_nz(int n, ...) {
91 va_list args;
92 int i, a, m = 0;
93
94 va_start(args, n);
95 for (i = 0; i < n; i++) {
96 if ((a = va_arg(args, int)) && (!m || a < m))
97 m = a;
98 }
99 va_end(args);
100 return m;
101}
102
103void size_readable(float *size, const char **unit) {
104 const char *units[] = { "", "K", "M", "G" };
105 int i;
106
107 for (i = 0; i < LEN(units) && *size > 1024; i++)
108 *size /= 1024;
109 *unit = units[MIN(i, LEN(units) - 1)];
110}
111
112char* absolute_path(const char *filename) {
113 size_t len;
114 char *path = NULL;
115 const char *basename;
116 char *dirname = NULL;
117 char *cwd = NULL;
118 char *twd = NULL;
119 char *dir;
120 char *s;
121
122 if (!filename || *filename == '\0' || *filename == '/')
123 return NULL;
124
125 len = FNAME_LEN;
126 cwd = (char*) s_malloc(len);
127 while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
128 len *= 2;
129 cwd = (char*) s_realloc(cwd, len);
130 }
131 if (!s)
132 goto error;
133
134 s = strrchr(filename, '/');
135 if (s) {
136 len = s - filename;
137 dirname = (char*) s_malloc(len + 1);
138 strncpy(dirname, filename, len);
139 dirname[len] = '\0';
140 basename = s + 1;
141
142 if (chdir(cwd))
143 /* we're not able to come back afterwards */
144 goto error;
145 if (chdir(dirname))
146 goto error;
147
148 len = FNAME_LEN;
149 twd = (char*) s_malloc(len);
150 while (!(s = getcwd(twd, len)) && errno == ERANGE) {
151 len *= 2;
152 twd = (char*) s_realloc(twd, len);
153 }
154 if (chdir(cwd))
155 die("could not revert to prior working directory");
156 if (!s)
157 goto error;
158 dir = twd;
159 } else {
160 /* only a single filename given */
161 basename = filename;
162 dir = cwd;
163 }
164
165 len = strlen(dir) + strlen(basename) + 2;
166 path = (char*) s_malloc(len);
167 snprintf(path, len, "%s/%s", dir, basename);
168
169 goto end;
170
171error:
172 if (path) {
173 free(path);
174 path = NULL;
175 }
176
177end:
178 if (dirname)
179 free(dirname);
180 if (cwd)
181 free(cwd);
182 if (twd)
183 free(twd);
184
185 return path;
186}
187
188int r_opendir(r_dir_t *rdir, const char *dirname) {
189 if (!rdir || !dirname || !*dirname)
190 return -1;
191
192 if (!(rdir->dir = opendir(dirname))) {
193 rdir->name = NULL;
194 rdir->stack = NULL;
195 return -1;
196 }
197
198 rdir->stcap = DNAME_CNT;
199 rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
200 rdir->stlen = 0;
201
202 rdir->name = (char*) dirname;
203 rdir->d = 0;
204
205 return 0;
206}
207
208int r_closedir(r_dir_t *rdir) {
209 int ret = 0;
210
211 if (!rdir)
212 return -1;
213
214 if (rdir->stack) {
215 while (rdir->stlen > 0)
216 free(rdir->stack[--rdir->stlen]);
217 free(rdir->stack);
218 rdir->stack = NULL;
219 }
220
221 if (rdir->dir) {
222 if (!(ret = closedir(rdir->dir)))
223 rdir->dir = NULL;
224 }
225
226 if (rdir->d && rdir->name) {
227 free(rdir->name);
228 rdir->name = NULL;
229 }
230
231 return ret;
232}
233
234char* r_readdir(r_dir_t *rdir) {
235 size_t len;
236 char *filename;
237 struct dirent *dentry;
238 struct stat fstats;
239
240 if (!rdir || !rdir->dir || !rdir->name)
241 return NULL;
242
243 while (1) {
244 if (rdir->dir && (dentry = readdir(rdir->dir))) {
245 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
246 continue;
247
248 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
249 filename = (char*) s_malloc(len);
250 snprintf(filename, len, "%s%s%s", rdir->name,
251 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
252 dentry->d_name);
253
254 if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
255 /* put subdirectory on the stack */
256 if (rdir->stlen == rdir->stcap) {
257 rdir->stcap *= 2;
258 rdir->stack = (char**) s_realloc(rdir->stack,
259 rdir->stcap * sizeof(char*));
260 }
261 rdir->stack[rdir->stlen++] = filename;
262 continue;
263 }
264 return filename;
265 }
266
267 if (rdir->stlen > 0) {
268 /* open next subdirectory */
269 closedir(rdir->dir);
270 if (rdir->d)
271 free(rdir->name);
272 rdir->name = rdir->stack[--rdir->stlen];
273 rdir->d = 1;
274 if (!(rdir->dir = opendir(rdir->name)))
275 warn("could not open directory: %s", rdir->name);
276 continue;
277 }
278
279 /* no more entries */
280 break;
281 }
282
283 return NULL;
284}
285
286int r_mkdir(const char *path) {
287 char *dir, *d;
288 struct stat stats;
289 int err = 0;
290
291 if (!path || !*path)
292 return -1;
293
294 if (!stat(path, &stats)) {
295 if (S_ISDIR(stats.st_mode)) {
296 return 0;
297 } else {
298 warn("not a directory: %s", path);
299 return -1;
300 }
301 }
302
303 d = dir = (char*) s_malloc(strlen(path) + 1);
304 strcpy(dir, path);
305
306 while (d != NULL && !err) {
307 d = strchr(d + 1, '/');
308 if (d != NULL)
309 *d = '\0';
310 if (access(dir, F_OK) && errno == ENOENT) {
311 if (mkdir(dir, 0755)) {
312 warn("could not create directory: %s", dir);
313 err = -1;
314 }
315 } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
316 warn("not a directory: %s", dir);
317 err = -1;
318 }
319 if (d != NULL)
320 *d = '/';
321 }
322 free(dir);
323
324 return err;
325}