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.
 
 
 
 
 
 

313 lines
6.1 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
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <unistd.h>
  23. #include <errno.h>
  24. #include "options.h"
  25. #include "util.h"
  26. enum {
  27. DNAME_CNT = 512,
  28. FNAME_LEN = 1024
  29. };
  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. char* s_strdup(char *s) {
  43. char *d = NULL;
  44. if (s) {
  45. if (!(d = malloc(strlen(s) + 1)))
  46. die("could not allocate memory");
  47. strcpy(d, s);
  48. }
  49. return d;
  50. }
  51. void warn(const char* fmt, ...) {
  52. va_list args;
  53. if (!fmt || options->quiet)
  54. return;
  55. va_start(args, fmt);
  56. fprintf(stderr, "sxiv: warning: ");
  57. vfprintf(stderr, fmt, args);
  58. fprintf(stderr, "\n");
  59. va_end(args);
  60. }
  61. void die(const char* fmt, ...) {
  62. va_list args;
  63. if (!fmt)
  64. return;
  65. va_start(args, fmt);
  66. fprintf(stderr, "sxiv: error: ");
  67. vfprintf(stderr, fmt, args);
  68. fprintf(stderr, "\n");
  69. va_end(args);
  70. cleanup();
  71. exit(1);
  72. }
  73. void size_readable(float *size, const char **unit) {
  74. const char *units[] = { "", "K", "M", "G" };
  75. int i;
  76. for (i = 0; i < LEN(units) && *size > 1024; i++)
  77. *size /= 1024;
  78. *unit = units[MIN(i, LEN(units) - 1)];
  79. }
  80. char* absolute_path(const char *filename) {
  81. size_t len;
  82. char *path = NULL;
  83. const char *basename;
  84. char *dirname = NULL;
  85. char *cwd = NULL;
  86. char *twd = NULL;
  87. char *dir;
  88. char *s;
  89. if (!filename || *filename == '\0' || *filename == '/')
  90. return NULL;
  91. len = FNAME_LEN;
  92. cwd = (char*) s_malloc(len);
  93. while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
  94. len *= 2;
  95. cwd = (char*) s_realloc(cwd, len);
  96. }
  97. if (!s)
  98. goto error;
  99. s = strrchr(filename, '/');
  100. if (s) {
  101. len = s - filename;
  102. dirname = (char*) s_malloc(len + 1);
  103. strncpy(dirname, filename, len);
  104. dirname[len] = '\0';
  105. basename = s + 1;
  106. if (chdir(cwd))
  107. /* we're not able to come back afterwards */
  108. goto error;
  109. if (chdir(dirname))
  110. goto error;
  111. len = FNAME_LEN;
  112. twd = (char*) s_malloc(len);
  113. while (!(s = getcwd(twd, len)) && errno == ERANGE) {
  114. len *= 2;
  115. twd = (char*) s_realloc(twd, len);
  116. }
  117. if (chdir(cwd))
  118. die("could not revert to prior working directory");
  119. if (!s)
  120. goto error;
  121. dir = twd;
  122. } else {
  123. /* only a single filename given */
  124. basename = filename;
  125. dir = cwd;
  126. }
  127. len = strlen(dir) + strlen(basename) + 2;
  128. path = (char*) s_malloc(len);
  129. snprintf(path, len, "%s/%s", dir, basename);
  130. goto end;
  131. error:
  132. if (path) {
  133. free(path);
  134. path = NULL;
  135. }
  136. end:
  137. if (dirname)
  138. free(dirname);
  139. if (cwd)
  140. free(cwd);
  141. if (twd)
  142. free(twd);
  143. return path;
  144. }
  145. int r_opendir(r_dir_t *rdir, const char *dirname) {
  146. if (!rdir || !dirname || !*dirname)
  147. return -1;
  148. if (!(rdir->dir = opendir(dirname))) {
  149. rdir->name = NULL;
  150. rdir->stack = NULL;
  151. return -1;
  152. }
  153. rdir->stcap = DNAME_CNT;
  154. rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
  155. rdir->stlen = 0;
  156. rdir->name = (char*) dirname;
  157. rdir->d = 0;
  158. return 0;
  159. }
  160. int r_closedir(r_dir_t *rdir) {
  161. int ret = 0;
  162. if (!rdir)
  163. return -1;
  164. if (rdir->stack) {
  165. while (rdir->stlen > 0)
  166. free(rdir->stack[--rdir->stlen]);
  167. free(rdir->stack);
  168. rdir->stack = NULL;
  169. }
  170. if (rdir->dir) {
  171. if (!(ret = closedir(rdir->dir)))
  172. rdir->dir = NULL;
  173. }
  174. if (rdir->d && rdir->name) {
  175. free(rdir->name);
  176. rdir->name = NULL;
  177. }
  178. return ret;
  179. }
  180. char* r_readdir(r_dir_t *rdir) {
  181. size_t len;
  182. char *filename;
  183. struct dirent *dentry;
  184. struct stat fstats;
  185. if (!rdir || !rdir->dir || !rdir->name)
  186. return NULL;
  187. while (1) {
  188. if (rdir->dir && (dentry = readdir(rdir->dir))) {
  189. if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
  190. continue;
  191. len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
  192. filename = (char*) s_malloc(len);
  193. snprintf(filename, len, "%s%s%s", rdir->name,
  194. rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
  195. dentry->d_name);
  196. if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
  197. /* put subdirectory on the stack */
  198. if (rdir->stlen == rdir->stcap) {
  199. rdir->stcap *= 2;
  200. rdir->stack = (char**) s_realloc(rdir->stack,
  201. rdir->stcap * sizeof(char*));
  202. }
  203. rdir->stack[rdir->stlen++] = filename;
  204. continue;
  205. }
  206. return filename;
  207. }
  208. if (rdir->stlen > 0) {
  209. /* open next subdirectory */
  210. closedir(rdir->dir);
  211. if (rdir->d)
  212. free(rdir->name);
  213. rdir->name = rdir->stack[--rdir->stlen];
  214. rdir->d = 1;
  215. if (!(rdir->dir = opendir(rdir->name)))
  216. warn("could not open directory: %s", rdir->name);
  217. continue;
  218. }
  219. /* no more entries */
  220. break;
  221. }
  222. return NULL;
  223. }
  224. int r_mkdir(const char *path) {
  225. char *dir, *d;
  226. struct stat stats;
  227. int err = 0;
  228. if (!path || !*path)
  229. return -1;
  230. if (!stat(path, &stats)) {
  231. if (S_ISDIR(stats.st_mode)) {
  232. return 0;
  233. } else {
  234. warn("not a directory: %s", path);
  235. return -1;
  236. }
  237. }
  238. d = dir = (char*) s_malloc(strlen(path) + 1);
  239. strcpy(dir, path);
  240. while (d != NULL && !err) {
  241. d = strchr(d + 1, '/');
  242. if (d != NULL)
  243. *d = '\0';
  244. if (access(dir, F_OK) && errno == ENOENT) {
  245. if (mkdir(dir, 0755)) {
  246. warn("could not create directory: %s", dir);
  247. err = -1;
  248. }
  249. } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
  250. warn("not a directory: %s", dir);
  251. err = -1;
  252. }
  253. if (d != NULL)
  254. *d = '/';
  255. }
  256. free(dir);
  257. return err;
  258. }