A Simple X Image Viewer
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

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