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