1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim 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 GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
23 #include <sys/types.h>
31 #include <loaders/GP_Loader.h>
32 #include <core/GP_Debug.h>
34 #include "image_list.h"
37 /* list we got from the app */
41 /* counters for files in corresponding arg */
44 /* path to the currently loaded image */
48 /* directory handling */
53 struct dirent
**dir_files
;
56 static int dir_cmp(const struct dirent
**a
, const struct dirent
**b
)
58 return strcasecmp((*a
)->d_name
, (*b
)->d_name
);
61 static int dir_filter(const struct dirent
*d
)
63 /* Ignore some filenames */
64 if (!strcmp(d
->d_name
, "."))
67 if (!strcmp(d
->d_name
, ".."))
70 //TODO: filter out directories
72 if (!GP_LoaderByFilename(d
->d_name
))
75 GP_DEBUG(4, "Adding file '%s'", d
->d_name
);
80 static void try_load_dir(struct image_list
*self
)
83 const char *path
= self
->args
[self
->cur_arg
];
85 if (stat(path
, &sb
)) {
86 GP_WARN("Failed to stat '%s': %s", path
, strerror(errno
));
90 if (!(sb
.st_mode
& S_IFDIR
)) {
91 self
->arg_file_counts
[self
->cur_arg
] = 1;
95 GP_DEBUG(1, "Loading directory '%s' content.", path
);
97 int ret
= scandir(path
, &self
->dir_files
, dir_filter
, dir_cmp
);
100 GP_WARN("Failed to scandir '%s': %s", path
, strerror(errno
));
104 if (self
->arg_file_counts
[self
->cur_arg
] != ret
) {
105 GP_DEBUG(1, "Updating arg counter to %i", ret
);
106 self
->arg_file_counts
[self
->cur_arg
] = ret
;
110 GP_DEBUG(1, "There are no files in '%s'", path
);
114 self
->max_file
= ret
;
119 static void exit_dir(struct image_list
*self
)
123 GP_DEBUG(1, "Freeing directory '%s' content.",
124 self
->args
[self
->cur_arg
]);
126 for (i
= 0; i
< self
->max_file
; i
++)
127 free(self
->dir_files
[i
]);
129 free(self
->dir_files
);
134 static void next_img(struct image_list
*self
)
137 if (++self
->cur_file
== self
->max_file
) {
140 self
->path_loaded
= 0;
145 if (++self
->cur_arg
== self
->max_arg
)
150 self
->path_loaded
= 0;
153 static void prev_img(struct image_list
*self
)
156 if (self
->cur_file
-- == 0) {
159 self
->path_loaded
= 0;
164 /* If we are at first image -> wrap around argv */
165 if (self
->cur_arg
== 0)
166 self
->cur_arg
= self
->max_arg
- 1;
172 /* if in directory, select last image in it */
174 self
->cur_file
= self
->max_file
- 1;
176 self
->path_loaded
= 0;
180 * Sets current image, if we are in directory.
182 static void set_dir_cur_img(struct image_list
*self
, int img
)
185 GP_BUG("Not in directory at %s",
186 self
->args
[self
->cur_arg
]);
190 if (img
< 0 || img
>= self
->max_file
) {
191 GP_BUG("Invalid image index %i", img
);
196 if (self
->cur_file
== img
)
199 self
->cur_file
= img
;
200 self
->path_loaded
= 0;
204 * Returns current argument from arg list we are in.
206 * Either it's image file or directory.
208 static const char *cur_arg(struct image_list
*self
)
210 return self
->args
[self
->cur_arg
];
214 * Sets current argument from arg list.
216 static void set_cur_arg(struct image_list
*self
, int arg
)
218 if (arg
< 0 || arg
>= (int)self
->max_arg
) {
219 GP_BUG("Invalid argument index %i", arg
);
224 if ((int)self
->cur_arg
!= arg
) {
227 self
->path_loaded
= 0;
230 set_dir_cur_img(self
, 0);
235 if ((int)self
->cur_arg
== arg
)
239 self
->path_loaded
= 0;
244 static void load_path(struct image_list
*self
)
247 //TODO: eliminate double /
248 snprintf(self
->path
, sizeof(self
->path
), "%s/%s",
250 self
->dir_files
[self
->cur_file
]->d_name
);
253 snprintf(self
->path
, sizeof(self
->path
), "%s", cur_arg(self
));
256 self
->path_loaded
= 1;
259 const char *image_list_move(struct image_list
*self
, int direction
)
261 GP_DEBUG(2, "Moving list by %i", direction
);
265 for (i
= 0; i
< direction
; i
++)
268 for (i
= 0; i
> direction
; i
--)
271 return image_list_img_path(self
);
274 const char *image_list_dir_move(struct image_list
*self
, int direction
)
277 GP_DEBUG(2, "Not in directory");
278 return image_list_move(self
, direction
);
282 if (self
->cur_file
== self
->max_file
- 1) {
283 GP_DEBUG(2, "Moving after dir '%s'", cur_arg(self
));
286 GP_DEBUG(2, "Moving to last image in dir '%s'",
288 set_dir_cur_img(self
, self
->max_file
- 1);
291 if (self
->cur_file
== 0) {
292 GP_DEBUG(2, "Moving before dir '%s'", cur_arg(self
));
295 GP_DEBUG(2, "Moving to first image in dir '%s'",
297 set_dir_cur_img(self
, 0);
301 return image_list_img_path(self
);
304 const char *image_list_first(struct image_list
*self
)
306 GP_DEBUG(2, "Moving to the first image in the list");
308 set_cur_arg(self
, 0);
311 set_dir_cur_img(self
, 0);
313 return image_list_img_path(self
);
316 const char *image_list_last(struct image_list
*self
)
318 GP_DEBUG(2, "Moving to the last image in the list");
320 set_cur_arg(self
, self
->max_arg
- 1);
323 set_dir_cur_img(self
, self
->max_file
- 1);
325 return image_list_img_path(self
);
328 static unsigned int count_img_to(struct image_list
*self
, unsigned int arg_to
)
330 unsigned int cur_arg
= self
->cur_arg
;
331 unsigned int cur_file
= self
->cur_file
;
332 unsigned int count
= 0, i
;
334 for (i
= 0; i
< arg_to
; i
++) {
335 /* cache number of images in arg */
336 if (self
->arg_file_counts
[i
] == -1)
337 set_cur_arg(self
, i
);
340 * if the counter is still at -1
341 * directory couldn't be loaded
343 if (self
->arg_file_counts
[i
] != -1)
344 count
+= self
->arg_file_counts
[i
];
347 /* restore the original position */
348 set_cur_arg(self
, cur_arg
);
351 set_dir_cur_img(self
, cur_file
);
356 unsigned int image_list_count(struct image_list
*self
)
358 return count_img_to(self
, self
->max_arg
);
361 unsigned int image_list_pos(struct image_list
*self
)
364 return count_img_to(self
, self
->cur_arg
);
366 return count_img_to(self
, self
->cur_arg
) + self
->cur_file
;
369 unsigned int image_list_dir_count(struct image_list
*self
)
374 return self
->max_file
;
377 unsigned int image_list_dir_pos(struct image_list
*self
)
382 return self
->cur_file
;
385 struct image_list
*image_list_create(const char *args
[])
387 struct image_list
*self
;
388 size_t file_count_size
;
391 GP_DEBUG(1, "Creating image list");
393 self
= malloc(sizeof(struct image_list
));
396 GP_WARN("Malloc failed");
403 self
->path_loaded
= 0;
409 while (args
[++self
->max_arg
] != NULL
);
411 file_count_size
= self
->max_arg
* sizeof(int);
412 self
->arg_file_counts
= malloc(file_count_size
);
414 if (self
->arg_file_counts
== NULL
) {
415 GP_WARN("Malloc failed");
420 for (i
= 0; i
< self
->max_arg
; i
++)
421 self
->arg_file_counts
[i
] = -1;
428 void image_list_destroy(struct image_list
*self
)
433 free(self
->arg_file_counts
);
437 const char *image_list_img_path(struct image_list
*self
)
439 if (!self
->path_loaded
)
442 GP_DEBUG(2, "Returning path '%s'", self
->path
);