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.
 
 
 
 
 
 

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