Krolyxon
Commit b8ff167

Branches

Refs →

nsxivutil.c

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