A Simple X Image Viewer
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

336 řádky
6.4 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. ssize_t get_line(char **buf, size_t *n, FILE *stream)
  83. {
  84. size_t len;
  85. char *s;
  86. if (*buf == NULL || *n == 0) {
  87. *n = BUF_SIZE;
  88. *buf = (char*) s_malloc(*n);
  89. }
  90. s = *buf;
  91. while (true) {
  92. if (fgets(s, *n - (s - *buf), stream) == NULL)
  93. return -1;
  94. len = strlen(s);
  95. if (feof(stream))
  96. break;
  97. if (len > 0 && s[len-1] == '\n')
  98. break;
  99. if (len + 1 == *n - (s - *buf)) {
  100. *buf = (char*) s_realloc(*buf, 2 * *n);
  101. s = *buf + *n - 1;
  102. *n *= 2;
  103. } else {
  104. s += len;
  105. }
  106. }
  107. return s - *buf + len;
  108. }
  109. void size_readable(float *size, const char **unit)
  110. {
  111. const char *units[] = { "", "K", "M", "G" };
  112. int i;
  113. for (i = 0; i < ARRLEN(units) && *size > 1024.0; i++)
  114. *size /= 1024.0;
  115. *unit = units[MIN(i, ARRLEN(units) - 1)];
  116. }
  117. char* absolute_path(const char *filename)
  118. {
  119. size_t len;
  120. const char *basename;
  121. char *dir, *dirname = NULL, *path = NULL, *s;
  122. char *cwd = NULL, *twd = NULL;
  123. if (*filename == '\0' || *filename == '/')
  124. return NULL;
  125. len = FNAME_LEN;
  126. cwd = (char*) s_malloc(len);
  127. while ((s = getcwd(cwd, len)) == NULL && errno == ERANGE) {
  128. len *= 2;
  129. cwd = (char*) s_realloc(cwd, len);
  130. }
  131. if (s == NULL)
  132. goto error;
  133. s = strrchr(filename, '/');
  134. if (s != NULL) {
  135. len = s - filename;
  136. dirname = (char*) s_malloc(len + 1);
  137. strncpy(dirname, filename, len);
  138. dirname[len] = '\0';
  139. basename = s + 1;
  140. if (chdir(cwd) < 0)
  141. /* we're not able to come back afterwards */
  142. goto error;
  143. if (chdir(dirname) < 0)
  144. goto error;
  145. len = FNAME_LEN;
  146. twd = (char*) s_malloc(len);
  147. while ((s = getcwd(twd, len)) == NULL && errno == ERANGE) {
  148. len *= 2;
  149. twd = (char*) s_realloc(twd, len);
  150. }
  151. if (chdir(cwd) < 0)
  152. die("could not revert to prior working directory");
  153. if (s == NULL)
  154. goto error;
  155. dir = twd;
  156. } else {
  157. /* only a single filename given */
  158. basename = filename;
  159. dir = cwd;
  160. }
  161. len = strlen(dir) + strlen(basename) + 2;
  162. path = (char*) s_malloc(len);
  163. snprintf(path, len, "%s/%s", dir, basename);
  164. goto end;
  165. error:
  166. free(path);
  167. path = NULL;
  168. end:
  169. free(dirname);
  170. free(cwd);
  171. free(twd);
  172. return path;
  173. }
  174. int r_opendir(r_dir_t *rdir, const char *dirname)
  175. {
  176. if (*dirname == '\0')
  177. return -1;
  178. if ((rdir->dir = opendir(dirname)) == NULL) {
  179. rdir->name = NULL;
  180. rdir->stack = NULL;
  181. return -1;
  182. }
  183. rdir->stcap = DNAME_CNT;
  184. rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
  185. rdir->stlen = 0;
  186. rdir->name = (char*) dirname;
  187. rdir->d = 0;
  188. return 0;
  189. }
  190. int r_closedir(r_dir_t *rdir)
  191. {
  192. int ret = 0;
  193. if (rdir->stack != NULL) {
  194. while (rdir->stlen > 0)
  195. free(rdir->stack[--rdir->stlen]);
  196. free(rdir->stack);
  197. rdir->stack = NULL;
  198. }
  199. if (rdir->dir != NULL) {
  200. if ((ret = closedir(rdir->dir)) == 0)
  201. rdir->dir = NULL;
  202. }
  203. if (rdir->d != 0) {
  204. free(rdir->name);
  205. rdir->name = NULL;
  206. }
  207. return ret;
  208. }
  209. char* r_readdir(r_dir_t *rdir)
  210. {
  211. size_t len;
  212. char *filename;
  213. struct dirent *dentry;
  214. struct stat fstats;
  215. while (true) {
  216. if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
  217. if (dentry->d_name[0] == '.')
  218. continue;
  219. len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
  220. filename = (char*) s_malloc(len);
  221. snprintf(filename, len, "%s%s%s", rdir->name,
  222. rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
  223. dentry->d_name);
  224. if (stat(filename, &fstats) < 0)
  225. continue;
  226. if (S_ISDIR(fstats.st_mode)) {
  227. /* put subdirectory on the stack */
  228. if (rdir->stlen == rdir->stcap) {
  229. rdir->stcap *= 2;
  230. rdir->stack = (char**) s_realloc(rdir->stack,
  231. rdir->stcap * sizeof(char*));
  232. }
  233. rdir->stack[rdir->stlen++] = filename;
  234. continue;
  235. }
  236. return filename;
  237. }
  238. if (rdir->stlen > 0) {
  239. /* open next subdirectory */
  240. closedir(rdir->dir);
  241. if (rdir->d != 0)
  242. free(rdir->name);
  243. rdir->name = rdir->stack[--rdir->stlen];
  244. rdir->d = 1;
  245. if ((rdir->dir = opendir(rdir->name)) == NULL)
  246. warn("could not open directory: %s", rdir->name);
  247. continue;
  248. }
  249. /* no more entries */
  250. break;
  251. }
  252. return NULL;
  253. }
  254. int r_mkdir(const char *path)
  255. {
  256. char *dir, *d;
  257. struct stat stats;
  258. int err = 0;
  259. if (*path == '\0')
  260. return -1;
  261. if (stat(path, &stats) == 0)
  262. return S_ISDIR(stats.st_mode) ? 0 : -1;
  263. d = dir = (char*) s_malloc(strlen(path) + 1);
  264. strcpy(dir, path);
  265. while (d != NULL && err == 0) {
  266. d = strchr(d + 1, '/');
  267. if (d != NULL)
  268. *d = '\0';
  269. if (access(dir, F_OK) < 0 && errno == ENOENT) {
  270. if (mkdir(dir, 0755) < 0) {
  271. warn("could not create directory: %s", dir);
  272. err = -1;
  273. }
  274. } else if (stat(dir, &stats) < 0 || !S_ISDIR(stats.st_mode)) {
  275. err = -1;
  276. }
  277. if (d != NULL)
  278. *d = '/';
  279. }
  280. free(dir);
  281. return err;
  282. }