A Simple X Image Viewer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

316 lines
6.3 KiB

  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. #include <stdlib.h>
  19. #include <string.h>
  20. #include <dirent.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include "options.h"
  26. #include "util.h"
  27. #define DNAME_CNT 512
  28. #define FNAME_CNT 1024
  29. #define FNAME_LEN 1024
  30. void cleanup();
  31. void* s_malloc(size_t size) {
  32. void *ptr;
  33. if (!(ptr = malloc(size)))
  34. die("could not allocate memory");
  35. return ptr;
  36. }
  37. void* s_realloc(void *ptr, size_t size) {
  38. if (!(ptr = realloc(ptr, size)))
  39. die("could not allocate memory");
  40. return ptr;
  41. }
  42. void warn(const char* fmt, ...) {
  43. va_list args;
  44. if (!fmt || options->quiet)
  45. return;
  46. va_start(args, fmt);
  47. fprintf(stderr, "sxiv: warning: ");
  48. vfprintf(stderr, fmt, args);
  49. fprintf(stderr, "\n");
  50. va_end(args);
  51. }
  52. void die(const char* fmt, ...) {
  53. va_list args;
  54. if (!fmt)
  55. return;
  56. va_start(args, fmt);
  57. fprintf(stderr, "sxiv: error: ");
  58. vfprintf(stderr, fmt, args);
  59. fprintf(stderr, "\n");
  60. va_end(args);
  61. cleanup();
  62. exit(1);
  63. }
  64. void size_readable(float *size, const char **unit) {
  65. const char *units[] = { "", "K", "M", "G" };
  66. int i;
  67. for (i = 0; i < LEN(units) && *size > 1024; ++i)
  68. *size /= 1024;
  69. *unit = units[MIN(i, LEN(units) - 1)];
  70. }
  71. char* absolute_path(const char *filename) {
  72. size_t len;
  73. char *path = NULL;
  74. const char *basename;
  75. char *dirname = NULL;
  76. char *cwd = NULL;
  77. char *twd = NULL;
  78. char *dir;
  79. char *s;
  80. if (!filename || *filename == '\0' || *filename == '/')
  81. return NULL;
  82. len = FNAME_LEN;
  83. cwd = (char*) s_malloc(len);
  84. while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
  85. len *= 2;
  86. cwd = (char*) s_realloc(cwd, len);
  87. }
  88. if (!s)
  89. goto error;
  90. s = strrchr(filename, '/');
  91. if (s) {
  92. len = s - filename;
  93. dirname = (char*) s_malloc(len + 1);
  94. strncpy(dirname, filename, len);
  95. dirname[len] = '\0';
  96. basename = s + 1;
  97. if (chdir(cwd))
  98. /* we're not able to come back afterwards */
  99. goto error;
  100. if (chdir(dirname))
  101. goto error;
  102. len = FNAME_LEN;
  103. twd = (char*) s_malloc(len);
  104. while (!(s = getcwd(twd, len)) && errno == ERANGE) {
  105. len *= 2;
  106. twd = (char*) s_realloc(twd, len);
  107. }
  108. if (chdir(cwd))
  109. die("could not revert to prior working directory");
  110. if (!s)
  111. goto error;
  112. dir = twd;
  113. } else {
  114. /* only a single filename given */
  115. basename = filename;
  116. dir = cwd;
  117. }
  118. len = strlen(dir) + strlen(basename) + 2;
  119. path = (char*) s_malloc(len);
  120. snprintf(path, len, "%s/%s", dir, basename);
  121. goto end;
  122. error:
  123. if (path) {
  124. free(path);
  125. path = NULL;
  126. }
  127. end:
  128. if (dirname)
  129. free(dirname);
  130. if (cwd)
  131. free(cwd);
  132. if (twd)
  133. free(twd);
  134. return path;
  135. }
  136. int create_dir_rec(const char *path) {
  137. char *dir, *d;
  138. struct stat stats;
  139. int err = 0;
  140. if (!path || !*path)
  141. return -1;
  142. if (!stat(path, &stats)) {
  143. if (S_ISDIR(stats.st_mode)) {
  144. return 0;
  145. } else {
  146. warn("not a directory: %s", path);
  147. return -1;
  148. }
  149. }
  150. d = dir = (char*) s_malloc(strlen(path) + 1);
  151. strcpy(dir, path);
  152. while (d != NULL && !err) {
  153. d = strchr(d + 1, '/');
  154. if (d != NULL)
  155. *d = '\0';
  156. if (access(dir, F_OK) && errno == ENOENT) {
  157. if (mkdir(dir, 0755)) {
  158. warn("could not create directory: %s", dir);
  159. err = -1;
  160. }
  161. } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
  162. warn("not a directory: %s", dir);
  163. err = -1;
  164. }
  165. if (d != NULL)
  166. *d = '/';
  167. }
  168. free(dir);
  169. return err;
  170. }
  171. int fncmp(const void *a, const void *b) {
  172. return strcoll(*((char* const*) a), *((char* const*) b));
  173. }
  174. char** read_dir_rec(const char *dirname) {
  175. int dcnt, didx, fcnt, fidx;
  176. char **dnames, **fnames, *filename;
  177. unsigned char first;
  178. size_t len;
  179. DIR *dir;
  180. struct dirent *dentry;
  181. struct stat fstats;
  182. if (!dirname)
  183. return NULL;
  184. dcnt = DNAME_CNT;
  185. didx = first = 1;
  186. dnames = (char**) s_malloc(dcnt * sizeof(char*));
  187. dnames[0] = (char*) dirname;
  188. fcnt = FNAME_CNT;
  189. fidx = 0;
  190. fnames = (char**) s_malloc(fcnt * sizeof(char*));
  191. while (didx > 0) {
  192. dirname = dnames[--didx];
  193. if (!(dir = opendir(dirname))) {
  194. warn("could not open directory: %s", dirname);
  195. } else {
  196. while ((dentry = readdir(dir))) {
  197. if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
  198. continue;
  199. len = strlen(dirname) + strlen(dentry->d_name) + 2;
  200. filename = (char*) s_malloc(len * sizeof(char));
  201. snprintf(filename, len, "%s%s%s", dirname,
  202. dirname[strlen(dirname)-1] == '/' ? "" : "/", dentry->d_name);
  203. if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
  204. if (didx == dcnt) {
  205. dcnt *= 2;
  206. dnames = (char**) s_realloc(dnames, dcnt * sizeof(char*));
  207. }
  208. dnames[didx++] = filename;
  209. } else {
  210. if (fidx + 1 == fcnt) {
  211. fcnt *= 2;
  212. fnames = (char**) s_realloc(fnames, fcnt * sizeof(char*));
  213. }
  214. fnames[fidx++] = filename;
  215. }
  216. }
  217. closedir(dir);
  218. }
  219. if (!first)
  220. free((void*) dirname);
  221. else
  222. first = 0;
  223. }
  224. if (!fidx) {
  225. free(fnames);
  226. fnames = NULL;
  227. } else {
  228. if (fidx > 1)
  229. qsort(fnames, fidx, sizeof(char*), fncmp);
  230. fnames[fidx] = NULL;
  231. }
  232. free(dnames);
  233. return fnames;
  234. }
  235. char* readline(FILE *stream) {
  236. size_t len;
  237. char *buf, *s, *end;
  238. if (!stream || feof(stream) || ferror(stream))
  239. return NULL;
  240. len = FNAME_LEN;
  241. s = buf = (char*) s_malloc(len * sizeof(char));
  242. do {
  243. *s = '\0';
  244. fgets(s, len - (s - buf), stream);
  245. if ((end = strchr(s, '\n'))) {
  246. *end = '\0';
  247. } else if (strlen(s) + 1 == len - (s - buf)) {
  248. buf = (char*) s_realloc(buf, 2 * len * sizeof(char));
  249. s = buf + len - 1;
  250. len *= 2;
  251. } else {
  252. s += strlen(s);
  253. }
  254. } while (!end && !feof(stream) && !ferror(stream));
  255. if (ferror(stream)) {
  256. s = NULL;
  257. } else {
  258. s = (char*) s_malloc((strlen(buf) + 1) * sizeof(char));
  259. strcpy(s, buf);
  260. }
  261. free(buf);
  262. return s;
  263. }