A Simple X Image Viewer
 
 
 
 
 
 

238 lines
4.6 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. int r_opendir(r_dir_t *rdir, const char *dirname)
  91. {
  92. if (*dirname == '\0')
  93. return -1;
  94. if ((rdir->dir = opendir(dirname)) == NULL) {
  95. rdir->name = NULL;
  96. rdir->stack = NULL;
  97. return -1;
  98. }
  99. rdir->stcap = DNAME_CNT;
  100. rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
  101. rdir->stlen = 0;
  102. rdir->name = (char*) dirname;
  103. rdir->d = 0;
  104. return 0;
  105. }
  106. int r_closedir(r_dir_t *rdir)
  107. {
  108. int ret = 0;
  109. if (rdir->stack != NULL) {
  110. while (rdir->stlen > 0)
  111. free(rdir->stack[--rdir->stlen]);
  112. free(rdir->stack);
  113. rdir->stack = NULL;
  114. }
  115. if (rdir->dir != NULL) {
  116. if ((ret = closedir(rdir->dir)) == 0)
  117. rdir->dir = NULL;
  118. }
  119. if (rdir->d != 0) {
  120. free(rdir->name);
  121. rdir->name = NULL;
  122. }
  123. return ret;
  124. }
  125. char* r_readdir(r_dir_t *rdir)
  126. {
  127. size_t len;
  128. char *filename;
  129. struct dirent *dentry;
  130. struct stat fstats;
  131. while (true) {
  132. if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
  133. if (dentry->d_name[0] == '.')
  134. continue;
  135. len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
  136. filename = (char*) s_malloc(len);
  137. snprintf(filename, len, "%s%s%s", rdir->name,
  138. rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
  139. dentry->d_name);
  140. if (stat(filename, &fstats) < 0)
  141. continue;
  142. if (S_ISDIR(fstats.st_mode)) {
  143. /* put subdirectory on the stack */
  144. if (rdir->stlen == rdir->stcap) {
  145. rdir->stcap *= 2;
  146. rdir->stack = (char**) s_realloc(rdir->stack,
  147. rdir->stcap * sizeof(char*));
  148. }
  149. rdir->stack[rdir->stlen++] = filename;
  150. continue;
  151. }
  152. return filename;
  153. }
  154. if (rdir->stlen > 0) {
  155. /* open next subdirectory */
  156. closedir(rdir->dir);
  157. if (rdir->d != 0)
  158. free(rdir->name);
  159. rdir->name = rdir->stack[--rdir->stlen];
  160. rdir->d = 1;
  161. if ((rdir->dir = opendir(rdir->name)) == NULL)
  162. warn("could not open directory: %s", rdir->name);
  163. continue;
  164. }
  165. /* no more entries */
  166. break;
  167. }
  168. return NULL;
  169. }
  170. int r_mkdir(const char *path)
  171. {
  172. char *dir, *d;
  173. struct stat stats;
  174. int err = 0;
  175. if (*path == '\0')
  176. return -1;
  177. if (stat(path, &stats) == 0)
  178. return S_ISDIR(stats.st_mode) ? 0 : -1;
  179. d = dir = (char*) s_malloc(strlen(path) + 1);
  180. strcpy(dir, path);
  181. while (d != NULL && err == 0) {
  182. d = strchr(d + 1, '/');
  183. if (d != NULL)
  184. *d = '\0';
  185. if (access(dir, F_OK) < 0 && errno == ENOENT) {
  186. if (mkdir(dir, 0755) < 0) {
  187. warn("could not create directory: %s", dir);
  188. err = -1;
  189. }
  190. } else if (stat(dir, &stats) < 0 || !S_ISDIR(stats.st_mode)) {
  191. err = -1;
  192. }
  193. if (d != NULL)
  194. *d = '/';
  195. }
  196. free(dir);
  197. return err;
  198. }