Krolyxon
Commit e999688

Branches

Refs →

nsxivutil.c

315 lines · 6.3 KB · C

1/* sxiv: util.c
2 * Copyright (c) 2011 Bert Muennich <muennich at informatik.hu-berlin.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <dirent.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <errno.h>
26
27#include "options.h"
28#include "util.h"
29
30#define DNAME_CNT 512
31#define FNAME_CNT 1024
32#define FNAME_LEN 1024
33
34void cleanup();
35
36void* s_malloc(size_t size) {
37 void *ptr;
38
39 if (!(ptr = malloc(size)))
40 die("could not allocate memory");
41 return ptr;
42}
43
44void* s_realloc(void *ptr, size_t size) {
45 if (!(ptr = realloc(ptr, size)))
46 die("could not allocate memory");
47 return ptr;
48}
49
50void warn(const char* fmt, ...) {
51 va_list args;
52
53 if (!fmt || options->quiet)
54 return;
55
56 va_start(args, fmt);
57 fprintf(stderr, "sxiv: warning: ");
58 vfprintf(stderr, fmt, args);
59 fprintf(stderr, "\n");
60 va_end(args);
61}
62
63void die(const char* fmt, ...) {
64 va_list args;
65
66 if (!fmt)
67 return;
68
69 va_start(args, fmt);
70 fprintf(stderr, "sxiv: error: ");
71 vfprintf(stderr, fmt, args);
72 fprintf(stderr, "\n");
73 va_end(args);
74
75 cleanup();
76 exit(1);
77}
78
79void size_readable(float *size, const char **unit) {
80 const char *units[] = { "", "K", "M", "G" };
81 int i;
82
83 for (i = 0; i < LEN(units) && *size > 1024; ++i)
84 *size /= 1024;
85 *unit = units[MIN(i, LEN(units) - 1)];
86}
87
88char* absolute_path(const char *filename) {
89 size_t len;
90 char *path = NULL;
91 const char *basename;
92 char *dirname = NULL;
93 char *cwd = NULL;
94 char *twd = NULL;
95 char *dir;
96 char *s;
97
98 if (!filename || *filename == '\0' || *filename == '/')
99 return NULL;
100
101 len = FNAME_LEN;
102 cwd = (char*) s_malloc(len);
103 while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
104 len *= 2;
105 cwd = (char*) s_realloc(cwd, len);
106 }
107 if (!s)
108 goto error;
109
110 s = strrchr(filename, '/');
111 if (s) {
112 len = s - filename;
113 dirname = (char*) s_malloc(len + 1);
114 strncpy(dirname, filename, len);
115 dirname[len] = '\0';
116 basename = s + 1;
117
118 if (chdir(cwd))
119 /* we're not able to come back afterwards */
120 goto error;
121 if (chdir(dirname))
122 goto error;
123
124 len = FNAME_LEN;
125 twd = (char*) s_malloc(len);
126 while (!(s = getcwd(twd, len)) && errno == ERANGE) {
127 len *= 2;
128 twd = (char*) s_realloc(twd, len);
129 }
130 if (chdir(cwd))
131 die("could not revert to prior working directory");
132 if (!s)
133 goto error;
134 dir = twd;
135 } else {
136 /* only a single filename given */
137 basename = filename;
138 dir = cwd;
139 }
140
141 len = strlen(dir) + strlen(basename) + 2;
142 path = (char*) s_malloc(len);
143 snprintf(path, len, "%s/%s", dir, basename);
144
145goto end;
146
147error:
148 if (path) {
149 free(path);
150 path = NULL;
151 }
152
153end:
154 if (dirname)
155 free(dirname);
156 if (cwd)
157 free(cwd);
158 if (twd)
159 free(twd);
160
161 return path;
162}
163
164int create_dir_rec(const char *path) {
165 char *dir, *d;
166 struct stat stats;
167 int err = 0;
168
169 if (!path || !*path)
170 return -1;
171
172 if (!stat(path, &stats)) {
173 if (S_ISDIR(stats.st_mode)) {
174 return 0;
175 } else {
176 warn("not a directory: %s", path);
177 return -1;
178 }
179 }
180
181 d = dir = (char*) s_malloc(strlen(path) + 1);
182 strcpy(dir, path);
183
184 while (d != NULL && !err) {
185 d = strchr(d + 1, '/');
186 if (d != NULL)
187 *d = '\0';
188 if (access(dir, F_OK) && errno == ENOENT) {
189 if (mkdir(dir, 0755)) {
190 warn("could not create directory: %s", dir);
191 err = -1;
192 }
193 } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
194 warn("not a directory: %s", dir);
195 err = -1;
196 }
197 if (d != NULL)
198 *d = '/';
199 }
200 free(dir);
201
202 return err;
203}
204
205int fncmp(const void *a, const void *b) {
206 return strcoll(*((char* const*) a), *((char* const*) b));
207}
208
209char** read_dir_rec(const char *dirname) {
210 int dcnt, didx, fcnt, fidx;
211 char **dnames, **fnames, *filename;
212 unsigned char first;
213 size_t len;
214 DIR *dir;
215 struct dirent *dentry;
216 struct stat fstats;
217
218 if (!dirname)
219 return NULL;
220
221 dcnt = DNAME_CNT;
222 didx = first = 1;
223 dnames = (char**) s_malloc(dcnt * sizeof(char*));
224 dnames[0] = (char*) dirname;
225
226 fcnt = FNAME_CNT;
227 fidx = 0;
228 fnames = (char**) s_malloc(fcnt * sizeof(char*));
229
230 while (didx > 0) {
231 dirname = dnames[--didx];
232 if (!(dir = opendir(dirname))) {
233 warn("could not open directory: %s", dirname);
234 } else {
235 while ((dentry = readdir(dir))) {
236 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
237 continue;
238
239 len = strlen(dirname) + strlen(dentry->d_name) + 2;
240 filename = (char*) s_malloc(len * sizeof(char));
241 snprintf(filename, len, "%s%s%s", dirname,
242 dirname[strlen(dirname)-1] == '/' ? "" : "/", dentry->d_name);
243
244 if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
245 if (didx == dcnt) {
246 dcnt *= 2;
247 dnames = (char**) s_realloc(dnames, dcnt * sizeof(char*));
248 }
249 dnames[didx++] = filename;
250 } else {
251 if (fidx + 1 == fcnt) {
252 fcnt *= 2;
253 fnames = (char**) s_realloc(fnames, fcnt * sizeof(char*));
254 }
255 fnames[fidx++] = filename;
256 }
257 }
258 closedir(dir);
259 }
260
261 if (!first)
262 free((void*) dirname);
263 else
264 first = 0;
265 }
266
267 if (!fidx) {
268 free(fnames);
269 fnames = NULL;
270 } else {
271 if (fidx > 1)
272 qsort(fnames, fidx, sizeof(char*), fncmp);
273 fnames[fidx] = NULL;
274 }
275
276 free(dnames);
277
278 return fnames;
279}
280
281char* readline(FILE *stream) {
282 size_t len;
283 char *buf, *s, *end;
284
285 if (!stream || feof(stream) || ferror(stream))
286 return NULL;
287
288 len = FNAME_LEN;
289 s = buf = (char*) s_malloc(len * sizeof(char));
290
291 do {
292 *s = '\0';
293 fgets(s, len - (s - buf), stream);
294 if ((end = strchr(s, '\n'))) {
295 *end = '\0';
296 } else if (strlen(s) + 1 == len - (s - buf)) {
297 buf = (char*) s_realloc(buf, 2 * len * sizeof(char));
298 s = buf + len - 1;
299 len *= 2;
300 } else {
301 s += strlen(s);
302 }
303 } while (!end && !feof(stream) && !ferror(stream));
304
305 if (ferror(stream)) {
306 s = NULL;
307 } else {
308 s = (char*) s_malloc((strlen(buf) + 1) * sizeof(char));
309 strcpy(s, buf);
310 }
311
312 free(buf);
313
314 return s;
315}