A Simple X Image Viewer
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

302 lines
6.0 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 <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. 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 r_opendir(r_dir_t *rdir, const char *dirname) {
  137. if (!rdir || !dirname || !*dirname)
  138. return -1;
  139. if (!(rdir->dir = opendir(dirname))) {
  140. rdir->name = NULL;
  141. rdir->stack = NULL;
  142. return -1;
  143. }
  144. rdir->stcap = DNAME_CNT;
  145. rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
  146. rdir->stlen = 0;
  147. rdir->name = (char*) dirname;
  148. rdir->d = 0;
  149. return 0;
  150. }
  151. int r_closedir(r_dir_t *rdir) {
  152. int ret = 0;
  153. if (!rdir)
  154. return -1;
  155. if (rdir->stack) {
  156. while (rdir->stlen > 0)
  157. free(rdir->stack[--rdir->stlen]);
  158. free(rdir->stack);
  159. rdir->stack = NULL;
  160. }
  161. if (rdir->dir) {
  162. if (!(ret = closedir(rdir->dir)))
  163. rdir->dir = NULL;
  164. }
  165. if (rdir->d && rdir->name) {
  166. free(rdir->name);
  167. rdir->name = NULL;
  168. }
  169. return ret;
  170. }
  171. char* r_readdir(r_dir_t *rdir) {
  172. size_t len;
  173. char *filename;
  174. struct dirent *dentry;
  175. struct stat fstats;
  176. if (!rdir || !rdir->dir || !rdir->name)
  177. return NULL;
  178. while (1) {
  179. if (rdir->dir && (dentry = readdir(rdir->dir))) {
  180. if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
  181. continue;
  182. len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
  183. filename = (char*) s_malloc(len);
  184. snprintf(filename, len, "%s%s%s", rdir->name,
  185. rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
  186. dentry->d_name);
  187. if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
  188. /* put subdirectory on the stack */
  189. if (rdir->stlen == rdir->stcap) {
  190. rdir->stcap *= 2;
  191. rdir->stack = (char**) s_realloc(rdir->stack,
  192. rdir->stcap * sizeof(char*));
  193. }
  194. rdir->stack[rdir->stlen++] = filename;
  195. continue;
  196. }
  197. return filename;
  198. }
  199. if (rdir->stlen > 0) {
  200. /* open next subdirectory */
  201. closedir(rdir->dir);
  202. if (rdir->d)
  203. free(rdir->name);
  204. rdir->name = rdir->stack[--rdir->stlen];
  205. rdir->d = 1;
  206. if (!(rdir->dir = opendir(rdir->name)))
  207. warn("could not open directory: %s", rdir->name);
  208. continue;
  209. }
  210. /* no more entries */
  211. break;
  212. }
  213. return NULL;
  214. }
  215. int r_mkdir(const char *path) {
  216. char *dir, *d;
  217. struct stat stats;
  218. int err = 0;
  219. if (!path || !*path)
  220. return -1;
  221. if (!stat(path, &stats)) {
  222. if (S_ISDIR(stats.st_mode)) {
  223. return 0;
  224. } else {
  225. warn("not a directory: %s", path);
  226. return -1;
  227. }
  228. }
  229. d = dir = (char*) s_malloc(strlen(path) + 1);
  230. strcpy(dir, path);
  231. while (d != NULL && !err) {
  232. d = strchr(d + 1, '/');
  233. if (d != NULL)
  234. *d = '\0';
  235. if (access(dir, F_OK) && errno == ENOENT) {
  236. if (mkdir(dir, 0755)) {
  237. warn("could not create directory: %s", dir);
  238. err = -1;
  239. }
  240. } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
  241. warn("not a directory: %s", dir);
  242. err = -1;
  243. }
  244. if (d != NULL)
  245. *d = '/';
  246. }
  247. free(dir);
  248. return err;
  249. }