Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 347 lines (289 sloc) 7.2 kb
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
1 /* sxiv: util.c
d407dd6 @muennich Already in the year 2012
authored
2 * Copyright (c) 2012 Bert Muennich <be.muennich at googlemail.com>
8f4af65 @muennich Refactored, new files util.[ch], C89
authored
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
c21a3e3 @muennich Write thumbnail cache files on exit
authored
137 char* absolute_path(const char *filename) {
138 size_t len;
139 const char *basename;
6e575b0 @muennich Strict conformance to IEEE Std 1003.1-2001
authored
140 char *dir, *dirname = NULL, *path = NULL, *s;
141 char *cwd = NULL, *twd = NULL;
c21a3e3 @muennich Write thumbnail cache files on exit
authored
142
8dcf682 @muennich Made all conditionals more precise
authored
143 if (filename == NULL || *filename == '\0' || *filename == '/')
c21a3e3 @muennich Write thumbnail cache files on exit
authored
144 return NULL;
145
146 len = FNAME_LEN;
147 cwd = (char*) s_malloc(len);
8dcf682 @muennich Made all conditionals more precise
authored
148 while ((s = getcwd(cwd, len)) == NULL && errno == ERANGE) {
c21a3e3 @muennich Write thumbnail cache files on exit
authored
149 len *= 2;
150 cwd = (char*) s_realloc(cwd, len);
151 }
8dcf682 @muennich Made all conditionals more precise
authored
152 if (s == NULL)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
153 goto error;
154
155 s = strrchr(filename, '/');
8dcf682 @muennich Made all conditionals more precise
authored
156 if (s != NULL) {
c21a3e3 @muennich Write thumbnail cache files on exit
authored
157 len = s - filename;
158 dirname = (char*) s_malloc(len + 1);
159 strncpy(dirname, filename, len);
160 dirname[len] = '\0';
161 basename = s + 1;
162
8dcf682 @muennich Made all conditionals more precise
authored
163 if (chdir(cwd) < 0)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
164 /* we're not able to come back afterwards */
165 goto error;
8dcf682 @muennich Made all conditionals more precise
authored
166 if (chdir(dirname) < 0)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
167 goto error;
168
169 len = FNAME_LEN;
170 twd = (char*) s_malloc(len);
8dcf682 @muennich Made all conditionals more precise
authored
171 while ((s = getcwd(twd, len)) == NULL && errno == ERANGE) {
c21a3e3 @muennich Write thumbnail cache files on exit
authored
172 len *= 2;
173 twd = (char*) s_realloc(twd, len);
174 }
8dcf682 @muennich Made all conditionals more precise
authored
175 if (chdir(cwd) < 0)
f93f4d8 @muennich Write cache file for thumbnail directly after creating it
authored
176 die("could not revert to prior working directory");
8dcf682 @muennich Made all conditionals more precise
authored
177 if (s == NULL)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
178 goto error;
179 dir = twd;
180 } else {
181 /* only a single filename given */
182 basename = filename;
183 dir = cwd;
184 }
185
186 len = strlen(dir) + strlen(basename) + 2;
187 path = (char*) s_malloc(len);
188 snprintf(path, len, "%s/%s", dir, basename);
189
ea23115 @muennich Use getline instead of readline
authored
190 goto end;
c21a3e3 @muennich Write thumbnail cache files on exit
authored
191
192 error:
8dcf682 @muennich Made all conditionals more precise
authored
193 if (path != NULL) {
c21a3e3 @muennich Write thumbnail cache files on exit
authored
194 free(path);
195 path = NULL;
196 }
197
198 end:
8dcf682 @muennich Made all conditionals more precise
authored
199 if (dirname != NULL)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
200 free(dirname);
8dcf682 @muennich Made all conditionals more precise
authored
201 if (cwd != NULL)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
202 free(cwd);
8dcf682 @muennich Made all conditionals more precise
authored
203 if (twd != NULL)
c21a3e3 @muennich Write thumbnail cache files on exit
authored
204 free(twd);
205
206 return path;
207 }
208
a90bd1c @muennich Refactored recursive directory util functions
authored
209 int r_opendir(r_dir_t *rdir, const char *dirname) {
8dcf682 @muennich Made all conditionals more precise
authored
210 if (rdir == NULL || dirname == NULL || *dirname == '\0')
a90bd1c @muennich Refactored recursive directory util functions
authored
211 return -1;
212
8dcf682 @muennich Made all conditionals more precise
authored
213 if ((rdir->dir = opendir(dirname)) == NULL) {
a90bd1c @muennich Refactored recursive directory util functions
authored
214 rdir->name = NULL;
215 rdir->stack = NULL;
216 return -1;
217 }
218
219 rdir->stcap = DNAME_CNT;
220 rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
221 rdir->stlen = 0;
222
223 rdir->name = (char*) dirname;
224 rdir->d = 0;
225
226 return 0;
227 }
228
229 int r_closedir(r_dir_t *rdir) {
230 int ret = 0;
231
8dcf682 @muennich Made all conditionals more precise
authored
232 if (rdir == NULL)
a90bd1c @muennich Refactored recursive directory util functions
authored
233 return -1;
234
8dcf682 @muennich Made all conditionals more precise
authored
235 if (rdir->stack != NULL) {
a90bd1c @muennich Refactored recursive directory util functions
authored
236 while (rdir->stlen > 0)
237 free(rdir->stack[--rdir->stlen]);
238 free(rdir->stack);
239 rdir->stack = NULL;
240 }
241
8dcf682 @muennich Made all conditionals more precise
authored
242 if (rdir->dir != NULL) {
243 if ((ret = closedir(rdir->dir)) == 0)
a90bd1c @muennich Refactored recursive directory util functions
authored
244 rdir->dir = NULL;
245 }
246
8dcf682 @muennich Made all conditionals more precise
authored
247 if (rdir->d != 0 && rdir->name != NULL) {
a90bd1c @muennich Refactored recursive directory util functions
authored
248 free(rdir->name);
249 rdir->name = NULL;
250 }
251
252 return ret;
253 }
254
255 char* r_readdir(r_dir_t *rdir) {
256 size_t len;
257 char *filename;
258 struct dirent *dentry;
259 struct stat fstats;
260
8dcf682 @muennich Made all conditionals more precise
authored
261 if (rdir == NULL || rdir->dir == NULL || rdir->name == NULL)
a90bd1c @muennich Refactored recursive directory util functions
authored
262 return NULL;
263
8dcf682 @muennich Made all conditionals more precise
authored
264 while (true) {
265 if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
4383a65 @muennich Strictly adhere to ANSI-C standard
authored
266 if (STREQ(dentry->d_name, ".") || STREQ(dentry->d_name, ".."))
a90bd1c @muennich Refactored recursive directory util functions
authored
267 continue;
268
269 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
270 filename = (char*) s_malloc(len);
271 snprintf(filename, len, "%s%s%s", rdir->name,
272 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
273 dentry->d_name);
274
8dcf682 @muennich Made all conditionals more precise
authored
275 if (stat(filename, &fstats) < 0)
276 continue;
277 if (S_ISDIR(fstats.st_mode)) {
a90bd1c @muennich Refactored recursive directory util functions
authored
278 /* put subdirectory on the stack */
279 if (rdir->stlen == rdir->stcap) {
280 rdir->stcap *= 2;
281 rdir->stack = (char**) s_realloc(rdir->stack,
282 rdir->stcap * sizeof(char*));
283 }
284 rdir->stack[rdir->stlen++] = filename;
285 continue;
286 }
287 return filename;
288 }
289
290 if (rdir->stlen > 0) {
291 /* open next subdirectory */
292 closedir(rdir->dir);
8dcf682 @muennich Made all conditionals more precise
authored
293 if (rdir->d != 0)
a90bd1c @muennich Refactored recursive directory util functions
authored
294 free(rdir->name);
295 rdir->name = rdir->stack[--rdir->stlen];
296 rdir->d = 1;
8dcf682 @muennich Made all conditionals more precise
authored
297 if ((rdir->dir = opendir(rdir->name)) == NULL)
a90bd1c @muennich Refactored recursive directory util functions
authored
298 warn("could not open directory: %s", rdir->name);
299 continue;
300 }
301 /* no more entries */
302 break;
303 }
304 return NULL;
305 }
306
307 int r_mkdir(const char *path) {
92709b2 @muennich Use directory structure in cache dir
authored
308 char *dir, *d;
309 struct stat stats;
310 int err = 0;
311
8dcf682 @muennich Made all conditionals more precise
authored
312 if (path == NULL || *path == '\0')
92709b2 @muennich Use directory structure in cache dir
authored
313 return -1;
314
8dcf682 @muennich Made all conditionals more precise
authored
315 if (stat(path, &stats) == 0) {
92709b2 @muennich Use directory structure in cache dir
authored
316 if (S_ISDIR(stats.st_mode)) {
317 return 0;
318 } else {
319 warn("not a directory: %s", path);
320 return -1;
321 }
322 }
323
324 d = dir = (char*) s_malloc(strlen(path) + 1);
325 strcpy(dir, path);
326
8dcf682 @muennich Made all conditionals more precise
authored
327 while (d != NULL && err == 0) {
92709b2 @muennich Use directory structure in cache dir
authored
328 d = strchr(d + 1, '/');
329 if (d != NULL)
330 *d = '\0';
8dcf682 @muennich Made all conditionals more precise
authored
331 if (access(dir, F_OK) < 0 && errno == ENOENT) {
332 if (mkdir(dir, 0755) < 0) {
92709b2 @muennich Use directory structure in cache dir
authored
333 warn("could not create directory: %s", dir);
334 err = -1;
335 }
8dcf682 @muennich Made all conditionals more precise
authored
336 } else if (stat(dir, &stats) < 0 || !S_ISDIR(stats.st_mode)) {
92709b2 @muennich Use directory structure in cache dir
authored
337 warn("not a directory: %s", dir);
338 err = -1;
339 }
340 if (d != NULL)
341 *d = '/';
342 }
343 free(dir);
344
345 return err;
346 }
Something went wrong with that request. Please try again.