Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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