Krolyxon
Commit e0e9697

Branches

Refs →

nsxivutil.c

337 lines · 6.4 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(const 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 (*buf == NULL || *n == 0) {
107 *n = BUF_SIZE;
108 *buf = (char*) s_malloc(*n);
109 }
110 s = *buf;
111
112 while (true) {
113 if (fgets(s, *n - (s - *buf), stream) == NULL)
114 return -1;
115 len = strlen(s);
116 if (feof(stream))
117 break;
118 if (len > 0 && s[len-1] == '\n')
119 break;
120 if (len + 1 == *n - (s - *buf)) {
121 *buf = (char*) s_realloc(*buf, 2 * *n);
122 s = *buf + *n - 1;
123 *n *= 2;
124 } else {
125 s += len;
126 }
127 }
128 return s - *buf + len;
129}
130
131void size_readable(float *size, const char **unit)
132{
133 const char *units[] = { "", "K", "M", "G" };
134 int i;
135
136 for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++)
137 *size /= 1024.0;
138 *unit = units[MIN(i, ARRLEN(units) - 1)];
139}
140
141char* absolute_path(const char *filename)
142{
143 size_t len;
144 const char *basename;
145 char *dir, *dirname = NULL, *path = NULL, *s;
146 char *cwd = NULL, *twd = NULL;
147
148 if (*filename == '\0' || *filename == '/')
149 return NULL;
150
151 len = FNAME_LEN;
152 cwd = (char*) s_malloc(len);
153 while ((s = getcwd(cwd, len)) == NULL && errno == ERANGE) {
154 len *= 2;
155 cwd = (char*) s_realloc(cwd, len);
156 }
157 if (s == NULL)
158 goto error;
159
160 s = strrchr(filename, '/');
161 if (s != NULL) {
162 len = s - filename;
163 dirname = (char*) s_malloc(len + 1);
164 strncpy(dirname, filename, len);
165 dirname[len] = '\0';
166 basename = s + 1;
167
168 if (chdir(cwd) < 0)
169 /* we're not able to come back afterwards */
170 goto error;
171 if (chdir(dirname) < 0)
172 goto error;
173
174 len = FNAME_LEN;
175 twd = (char*) s_malloc(len);
176 while ((s = getcwd(twd, len)) == NULL && errno == ERANGE) {
177 len *= 2;
178 twd = (char*) s_realloc(twd, len);
179 }
180 if (chdir(cwd) < 0)
181 die("could not revert to prior working directory");
182 if (s == NULL)
183 goto error;
184 dir = twd;
185 } else {
186 /* only a single filename given */
187 basename = filename;
188 dir = cwd;
189 }
190
191 len = strlen(dir) + strlen(basename) + 2;
192 path = (char*) s_malloc(len);
193 snprintf(path, len, "%s/%s", dir, basename);
194
195 goto end;
196
197error:
198 free(path);
199 path = NULL;
200
201end:
202 free(dirname);
203 free(cwd);
204 free(twd);
205
206 return path;
207}
208
209int r_opendir(r_dir_t *rdir, const char *dirname)
210{
211 if (*dirname == '\0')
212 return -1;
213
214 if ((rdir->dir = opendir(dirname)) == NULL) {
215 rdir->name = NULL;
216 rdir->stack = NULL;
217 return -1;
218 }
219
220 rdir->stcap = DNAME_CNT;
221 rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
222 rdir->stlen = 0;
223
224 rdir->name = (char*) dirname;
225 rdir->d = 0;
226
227 return 0;
228}
229
230int r_closedir(r_dir_t *rdir)
231{
232 int ret = 0;
233
234 if (rdir->stack != NULL) {
235 while (rdir->stlen > 0)
236 free(rdir->stack[--rdir->stlen]);
237 free(rdir->stack);
238 rdir->stack = NULL;
239 }
240
241 if (rdir->dir != NULL) {
242 if ((ret = closedir(rdir->dir)) == 0)
243 rdir->dir = NULL;
244 }
245
246 if (rdir->d != 0) {
247 free(rdir->name);
248 rdir->name = NULL;
249 }
250
251 return ret;
252}
253
254char* r_readdir(r_dir_t *rdir)
255{
256 size_t len;
257 char *filename;
258 struct dirent *dentry;
259 struct stat fstats;
260
261 while (true) {
262 if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
263 if (dentry->d_name[0] == '.')
264 continue;
265
266 len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
267 filename = (char*) s_malloc(len);
268 snprintf(filename, len, "%s%s%s", rdir->name,
269 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
270 dentry->d_name);
271
272 if (stat(filename, &fstats) < 0)
273 continue;
274 if (S_ISDIR(fstats.st_mode)) {
275 /* put subdirectory on the stack */
276 if (rdir->stlen == rdir->stcap) {
277 rdir->stcap *= 2;
278 rdir->stack = (char**) s_realloc(rdir->stack,
279 rdir->stcap * sizeof(char*));
280 }
281 rdir->stack[rdir->stlen++] = filename;
282 continue;
283 }
284 return filename;
285 }
286
287 if (rdir->stlen > 0) {
288 /* open next subdirectory */
289 closedir(rdir->dir);
290 if (rdir->d != 0)
291 free(rdir->name);
292 rdir->name = rdir->stack[--rdir->stlen];
293 rdir->d = 1;
294 if ((rdir->dir = opendir(rdir->name)) == NULL)
295 warn("could not open directory: %s", rdir->name);
296 continue;
297 }
298 /* no more entries */
299 break;
300 }
301 return NULL;
302}
303
304int r_mkdir(const char *path)
305{
306 char *dir, *d;
307 struct stat stats;
308 int err = 0;
309
310 if (*path == '\0')
311 return -1;
312
313 if (stat(path, &stats) == 0)
314 return S_ISDIR(stats.st_mode) ? 0 : -1;
315
316 d = dir = (char*) s_malloc(strlen(path) + 1);
317 strcpy(dir, path);
318
319 while (d != NULL && err == 0) {
320 d = strchr(d + 1, '/');
321 if (d != NULL)
322 *d = '\0';
323 if (access(dir, F_OK) < 0 && errno == ENOENT) {
324 if (mkdir(dir, 0755) < 0) {
325 warn("could not create directory: %s", dir);
326 err = -1;
327 }
328 } else if (stat(dir, &stats) < 0 || !S_ISDIR(stats.st_mode)) {
329 err = -1;
330 }
331 if (d != NULL)
332 *d = '/';
333 }
334 free(dir);
335
336 return err;
337}