Krolyxon
Commit bb85d3d

Branches

Refs →

nsxivutil.c

335 lines · 6.6 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
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
29#define DNAME_CNT 512
30#define FNAME_LEN 1024
31
32void cleanup();
33
34void* s_malloc(size_t size) {
35 void *ptr;
36
37 if (!(ptr = malloc(size)))
38 die("could not allocate memory");
39 return ptr;
40}
41
42void* s_realloc(void *ptr, size_t size) {
43 if (!(ptr = realloc(ptr, size)))
44 die("could not allocate memory");
45 return ptr;
46}
47
48void warn(const char* fmt, ...) {
49 va_list args;
50
51 if (!fmt || options->quiet)
52 return;
53
54 va_start(args, fmt);
55 fprintf(stderr, "sxiv: warning: ");
56 vfprintf(stderr, fmt, args);
57 fprintf(stderr, "\n");
58 va_end(args);
59}
60
61void die(const char* fmt, ...) {
62 va_list args;
63
64 if (!fmt)
65 return;
66
67 va_start(args, fmt);
68 fprintf(stderr, "sxiv: error: ");
69 vfprintf(stderr, fmt, args);
70 fprintf(stderr, "\n");
71 va_end(args);
72
73 cleanup();
74 exit(1);
75}
76
77void size_readable(float *size, const char **unit) {
78 const char *units[] = { "", "K", "M", "G" };
79 int i;
80
81 for (i = 0; i < LEN(units) && *size > 1024; ++i)
82 *size /= 1024;
83 *unit = units[MIN(i, LEN(units) - 1)];
84}
85
86char* absolute_path(const char *filename) {
87 size_t len;
88 char *path = NULL;
89 const char *basename;
90 char *dirname = NULL;
91 char *cwd = NULL;
92 char *twd = NULL;
93 char *dir;
94 char *s;
95
96 if (!filename || *filename == '\0' || *filename == '/')
97 return NULL;
98
99 len = FNAME_LEN;
100 cwd = (char*) s_malloc(len);
101 while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
102 len *= 2;
103 cwd = (char*) s_realloc(cwd, len);
104 }
105 if (!s)
106 goto error;
107
108 s = strrchr(filename, '/');
109 if (s) {
110 len = s - filename;
111 dirname = (char*) s_malloc(len + 1);
112 strncpy(dirname, filename, len);
113 dirname[len] = '\0';
114 basename = s + 1;
115
116 if (chdir(cwd))
117 /* we're not able to come back afterwards */
118 goto error;
119 if (chdir(dirname))
120 goto error;
121
122 len = FNAME_LEN;
123 twd = (char*) s_malloc(len);
124 while (!(s = getcwd(twd, len)) && errno == ERANGE) {
125 len *= 2;
126 twd = (char*) s_realloc(twd, len);
127 }
128 if (chdir(cwd))
129 die("could not revert to prior working directory");
130 if (!s)
131 goto error;
132 dir = twd;
133 } else {
134 /* only a single filename given */
135 basename = filename;
136 dir = cwd;
137 }
138
139 len = strlen(dir) + strlen(basename) + 2;
140 path = (char*) s_malloc(len);
141 snprintf(path, len, "%s/%s", dir, basename);
142
143goto end;
144
145error:
146 if (path) {
147 free(path);
148 path = NULL;
149 }
150
151end:
152 if (dirname)
153 free(dirname);
154 if (cwd)
155 free(cwd);
156 if (twd)
157 free(twd);
158
159 return path;
160}
161
162int r_opendir(r_dir_t *rdir, const char *dirname) {
163 if (!rdir || !dirname || !*dirname)
164 return -1;
165
166 if (!(rdir->dir = opendir(dirname))) {
167 rdir->name = NULL;
168 rdir->stack = NULL;
169 return -1;
170 }
171
172 rdir->stcap = DNAME_CNT;
173 rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
174 rdir->stlen = 0;
175
176 rdir->name = (char*) dirname;
177 rdir->d = 0;
178
179 return 0;
180}
181
182int r_closedir(r_dir_t *rdir) {
183 int ret = 0;
184
185 if (!rdir)
186 return -1;
187
188 if (rdir->stack) {
189 while (rdir->stlen > 0)
190 free(rdir->stack[--rdir->stlen]);
191 free(rdir->stack);
192 rdir->stack = NULL;
193 }
194
195 if (rdir->dir) {
196 if (!(ret = closedir(rdir->dir)))
197 rdir->dir = NULL;
198 }
199
200 if (rdir->d && rdir->name) {
201 free(rdir->name);
202 rdir->name = NULL;
203 }
204
205 return ret;
206}
207
208char* r_readdir(r_dir_t *rdir) {
209 size_t len;
210 char *filename;
211 struct dirent *dentry;
212 struct stat fstats;
213
214 if (!rdir || !rdir->dir || !rdir->name)
215 return NULL;
216
217 while (1) {
218 if (rdir->dir && (dentry = readdir(rdir->dir))) {
219 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
220 continue;
221
222 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
223 filename = (char*) s_malloc(len);
224 snprintf(filename, len, "%s%s%s", rdir->name,
225 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
226 dentry->d_name);
227
228 if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
229 /* put subdirectory on the stack */
230 if (rdir->stlen == rdir->stcap) {
231 rdir->stcap *= 2;
232 rdir->stack = (char**) s_realloc(rdir->stack,
233 rdir->stcap * sizeof(char*));
234 }
235 rdir->stack[rdir->stlen++] = filename;
236 continue;
237 }
238 return filename;
239 }
240
241 if (rdir->stlen > 0) {
242 /* open next subdirectory */
243 closedir(rdir->dir);
244 if (rdir->d)
245 free(rdir->name);
246 rdir->name = rdir->stack[--rdir->stlen];
247 rdir->d = 1;
248 if (!(rdir->dir = opendir(rdir->name)))
249 warn("could not open directory: %s", rdir->name);
250 continue;
251 }
252
253 /* no more entries */
254 break;
255 }
256
257 return NULL;
258}
259
260int r_mkdir(const char *path) {
261 char *dir, *d;
262 struct stat stats;
263 int err = 0;
264
265 if (!path || !*path)
266 return -1;
267
268 if (!stat(path, &stats)) {
269 if (S_ISDIR(stats.st_mode)) {
270 return 0;
271 } else {
272 warn("not a directory: %s", path);
273 return -1;
274 }
275 }
276
277 d = dir = (char*) s_malloc(strlen(path) + 1);
278 strcpy(dir, path);
279
280 while (d != NULL && !err) {
281 d = strchr(d + 1, '/');
282 if (d != NULL)
283 *d = '\0';
284 if (access(dir, F_OK) && errno == ENOENT) {
285 if (mkdir(dir, 0755)) {
286 warn("could not create directory: %s", dir);
287 err = -1;
288 }
289 } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
290 warn("not a directory: %s", dir);
291 err = -1;
292 }
293 if (d != NULL)
294 *d = '/';
295 }
296 free(dir);
297
298 return err;
299}
300
301char* readline(FILE *stream) {
302 size_t len;
303 char *buf, *s, *end;
304
305 if (!stream || feof(stream) || ferror(stream))
306 return NULL;
307
308 len = FNAME_LEN;
309 s = buf = (char*) s_malloc(len * sizeof(char));
310
311 do {
312 *s = '\0';
313 fgets(s, len - (s - buf), stream);
314 if ((end = strchr(s, '\n'))) {
315 *end = '\0';
316 } else if (strlen(s) + 1 == len - (s - buf)) {
317 buf = (char*) s_realloc(buf, 2 * len * sizeof(char));
318 s = buf + len - 1;
319 len *= 2;
320 } else {
321 s += strlen(s);
322 }
323 } while (!end && !feof(stream) && !ferror(stream));
324
325 if (ferror(stream)) {
326 s = NULL;
327 } else {
328 s = (char*) s_malloc((strlen(buf) + 1) * sizeof(char));
329 strcpy(s, buf);
330 }
331
332 free(buf);
333
334 return s;
335}