A Simple X Image Viewer
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

347 rindas
6.7 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(const 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. free(path);
  170. path = NULL;
  171. end:
  172. free(dirname);
  173. free(cwd);
  174. free(twd);
  175. return path;
  176. }
  177. int r_opendir(r_dir_t *rdir, const char *dirname)
  178. {
  179. if (rdir == NULL || dirname == NULL || *dirname == '\0')
  180. return -1;
  181. if ((rdir->dir = opendir(dirname)) == NULL) {
  182. rdir->name = NULL;
  183. rdir->stack = NULL;
  184. return -1;
  185. }
  186. rdir->stcap = DNAME_CNT;
  187. rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
  188. rdir->stlen = 0;
  189. rdir->name = (char*) dirname;
  190. rdir->d = 0;
  191. return 0;
  192. }
  193. int r_closedir(r_dir_t *rdir)
  194. {
  195. int ret = 0;
  196. if (rdir == NULL)
  197. return -1;
  198. if (rdir->stack != NULL) {
  199. while (rdir->stlen > 0)
  200. free(rdir->stack[--rdir->stlen]);
  201. free(rdir->stack);
  202. rdir->stack = NULL;
  203. }
  204. if (rdir->dir != NULL) {
  205. if ((ret = closedir(rdir->dir)) == 0)
  206. rdir->dir = NULL;
  207. }
  208. if (rdir->d != 0) {
  209. free(rdir->name);
  210. rdir->name = NULL;
  211. }
  212. return ret;
  213. }
  214. char* r_readdir(r_dir_t *rdir)
  215. {
  216. size_t len;
  217. char *filename;
  218. struct dirent *dentry;
  219. struct stat fstats;
  220. if (rdir == NULL || rdir->dir == NULL || rdir->name == NULL)
  221. return NULL;
  222. while (true) {
  223. if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
  224. if (dentry->d_name[0] == '.')
  225. continue;
  226. len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
  227. filename = (char*) s_malloc(len);
  228. snprintf(filename, len, "%s%s%s", rdir->name,
  229. rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
  230. dentry->d_name);
  231. if (stat(filename, &fstats) < 0)
  232. continue;
  233. if (S_ISDIR(fstats.st_mode)) {
  234. /* put subdirectory on the stack */
  235. if (rdir->stlen == rdir->stcap) {
  236. rdir->stcap *= 2;
  237. rdir->stack = (char**) s_realloc(rdir->stack,
  238. rdir->stcap * sizeof(char*));
  239. }
  240. rdir->stack[rdir->stlen++] = filename;
  241. continue;
  242. }
  243. return filename;
  244. }
  245. if (rdir->stlen > 0) {
  246. /* open next subdirectory */
  247. closedir(rdir->dir);
  248. if (rdir->d != 0)
  249. free(rdir->name);
  250. rdir->name = rdir->stack[--rdir->stlen];
  251. rdir->d = 1;
  252. if ((rdir->dir = opendir(rdir->name)) == NULL)
  253. warn("could not open directory: %s", rdir->name);
  254. continue;
  255. }
  256. /* no more entries */
  257. break;
  258. }
  259. return NULL;
  260. }
  261. int r_mkdir(const char *path)
  262. {
  263. char *dir, *d;
  264. struct stat stats;
  265. int err = 0;
  266. if (path == NULL || *path == '\0')
  267. return -1;
  268. if (stat(path, &stats) == 0)
  269. return S_ISDIR(stats.st_mode) ? 0 : -1;
  270. d = dir = (char*) s_malloc(strlen(path) + 1);
  271. strcpy(dir, path);
  272. while (d != NULL && err == 0) {
  273. d = strchr(d + 1, '/');
  274. if (d != NULL)
  275. *d = '\0';
  276. if (access(dir, F_OK) < 0 && errno == ENOENT) {
  277. if (mkdir(dir, 0755) < 0) {
  278. warn("could not create directory: %s", dir);
  279. err = -1;
  280. }
  281. } else if (stat(dir, &stats) < 0 || !S_ISDIR(stats.st_mode)) {
  282. err = -1;
  283. }
  284. if (d != NULL)
  285. *d = '/';
  286. }
  287. free(dir);
  288. return err;
  289. }