util.c (4431B)
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 #include "sxiv.h" 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 const char *progname; 29 30 void* emalloc(size_t size) 31 { 32 void *ptr; 33 34 ptr = malloc(size); 35 if (ptr == NULL) 36 error(EXIT_FAILURE, errno, NULL); 37 return ptr; 38 } 39 40 void* erealloc(void *ptr, size_t size) 41 { 42 ptr = realloc(ptr, size); 43 if (ptr == NULL) 44 error(EXIT_FAILURE, errno, NULL); 45 return ptr; 46 } 47 48 char* estrdup(const char *s) 49 { 50 char *d; 51 size_t n = strlen(s) + 1; 52 53 d = malloc(n); 54 if (d == NULL) 55 error(EXIT_FAILURE, errno, NULL); 56 memcpy(d, s, n); 57 return d; 58 } 59 60 void error(int eval, int err, const char* fmt, ...) 61 { 62 va_list ap; 63 64 if (eval == 0 && options->quiet) 65 return; 66 67 fflush(stdout); 68 fprintf(stderr, "%s: ", progname); 69 va_start(ap, fmt); 70 if (fmt != NULL) 71 vfprintf(stderr, fmt, ap); 72 va_end(ap); 73 if (err != 0) 74 fprintf(stderr, "%s%s", fmt != NULL ? ": " : "", strerror(err)); 75 fputc('\n', stderr); 76 77 if (eval != 0) 78 exit(eval); 79 } 80 81 void size_readable(float *size, const char **unit) 82 { 83 const char *units[] = { "", "K", "M", "G" }; 84 int i; 85 86 for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++) 87 *size /= 1024.0; 88 *unit = units[MIN(i, ARRLEN(units) - 1)]; 89 } 90 91 int r_opendir(r_dir_t *rdir, const char *dirname, bool recursive) 92 { 93 if (*dirname == '\0') 94 return -1; 95 96 if ((rdir->dir = opendir(dirname)) == NULL) { 97 rdir->name = NULL; 98 rdir->stack = NULL; 99 return -1; 100 } 101 102 rdir->stcap = 512; 103 rdir->stack = (char**) emalloc(rdir->stcap * sizeof(char*)); 104 rdir->stlen = 0; 105 106 rdir->name = (char*) dirname; 107 rdir->d = 0; 108 rdir->recursive = recursive; 109 110 return 0; 111 } 112 113 int r_closedir(r_dir_t *rdir) 114 { 115 int ret = 0; 116 117 if (rdir->stack != NULL) { 118 while (rdir->stlen > 0) 119 free(rdir->stack[--rdir->stlen]); 120 free(rdir->stack); 121 rdir->stack = NULL; 122 } 123 124 if (rdir->dir != NULL) { 125 if ((ret = closedir(rdir->dir)) == 0) 126 rdir->dir = NULL; 127 } 128 129 if (rdir->d != 0) { 130 free(rdir->name); 131 rdir->name = NULL; 132 } 133 134 return ret; 135 } 136 137 char* r_readdir(r_dir_t *rdir, bool skip_dotfiles) 138 { 139 size_t len; 140 char *filename; 141 struct dirent *dentry; 142 struct stat fstats; 143 144 while (true) { 145 if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) { 146 if (dentry->d_name[0] == '.') { 147 if (skip_dotfiles) 148 continue; 149 if (dentry->d_name[1] == '\0') 150 continue; 151 if (dentry->d_name[1] == '.' && dentry->d_name[2] == '\0') 152 continue; 153 } 154 155 len = strlen(rdir->name) + strlen(dentry->d_name) + 2; 156 filename = (char*) emalloc(len); 157 snprintf(filename, len, "%s%s%s", rdir->name, 158 rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/", 159 dentry->d_name); 160 161 if (stat(filename, &fstats) < 0) 162 continue; 163 if (S_ISDIR(fstats.st_mode)) { 164 /* put subdirectory on the stack */ 165 if (rdir->stlen == rdir->stcap) { 166 rdir->stcap *= 2; 167 rdir->stack = (char**) erealloc(rdir->stack, 168 rdir->stcap * sizeof(char*)); 169 } 170 rdir->stack[rdir->stlen++] = filename; 171 continue; 172 } 173 return filename; 174 } 175 176 if (rdir->recursive && rdir->stlen > 0) { 177 /* open next subdirectory */ 178 closedir(rdir->dir); 179 if (rdir->d != 0) 180 free(rdir->name); 181 rdir->name = rdir->stack[--rdir->stlen]; 182 rdir->d = 1; 183 if ((rdir->dir = opendir(rdir->name)) == NULL) 184 error(0, errno, "%s", rdir->name); 185 continue; 186 } 187 /* no more entries */ 188 break; 189 } 190 return NULL; 191 } 192 193 int r_mkdir(char *path) 194 { 195 char c, *s = path; 196 struct stat st; 197 198 while (*s != '\0') { 199 if (*s == '/') { 200 s++; 201 continue; 202 } 203 for (; *s != '\0' && *s != '/'; s++); 204 c = *s; 205 *s = '\0'; 206 if (mkdir(path, 0755) == -1) 207 if (errno != EEXIST || stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) 208 return -1; 209 *s = c; 210 } 211 return 0; 212 } 213