Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 354 lines (291 sloc) 7.074 kb
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
1 /* sxiv: util.c
2 * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3 *
d585b86 @muennich Reformated license header
authored
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.
8763f69 @muennich Corrected FSF address in license headers
authored
8 *
d585b86 @muennich Reformated license header
authored
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.
8763f69 @muennich Corrected FSF address in license headers
authored
13 *
d585b86 @muennich Reformated license header
authored
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.
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
17 */
18
6e575b0 @muennich Strict conformance to IEEE Std 1003.1-2001
authored
19 #define _POSIX_C_SOURCE 200112L
20
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
21 #include <stdlib.h>
26cc5af @muennich Read filenames from stdin
authored
22 #include <string.h>
92709b2 @muennich Use directory structure in cache dir
authored
23 #include <sys/types.h>
24 #include <sys/stat.h>
c21a3e3 @muennich Write thumbnail cache files on exit
authored
25 #include <unistd.h>
26 #include <errno.h>
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
27
28 #include "options.h"
29 #include "util.h"
30
b8ff167 @muennich Major code refactoring
authored
31 enum {
6e575b0 @muennich Strict conformance to IEEE Std 1003.1-2001
authored
32 BUF_SIZE = 1024,
b8ff167 @muennich Major code refactoring
authored
33 DNAME_CNT = 512,
34 FNAME_LEN = 1024
35 };
26cc5af @muennich Read filenames from stdin
authored
36
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
37 void cleanup();
38
39 void* s_malloc(size_t size) {
40 void *ptr;
41
42 if (!(ptr = malloc(size)))
43 die("could not allocate memory");
44 return ptr;
45 }
46
47 void* s_realloc(void *ptr, size_t size) {
48 if (!(ptr = realloc(ptr, size)))
49 die("could not allocate memory");
50 return ptr;
51 }
52
ff013dd @muennich Revised handling of file names & paths
authored
53 char* s_strdup(char *s) {
54 char *d = NULL;
55
56 if (s) {
57 if (!(d = malloc(strlen(s) + 1)))
58 die("could not allocate memory");
59 strcpy(d, s);
60 }
61 return d;
62 }
63
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
64 void warn(const char* fmt, ...) {
65 va_list args;
66
67 if (!fmt || options->quiet)
68 return;
69
70 va_start(args, fmt);
71 fprintf(stderr, "sxiv: warning: ");
e8cf8da @muennich Fixed die/warn in util.c
authored
72 vfprintf(stderr, fmt, args);
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
73 fprintf(stderr, "\n");
74 va_end(args);
75 }
76
77 void die(const char* fmt, ...) {
78 va_list args;
79
80 if (!fmt)
81 return;
82
83 va_start(args, fmt);
84 fprintf(stderr, "sxiv: error: ");
e8cf8da @muennich Fixed die/warn in util.c
authored
85 vfprintf(stderr, fmt, args);
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
86 fprintf(stderr, "\n");
87 va_end(args);
88
89 cleanup();
90 exit(1);
91 }
bad9a70 @muennich Display filesize in window title
authored
92
6e575b0 @muennich Strict conformance to IEEE Std 1003.1-2001
authored
93 ssize_t get_line(char **buf, size_t *n, FILE *stream) {
94 size_t len;
95 char *s;
96
97 if (!stream || feof(stream) || ferror(stream))
98 return -1;
99
100 if (!*buf || !*n) {
101 *n = BUF_SIZE;
102 *buf = (char*) s_malloc(*n);
103 }
104 s = *buf;
105
106 while (1) {
107 if (!fgets(s, *n - (s - *buf), stream))
108 return -1;
109 len = strlen(s);
110 if (feof(stream))
111 break;
112 if (len > 0 && s[len-1] == '\n')
113 break;
114 if (len + 1 == *n - (s - *buf)) {
115 *buf = (char*) s_realloc(*buf, 2 * *n);
116 s = *buf + *n - 1;
117 *n *= 2;
118 } else {
119 s += len;
120 }
121 }
122
123 return s - *buf + len;
124 }
125
bad9a70 @muennich Display filesize in window title
authored
126 void size_readable(float *size, const char **unit) {
127 const char *units[] = { "", "K", "M", "G" };
128 int i;
129
5105127 @muennich Added slideshow support
authored
130 for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++)
131 *size /= 1024.0;
132 *unit = units[MIN(i, ARRLEN(units) - 1)];
133 }
134
135 void time_readable(float *time, const char **unit) {
136 const char *units[] = { "s", "m", "h" };
137 int i;
138
139 for (i = 0; i < ARRLEN(units) && *time >= 60.0; i++)
140 *time /= 60.0;
711494a @muennich Avoid conflicting macros
authored
141 *unit = units[MIN(i, ARRLEN(units) - 1)];
bad9a70 @muennich Display filesize in window title
authored
142 }
26cc5af @muennich Read filenames from stdin
authored
143
c21a3e3 @muennich Write thumbnail cache files on exit
authored
144 char* absolute_path(const char *filename) {
145 size_t len;
146 const char *basename;
6e575b0 @muennich Strict conformance to IEEE Std 1003.1-2001
authored
147 char *dir, *dirname = NULL, *path = NULL, *s;
148 char *cwd = NULL, *twd = NULL;
c21a3e3 @muennich Write thumbnail cache files on exit
authored
149
150 if (!filename || *filename == '\0' || *filename == '/')
151 return NULL;
152
153 len = FNAME_LEN;
154 cwd = (char*) s_malloc(len);
155 while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
156 len *= 2;
157 cwd = (char*) s_realloc(cwd, len);
158 }
159 if (!s)
160 goto error;
161
162 s = strrchr(filename, '/');
163 if (s) {
164 len = s - filename;
165 dirname = (char*) s_malloc(len + 1);
166 strncpy(dirname, filename, len);
167 dirname[len] = '\0';
168 basename = s + 1;
169
170 if (chdir(cwd))
171 /* we're not able to come back afterwards */
172 goto error;
173 if (chdir(dirname))
174 goto error;
175
176 len = FNAME_LEN;
177 twd = (char*) s_malloc(len);
178 while (!(s = getcwd(twd, len)) && errno == ERANGE) {
179 len *= 2;
180 twd = (char*) s_realloc(twd, len);
181 }
182 if (chdir(cwd))
f93f4d8 @muennich Write cache file for thumbnail directly after creating it
authored
183 die("could not revert to prior working directory");
c21a3e3 @muennich Write thumbnail cache files on exit
authored
184 if (!s)
185 goto error;
186 dir = twd;
187 } else {
188 /* only a single filename given */
189 basename = filename;
190 dir = cwd;
191 }
192
193 len = strlen(dir) + strlen(basename) + 2;
194 path = (char*) s_malloc(len);
195 snprintf(path, len, "%s/%s", dir, basename);
196
ea23115 @muennich Use getline instead of readline
authored
197 goto end;
c21a3e3 @muennich Write thumbnail cache files on exit
authored
198
199 error:
200 if (path) {
201 free(path);
202 path = NULL;
203 }
204
205 end:
206 if (dirname)
207 free(dirname);
208 if (cwd)
209 free(cwd);
210 if (twd)
211 free(twd);
212
213 return path;
214 }
215
a90bd1c @muennich Refactored recursive directory util functions
authored
216 int r_opendir(r_dir_t *rdir, const char *dirname) {
217 if (!rdir || !dirname || !*dirname)
218 return -1;
219
220 if (!(rdir->dir = opendir(dirname))) {
221 rdir->name = NULL;
222 rdir->stack = NULL;
223 return -1;
224 }
225
226 rdir->stcap = DNAME_CNT;
227 rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
228 rdir->stlen = 0;
229
230 rdir->name = (char*) dirname;
231 rdir->d = 0;
232
233 return 0;
234 }
235
236 int r_closedir(r_dir_t *rdir) {
237 int ret = 0;
238
239 if (!rdir)
240 return -1;
241
242 if (rdir->stack) {
243 while (rdir->stlen > 0)
244 free(rdir->stack[--rdir->stlen]);
245 free(rdir->stack);
246 rdir->stack = NULL;
247 }
248
249 if (rdir->dir) {
250 if (!(ret = closedir(rdir->dir)))
251 rdir->dir = NULL;
252 }
253
254 if (rdir->d && rdir->name) {
255 free(rdir->name);
256 rdir->name = NULL;
257 }
258
259 return ret;
260 }
261
262 char* r_readdir(r_dir_t *rdir) {
263 size_t len;
264 char *filename;
265 struct dirent *dentry;
266 struct stat fstats;
267
268 if (!rdir || !rdir->dir || !rdir->name)
269 return NULL;
270
271 while (1) {
272 if (rdir->dir && (dentry = readdir(rdir->dir))) {
273 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
274 continue;
275
276 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
277 filename = (char*) s_malloc(len);
278 snprintf(filename, len, "%s%s%s", rdir->name,
279 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
280 dentry->d_name);
281
282 if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
283 /* put subdirectory on the stack */
284 if (rdir->stlen == rdir->stcap) {
285 rdir->stcap *= 2;
286 rdir->stack = (char**) s_realloc(rdir->stack,
287 rdir->stcap * sizeof(char*));
288 }
289 rdir->stack[rdir->stlen++] = filename;
290 continue;
291 }
292 return filename;
293 }
294
295 if (rdir->stlen > 0) {
296 /* open next subdirectory */
297 closedir(rdir->dir);
298 if (rdir->d)
299 free(rdir->name);
300 rdir->name = rdir->stack[--rdir->stlen];
301 rdir->d = 1;
302 if (!(rdir->dir = opendir(rdir->name)))
303 warn("could not open directory: %s", rdir->name);
304 continue;
305 }
306
307 /* no more entries */
308 break;
309 }
310
311 return NULL;
312 }
313
314 int r_mkdir(const char *path) {
92709b2 @muennich Use directory structure in cache dir
authored
315 char *dir, *d;
316 struct stat stats;
317 int err = 0;
318
319 if (!path || !*path)
320 return -1;
321
322 if (!stat(path, &stats)) {
323 if (S_ISDIR(stats.st_mode)) {
324 return 0;
325 } else {
326 warn("not a directory: %s", path);
327 return -1;
328 }
329 }
330
331 d = dir = (char*) s_malloc(strlen(path) + 1);
332 strcpy(dir, path);
333
334 while (d != NULL && !err) {
335 d = strchr(d + 1, '/');
336 if (d != NULL)
337 *d = '\0';
338 if (access(dir, F_OK) && errno == ENOENT) {
339 if (mkdir(dir, 0755)) {
340 warn("could not create directory: %s", dir);
341 err = -1;
342 }
343 } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
344 warn("not a directory: %s", dir);
345 err = -1;
346 }
347 if (d != NULL)
348 *d = '/';
349 }
350 free(dir);
351
352 return err;
353 }
Something went wrong with that request. Please try again.