Krolyxon
Commit 3a4f386

Branches

Refs →

nsxivutil.c

312 lines · 6.1 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 modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth 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
90void size_readable(float *size, const char **unit) {
91 const char *units[] = { "", "K", "M", "G" };
92 int i;
93
94 for (i = 0; i < ARRLEN(units) && *size > 1024; i++)
95 *size /= 1024;
96 *unit = units[MIN(i, ARRLEN(units) - 1)];
97}
98
99char* absolute_path(const char *filename) {
100 size_t len;
101 char *path = NULL;
102 const char *basename;
103 char *dirname = NULL;
104 char *cwd = NULL;
105 char *twd = NULL;
106 char *dir;
107 char *s;
108
109 if (!filename || *filename == '\0' || *filename == '/')
110 return NULL;
111
112 len = FNAME_LEN;
113 cwd = (char*) s_malloc(len);
114 while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
115 len *= 2;
116 cwd = (char*) s_realloc(cwd, len);
117 }
118 if (!s)
119 goto error;
120
121 s = strrchr(filename, '/');
122 if (s) {
123 len = s - filename;
124 dirname = (char*) s_malloc(len + 1);
125 strncpy(dirname, filename, len);
126 dirname[len] = '\0';
127 basename = s + 1;
128
129 if (chdir(cwd))
130 /* we're not able to come back afterwards */
131 goto error;
132 if (chdir(dirname))
133 goto error;
134
135 len = FNAME_LEN;
136 twd = (char*) s_malloc(len);
137 while (!(s = getcwd(twd, len)) && errno == ERANGE) {
138 len *= 2;
139 twd = (char*) s_realloc(twd, len);
140 }
141 if (chdir(cwd))
142 die("could not revert to prior working directory");
143 if (!s)
144 goto error;
145 dir = twd;
146 } else {
147 /* only a single filename given */
148 basename = filename;
149 dir = cwd;
150 }
151
152 len = strlen(dir) + strlen(basename) + 2;
153 path = (char*) s_malloc(len);
154 snprintf(path, len, "%s/%s", dir, basename);
155
156 goto end;
157
158error:
159 if (path) {
160 free(path);
161 path = NULL;
162 }
163
164end:
165 if (dirname)
166 free(dirname);
167 if (cwd)
168 free(cwd);
169 if (twd)
170 free(twd);
171
172 return path;
173}
174
175int r_opendir(r_dir_t *rdir, const char *dirname) {
176 if (!rdir || !dirname || !*dirname)
177 return -1;
178
179 if (!(rdir->dir = opendir(dirname))) {
180 rdir->name = NULL;
181 rdir->stack = NULL;
182 return -1;
183 }
184
185 rdir->stcap = DNAME_CNT;
186 rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
187 rdir->stlen = 0;
188
189 rdir->name = (char*) dirname;
190 rdir->d = 0;
191
192 return 0;
193}
194
195int r_closedir(r_dir_t *rdir) {
196 int ret = 0;
197
198 if (!rdir)
199 return -1;
200
201 if (rdir->stack) {
202 while (rdir->stlen > 0)
203 free(rdir->stack[--rdir->stlen]);
204 free(rdir->stack);
205 rdir->stack = NULL;
206 }
207
208 if (rdir->dir) {
209 if (!(ret = closedir(rdir->dir)))
210 rdir->dir = NULL;
211 }
212
213 if (rdir->d && rdir->name) {
214 free(rdir->name);
215 rdir->name = NULL;
216 }
217
218 return ret;
219}
220
221char* r_readdir(r_dir_t *rdir) {
222 size_t len;
223 char *filename;
224 struct dirent *dentry;
225 struct stat fstats;
226
227 if (!rdir || !rdir->dir || !rdir->name)
228 return NULL;
229
230 while (1) {
231 if (rdir->dir && (dentry = readdir(rdir->dir))) {
232 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
233 continue;
234
235 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
236 filename = (char*) s_malloc(len);
237 snprintf(filename, len, "%s%s%s", rdir->name,
238 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
239 dentry->d_name);
240
241 if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
242 /* put subdirectory on the stack */
243 if (rdir->stlen == rdir->stcap) {
244 rdir->stcap *= 2;
245 rdir->stack = (char**) s_realloc(rdir->stack,
246 rdir->stcap * sizeof(char*));
247 }
248 rdir->stack[rdir->stlen++] = filename;
249 continue;
250 }
251 return filename;
252 }
253
254 if (rdir->stlen > 0) {
255 /* open next subdirectory */
256 closedir(rdir->dir);
257 if (rdir->d)
258 free(rdir->name);
259 rdir->name = rdir->stack[--rdir->stlen];
260 rdir->d = 1;
261 if (!(rdir->dir = opendir(rdir->name)))
262 warn("could not open directory: %s", rdir->name);
263 continue;
264 }
265
266 /* no more entries */
267 break;
268 }
269
270 return NULL;
271}
272
273int r_mkdir(const char *path) {
274 char *dir, *d;
275 struct stat stats;
276 int err = 0;
277
278 if (!path || !*path)
279 return -1;
280
281 if (!stat(path, &stats)) {
282 if (S_ISDIR(stats.st_mode)) {
283 return 0;
284 } else {
285 warn("not a directory: %s", path);
286 return -1;
287 }
288 }
289
290 d = dir = (char*) s_malloc(strlen(path) + 1);
291 strcpy(dir, path);
292
293 while (d != NULL && !err) {
294 d = strchr(d + 1, '/');
295 if (d != NULL)
296 *d = '\0';
297 if (access(dir, F_OK) && errno == ENOENT) {
298 if (mkdir(dir, 0755)) {
299 warn("could not create directory: %s", dir);
300 err = -1;
301 }
302 } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
303 warn("not a directory: %s", dir);
304 err = -1;
305 }
306 if (d != NULL)
307 *d = '/';
308 }
309 free(dir);
310
311 return err;
312}