A Simple X Image Viewer
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

util.c 6.3 KiB

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