A Simple X Image Viewer
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 
 

306 líneas
5.9 KiB

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