Krolyxon
Commit 98972e9

Branches

Refs →

nsxivutil.c

358 lines · 6.9 KB · C

1/* Copyright 2011 Bert Muennich
2 *
3 * This file is part of sxiv.
4 *
5 * sxiv is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2 of the License,
8 * or (at your option) any later version.
9 *
10 * sxiv is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with sxiv. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#define _POSIX_C_SOURCE 200112L
20
21#include <stdlib.h>
22#include <string.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include <errno.h>
27
28#include "options.h"
29#include "util.h"
30
31enum {
32 BUF_SIZE = 1024,
33 DNAME_CNT = 512,
34 FNAME_LEN = 1024
35};
36
37void cleanup(void);
38
39void* s_malloc(size_t size)
40{
41 void *ptr;
42
43 ptr = malloc(size);
44 if (ptr == NULL)
45 die("could not allocate memory");
46 return ptr;
47}
48
49void* s_realloc(void *ptr, size_t size)
50{
51 ptr = realloc(ptr, size);
52 if (ptr == NULL)
53 die("could not allocate memory");
54 return ptr;
55}
56
57char* s_strdup(char *s)
58{
59 char *d = NULL;
60
61 if (s != NULL) {
62 d = malloc(strlen(s) + 1);
63 if (d == NULL)
64 die("could not allocate memory");
65 strcpy(d, s);
66 }
67 return d;
68}
69
70void warn(const char* fmt, ...)
71{
72 va_list args;
73
74 if (fmt == NULL || options->quiet)
75 return;
76
77 va_start(args, fmt);
78 fprintf(stderr, "sxiv: warning: ");
79 vfprintf(stderr, fmt, args);
80 fprintf(stderr, "\n");
81 va_end(args);
82}
83
84void die(const char* fmt, ...)
85{
86 va_list args;
87
88 if (fmt == NULL)
89 return;
90
91 va_start(args, fmt);
92 fprintf(stderr, "sxiv: error: ");
93 vfprintf(stderr, fmt, args);
94 fprintf(stderr, "\n");
95 va_end(args);
96
97 cleanup();
98 exit(EXIT_FAILURE);
99}
100
101ssize_t get_line(char **buf, size_t *n, FILE *stream)
102{
103 size_t len;
104 char *s;
105
106 if (stream == NULL || feof(stream) || ferror(stream))
107 return -1;
108
109 if (*buf == NULL || *n == 0) {
110 *n = BUF_SIZE;
111 *buf = (char*) s_malloc(*n);
112 }
113 s = *buf;
114
115 while (true) {
116 if (fgets(s, *n - (s - *buf), stream) == NULL)
117 return -1;
118 len = strlen(s);
119 if (feof(stream))
120 break;
121 if (len > 0 && s[len-1] == '\n')
122 break;
123 if (len + 1 == *n - (s - *buf)) {
124 *buf = (char*) s_realloc(*buf, 2 * *n);
125 s = *buf + *n - 1;
126 *n *= 2;
127 } else {
128 s += len;
129 }
130 }
131 return s - *buf + len;
132}
133
134void size_readable(float *size, const char **unit)
135{
136 const char *units[] = { "", "K", "M", "G" };
137 int i;
138
139 for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++)
140 *size /= 1024.0;
141 *unit = units[MIN(i, ARRLEN(units) - 1)];
142}
143
144char* absolute_path(const char *filename)
145{
146 size_t len;
147 const char *basename;
148 char *dir, *dirname = NULL, *path = NULL, *s;
149 char *cwd = NULL, *twd = NULL;
150
151 if (filename == NULL || *filename == '\0' || *filename == '/')
152 return NULL;
153
154 len = FNAME_LEN;
155 cwd = (char*) s_malloc(len);
156 while ((s = getcwd(cwd, len)) == NULL && errno == ERANGE) {
157 len *= 2;
158 cwd = (char*) s_realloc(cwd, len);
159 }
160 if (s == NULL)
161 goto error;
162
163 s = strrchr(filename, '/');
164 if (s != NULL) {
165 len = s - filename;
166 dirname = (char*) s_malloc(len + 1);
167 strncpy(dirname, filename, len);
168 dirname[len] = '\0';
169 basename = s + 1;
170
171 if (chdir(cwd) < 0)
172 /* we're not able to come back afterwards */
173 goto error;
174 if (chdir(dirname) < 0)
175 goto error;
176
177 len = FNAME_LEN;
178 twd = (char*) s_malloc(len);
179 while ((s = getcwd(twd, len)) == NULL && errno == ERANGE) {
180 len *= 2;
181 twd = (char*) s_realloc(twd, len);
182 }
183 if (chdir(cwd) < 0)
184 die("could not revert to prior working directory");
185 if (s == NULL)
186 goto error;
187 dir = twd;
188 } else {
189 /* only a single filename given */
190 basename = filename;
191 dir = cwd;
192 }
193
194 len = strlen(dir) + strlen(basename) + 2;
195 path = (char*) s_malloc(len);
196 snprintf(path, len, "%s/%s", dir, basename);
197
198 goto end;
199
200error:
201 if (path != NULL) {
202 free(path);
203 path = NULL;
204 }
205
206end:
207 if (dirname != NULL)
208 free(dirname);
209 if (cwd != NULL)
210 free(cwd);
211 if (twd != NULL)
212 free(twd);
213
214 return path;
215}
216
217int r_opendir(r_dir_t *rdir, const char *dirname)
218{
219 if (rdir == NULL || dirname == NULL || *dirname == '\0')
220 return -1;
221
222 if ((rdir->dir = opendir(dirname)) == NULL) {
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
238int r_closedir(r_dir_t *rdir)
239{
240 int ret = 0;
241
242 if (rdir == NULL)
243 return -1;
244
245 if (rdir->stack != NULL) {
246 while (rdir->stlen > 0)
247 free(rdir->stack[--rdir->stlen]);
248 free(rdir->stack);
249 rdir->stack = NULL;
250 }
251
252 if (rdir->dir != NULL) {
253 if ((ret = closedir(rdir->dir)) == 0)
254 rdir->dir = NULL;
255 }
256
257 if (rdir->d != 0 && rdir->name != NULL) {
258 free(rdir->name);
259 rdir->name = NULL;
260 }
261
262 return ret;
263}
264
265char* r_readdir(r_dir_t *rdir)
266{
267 size_t len;
268 char *filename;
269 struct dirent *dentry;
270 struct stat fstats;
271
272 if (rdir == NULL || rdir->dir == NULL || rdir->name == NULL)
273 return NULL;
274
275 while (true) {
276 if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
277 if (dentry->d_name[0] == '.')
278 continue;
279
280 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
281 filename = (char*) s_malloc(len);
282 snprintf(filename, len, "%s%s%s", rdir->name,
283 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
284 dentry->d_name);
285
286 if (stat(filename, &fstats) < 0)
287 continue;
288 if (S_ISDIR(fstats.st_mode)) {
289 /* put subdirectory on the stack */
290 if (rdir->stlen == rdir->stcap) {
291 rdir->stcap *= 2;
292 rdir->stack = (char**) s_realloc(rdir->stack,
293 rdir->stcap * sizeof(char*));
294 }
295 rdir->stack[rdir->stlen++] = filename;
296 continue;
297 }
298 return filename;
299 }
300
301 if (rdir->stlen > 0) {
302 /* open next subdirectory */
303 closedir(rdir->dir);
304 if (rdir->d != 0)
305 free(rdir->name);
306 rdir->name = rdir->stack[--rdir->stlen];
307 rdir->d = 1;
308 if ((rdir->dir = opendir(rdir->name)) == NULL)
309 warn("could not open directory: %s", rdir->name);
310 continue;
311 }
312 /* no more entries */
313 break;
314 }
315 return NULL;
316}
317
318int r_mkdir(const char *path)
319{
320 char *dir, *d;
321 struct stat stats;
322 int err = 0;
323
324 if (path == NULL || *path == '\0')
325 return -1;
326
327 if (stat(path, &stats) == 0) {
328 if (S_ISDIR(stats.st_mode)) {
329 return 0;
330 } else {
331 warn("not a directory: %s", path);
332 return -1;
333 }
334 }
335
336 d = dir = (char*) s_malloc(strlen(path) + 1);
337 strcpy(dir, path);
338
339 while (d != NULL && err == 0) {
340 d = strchr(d + 1, '/');
341 if (d != NULL)
342 *d = '\0';
343 if (access(dir, F_OK) < 0 && errno == ENOENT) {
344 if (mkdir(dir, 0755) < 0) {
345 warn("could not create directory: %s", dir);
346 err = -1;
347 }
348 } else if (stat(dir, &stats) < 0 || !S_ISDIR(stats.st_mode)) {
349 warn("not a directory: %s", dir);
350 err = -1;
351 }
352 if (d != NULL)
353 *d = '/';
354 }
355 free(dir);
356
357 return err;
358}