"Fossies" - the Fresh Open Source Software Archive

Member "feh-3.4.1/src/filelist.c" (29 May 2020, 16192 Bytes) of package /linux/privat/feh-3.4.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "filelist.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.4_vs_3.4.1.

    1 /* filelist.c
    2 
    3 Copyright (C) 1999-2003 Tom Gilbert.
    4 Copyright (C) 2010-2020 Daniel Friesel.
    5 
    6 Permission is hereby granted, free of charge, to any person obtaining a copy
    7 of this software and associated documentation files (the "Software"), to
    8 deal in the Software without restriction, including without limitation the
    9 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   10 sell copies of the Software, and to permit persons to whom the Software is
   11 furnished to do so, subject to the following conditions:
   12 
   13 The above copyright notice and this permission notice shall be included in
   14 all copies of the Software and its documentation and acknowledgment shall be
   15 given in the documentation and software packages that this Software was
   16 used.
   17 
   18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   21 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   22 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   24 
   25 */
   26 
   27 #ifdef HAVE_LIBEXIF
   28 #include <libexif/exif-data.h>
   29 #endif
   30 
   31 #include "feh.h"
   32 #include "filelist.h"
   33 #include "signals.h"
   34 #include "options.h"
   35 
   36 gib_list *filelist = NULL;
   37 gib_list *original_file_items = NULL; /* original file items from argv */
   38 int filelist_len = 0;
   39 gib_list *current_file = NULL;
   40 extern int errno;
   41 
   42 static gib_list *rm_filelist = NULL;
   43 
   44 feh_file *feh_file_new(char *filename)
   45 {
   46     feh_file *newfile;
   47     char *s;
   48 
   49     newfile = (feh_file *) emalloc(sizeof(feh_file));
   50     newfile->caption = NULL;
   51     newfile->filename = estrdup(filename);
   52     s = strrchr(filename, '/');
   53     if (s)
   54         newfile->name = estrdup(s + 1);
   55     else
   56         newfile->name = estrdup(filename);
   57     newfile->info = NULL;
   58 #ifdef HAVE_LIBEXIF
   59     newfile->ed = NULL;
   60 #endif
   61     return(newfile);
   62 }
   63 
   64 void feh_file_free(feh_file * file)
   65 {
   66     if (!file)
   67         return;
   68     if (file->filename)
   69         free(file->filename);
   70     if (file->name)
   71         free(file->name);
   72     if (file->caption)
   73         free(file->caption);
   74     if (file->info)
   75         feh_file_info_free(file->info);
   76 #ifdef HAVE_LIBEXIF
   77     if (file->ed)
   78         exif_data_unref(file->ed);
   79 #endif
   80     free(file);
   81     return;
   82 }
   83 
   84 feh_file_info *feh_file_info_new(void)
   85 {
   86     feh_file_info *info;
   87 
   88 
   89     info = (feh_file_info *) emalloc(sizeof(feh_file_info));
   90 
   91     info->width = 0;
   92     info->height = 0;
   93     info->size = 0;
   94     info->pixels = 0;
   95     info->has_alpha = 0;
   96     info->format = NULL;
   97     info->extension = NULL;
   98 
   99     return(info);
  100 }
  101 
  102 void feh_file_info_free(feh_file_info * info)
  103 {
  104     if (!info)
  105         return;
  106     if (info->format)
  107         free(info->format);
  108     if (info->extension)
  109         free(info->extension);
  110     free(info);
  111     return;
  112 }
  113 
  114 gib_list *feh_file_rm_and_free(gib_list * list, gib_list * l)
  115 {
  116     unlink(FEH_FILE(l->data)->filename);
  117     return(feh_file_remove_from_list(list, l));
  118 }
  119 
  120 gib_list *feh_file_remove_from_list(gib_list * list, gib_list * l)
  121 {
  122     feh_file_free(FEH_FILE(l->data));
  123     D(("filelist_len %d -> %d\n", filelist_len, filelist_len - 1));
  124     filelist_len--;
  125     return(gib_list_remove(list, l));
  126 }
  127 
  128 int file_selector_all(const struct dirent *unused __attribute__((unused)))
  129 {
  130   return 1;
  131 }
  132 
  133 static void feh_print_stat_error(char *path)
  134 {
  135     if (opt.quiet)
  136         return;
  137 
  138     switch (errno) {
  139     case ENOENT:
  140     case ENOTDIR:
  141         weprintf("%s does not exist - skipping", path);
  142         break;
  143     case ELOOP:
  144         weprintf("%s - too many levels of symbolic links - skipping", path);
  145         break;
  146     case EACCES:
  147         weprintf("you don't have permission to open %s - skipping", path);
  148         break;
  149     case EOVERFLOW:
  150         weprintf("Cannot open %s - EOVERFLOW.\n"
  151             "Recompile with stat64=1 to fix this", path);
  152         break;
  153     default:
  154         weprintf("couldn't open %s", path);
  155         break;
  156     }
  157 }
  158 
  159 static void add_stdin_to_filelist()
  160 {
  161     char buf[1024];
  162     size_t readsize;
  163     char *sfn = estrjoin("_", "/tmp/feh_stdin", "XXXXXX", NULL);
  164     int fd = mkstemp(sfn);
  165     FILE *outfile;
  166 
  167     if (fd == -1) {
  168         free(sfn);
  169         weprintf("cannot read from stdin: mktemp:");
  170         return;
  171     }
  172 
  173     outfile = fdopen(fd, "w");
  174 
  175     if (outfile == NULL) {
  176         free(sfn);
  177         weprintf("cannot read from stdin: fdopen:");
  178         return;
  179     }
  180 
  181     while ((readsize = fread(buf, sizeof(char), sizeof(buf), stdin)) > 0) {
  182         if (fwrite(buf, sizeof(char), readsize, outfile) < readsize) {
  183             free(sfn);
  184             return;
  185         }
  186     }
  187     fclose(outfile);
  188 
  189     filelist = gib_list_add_front(filelist, feh_file_new(sfn));
  190     add_file_to_rm_filelist(sfn);
  191     free(sfn);
  192 }
  193 
  194 
  195 /* Recursive */
  196 void add_file_to_filelist_recursively(char *origpath, unsigned char level)
  197 {
  198     struct stat st;
  199     char *path;
  200 
  201     if (!origpath)
  202         return;
  203 
  204     path = estrdup(origpath);
  205     D(("file is %s\n", path));
  206 
  207     if (level == FILELIST_FIRST) {
  208         /* First time through, sort out pathname */
  209         int len = 0;
  210 
  211         len = strlen(path);
  212         if (path[len - 1] == '/')
  213             path[len - 1] = '\0';
  214 
  215         if (path_is_url(path)) {
  216             D(("Adding url %s to filelist\n", path));
  217             filelist = gib_list_add_front(filelist, feh_file_new(path));
  218             /* We'll download it later... */
  219             free(path);
  220             return;
  221         } else if ((len == 1) && (path[0] == '-')) {
  222             D(("Adding temporary file for stdin (-) to filelist\n"));
  223             add_stdin_to_filelist();
  224             free(path);
  225             return;
  226         } else if (opt.filelistfile) {
  227             char *newpath = feh_absolute_path(path);
  228 
  229             free(path);
  230             path = newpath;
  231         }
  232     }
  233 
  234     errno = 0;
  235     if (stat(path, &st)) {
  236         feh_print_stat_error(path);
  237         free(path);
  238         return;
  239     }
  240 
  241     if ((S_ISDIR(st.st_mode)) && (level != FILELIST_LAST)) {
  242         struct dirent **de;
  243         DIR *dir;
  244         int cnt, n;
  245 
  246         D(("It is a directory\n"));
  247 
  248         if ((dir = opendir(path)) == NULL) {
  249             if (!opt.quiet)
  250                 weprintf("couldn't open directory %s:", path);
  251             free(path);
  252             return;
  253         }
  254         n = scandir(path, &de, file_selector_all, alphasort);
  255         if (n < 0) {
  256             switch (errno) {
  257             case ENOMEM:
  258                 weprintf("Insufficient memory to scan directory %s:", path);
  259                 break;
  260             default:
  261                 weprintf("Failed to scan directory %s:", path);
  262             }
  263         } else {
  264             for (cnt = 0; cnt < n; cnt++) {
  265                 if (strcmp(de[cnt]->d_name, ".")
  266                         && strcmp(de[cnt]->d_name, "..")) {
  267                     char *newfile;
  268 
  269                     newfile = estrjoin("", path, "/", de[cnt]->d_name, NULL);
  270 
  271                     /* This ensures we go down one level even if not fully recursive
  272                        - this way "feh some_dir" expands to some_dir's contents */
  273                     if (opt.recursive)
  274                         add_file_to_filelist_recursively(newfile, FILELIST_CONTINUE);
  275                     else
  276                         add_file_to_filelist_recursively(newfile, FILELIST_LAST);
  277 
  278                     free(newfile);
  279                 }
  280                 free(de[cnt]);
  281             }
  282             free(de);
  283         }
  284         closedir(dir);
  285     } else if (S_ISREG(st.st_mode)) {
  286         D(("Adding regular file %s to filelist\n", path));
  287         filelist = gib_list_add_front(filelist, feh_file_new(path));
  288     }
  289     free(path);
  290     return;
  291 }
  292 
  293 void add_file_to_rm_filelist(char *file)
  294 {
  295     rm_filelist = gib_list_add_front(rm_filelist, feh_file_new(file));
  296     return;
  297 }
  298 
  299 void delete_rm_files(void)
  300 {
  301     gib_list *l;
  302 
  303     for (l = rm_filelist; l; l = l->next)
  304         unlink(FEH_FILE(l->data)->filename);
  305     return;
  306 }
  307 
  308 gib_list *feh_file_info_preload(gib_list * list)
  309 {
  310     gib_list *l;
  311     feh_file *file = NULL;
  312     gib_list *remove_list = NULL;
  313 
  314     for (l = list; l; l = l->next) {
  315         file = FEH_FILE(l->data);
  316         D(("file %p, file->next %p, file->name %s\n", l, l->next, file->name));
  317         if (feh_file_info_load(file, NULL)) {
  318             D(("Failed to load file %p\n", file));
  319             remove_list = gib_list_add_front(remove_list, l);
  320             if (opt.verbose)
  321                 feh_display_status('x');
  322         } else if (((unsigned int)file->info->width < opt.min_width)
  323                 || ((unsigned int)file->info->width > opt.max_width)
  324                 || ((unsigned int)file->info->height < opt.min_height)
  325                 || ((unsigned int)file->info->height > opt.max_height)) {
  326             remove_list = gib_list_add_front(remove_list, l);
  327             if (opt.verbose)
  328                 feh_display_status('s');
  329         } else if (opt.verbose)
  330             feh_display_status('.');
  331         if (sig_exit) {
  332             feh_display_status(0);
  333             exit(sig_exit);
  334         }
  335     }
  336     if (opt.verbose)
  337         feh_display_status(0);
  338 
  339     if (remove_list) {
  340         for (l = remove_list; l; l = l->next) {
  341             feh_file_free(FEH_FILE(((gib_list *) l->data)->data));
  342             filelist = list = gib_list_remove(list, (gib_list *) l->data);
  343         }
  344 
  345         gib_list_free(remove_list);
  346     }
  347 
  348     return(list);
  349 }
  350 
  351 int feh_file_info_load(feh_file * file, Imlib_Image im)
  352 {
  353     struct stat st;
  354     int need_free = 1;
  355     Imlib_Image im1;
  356 
  357     D(("im is %p\n", im));
  358 
  359     if (im)
  360         need_free = 0;
  361 
  362     errno = 0;
  363     if (stat(file->filename, &st)) {
  364         feh_print_stat_error(file->filename);
  365         return(1);
  366     }
  367 
  368     if (im)
  369         im1 = im;
  370     else if (!feh_load_image(&im1, file) || !im1)
  371         return(1);
  372 
  373     file->info = feh_file_info_new();
  374 
  375     file->info->width = gib_imlib_image_get_width(im1);
  376     file->info->height = gib_imlib_image_get_height(im1);
  377 
  378     file->info->has_alpha = gib_imlib_image_has_alpha(im1);
  379 
  380     file->info->pixels = file->info->width * file->info->height;
  381 
  382     file->info->format = estrdup(gib_imlib_image_format(im1));
  383 
  384     file->info->size = st.st_size;
  385 
  386     if (need_free)
  387         gib_imlib_free_image_and_decache(im1);
  388     return(0);
  389 }
  390 
  391 void feh_file_dirname(char *dst, feh_file * f, int maxlen)
  392 {
  393     int n = strlen(f->filename) - strlen(f->name);
  394 
  395     /* Give up on long dirnames */
  396     if (n <= 0 || n >= maxlen) {
  397         dst[0] = '\0';
  398         return;
  399     }
  400 
  401     strncpy(dst, f->filename, n);
  402     dst[n] = '\0';
  403 }
  404 
  405 #ifdef HAVE_VERSCMP
  406 static inline int strcmp_or_strverscmp(const char *s1, const char *s2)
  407 {
  408     if (!opt.version_sort)
  409         return(strcmp(s1, s2));
  410     else
  411         return(strverscmp(s1, s2));
  412 }
  413 #else
  414 #define strcmp_or_strverscmp strcmp
  415 #endif
  416 
  417 int feh_cmp_filename(void *file1, void *file2)
  418 {
  419     return(strcmp_or_strverscmp(FEH_FILE(file1)->filename, FEH_FILE(file2)->filename));
  420 }
  421 
  422 int feh_cmp_name(void *file1, void *file2)
  423 {
  424     return(strcmp_or_strverscmp(FEH_FILE(file1)->name, FEH_FILE(file2)->name));
  425 }
  426 
  427 int feh_cmp_dirname(void *file1, void *file2)
  428 {
  429     char dir1[PATH_MAX], dir2[PATH_MAX];
  430     int cmp;
  431     feh_file_dirname(dir1, FEH_FILE(file1), PATH_MAX);
  432     feh_file_dirname(dir2, FEH_FILE(file2), PATH_MAX);
  433     if ((cmp = strcmp_or_strverscmp(dir1, dir2)) != 0)
  434         return(cmp);
  435     return(feh_cmp_name(file1, file2));
  436 }
  437 
  438 /* Return -1 if file1 is _newer_ than file2 */
  439 int feh_cmp_mtime(void *file1, void *file2)
  440 {
  441     struct stat s1, s2;
  442 
  443     if (stat(FEH_FILE(file1)->filename, &s1)) {
  444         feh_print_stat_error(FEH_FILE(file1)->filename);
  445         return(-1);
  446     }
  447 
  448     if (stat(FEH_FILE(file2)->filename, &s2)) {
  449         feh_print_stat_error(FEH_FILE(file2)->filename);
  450         return(-1);
  451     }
  452 
  453     /* gib_list_sort is not stable, so explicitly return 0 as -1 */
  454     return(s1.st_mtime >= s2.st_mtime ? -1 : 1);
  455 }
  456 
  457 int feh_cmp_width(void *file1, void *file2)
  458 {
  459     return((FEH_FILE(file1)->info->width - FEH_FILE(file2)->info->width));
  460 }
  461 
  462 int feh_cmp_height(void *file1, void *file2)
  463 {
  464     return((FEH_FILE(file1)->info->height - FEH_FILE(file2)->info->height));
  465 }
  466 
  467 int feh_cmp_pixels(void *file1, void *file2)
  468 {
  469     return((FEH_FILE(file1)->info->pixels - FEH_FILE(file2)->info->pixels));
  470 }
  471 
  472 int feh_cmp_size(void *file1, void *file2)
  473 {
  474     return((FEH_FILE(file1)->info->size - FEH_FILE(file2)->info->size));
  475 }
  476 
  477 int feh_cmp_format(void *file1, void *file2)
  478 {
  479     return(strcmp(FEH_FILE(file1)->info->format, FEH_FILE(file2)->info->format));
  480 }
  481 
  482 void feh_prepare_filelist(void)
  483 {
  484     /*
  485      * list and customlist mode as well as the somewhat more fancy sort modes
  486      * need access to file infos. Preloading them is also useful for
  487      * list/customlist as --min-dimension/--max-dimension may filter images
  488      * which should not be processed.
  489      * Finally, if --min-dimension/--max-dimension (-> opt.filter_by_dimensions)
  490      * is set and we're in thumbnail mode, we need to filter images first so
  491      * we can create a properly sized thumbnail list.
  492      */
  493     if (opt.list || opt.preload || opt.customlist || (opt.sort > SORT_MTIME)
  494             || (opt.filter_by_dimensions && (opt.index || opt.thumbs || opt.bgmode))) {
  495         /* For these sort options, we have to preload images */
  496         filelist = feh_file_info_preload(filelist);
  497         if (!gib_list_length(filelist))
  498             show_mini_usage();
  499     }
  500 
  501     D(("sort mode requested is: %d\n", opt.sort));
  502     switch (opt.sort) {
  503     case SORT_NONE:
  504         if (opt.randomize) {
  505             /* Randomize the filename order */
  506             filelist = gib_list_randomize(filelist);
  507         } else if (!opt.reverse) {
  508             /* Let's reverse the list. Its back-to-front right now ;) */
  509             filelist = gib_list_reverse(filelist);
  510         }
  511         break;
  512     case SORT_NAME:
  513         filelist = gib_list_sort(filelist, feh_cmp_name);
  514         break;
  515     case SORT_FILENAME:
  516         filelist = gib_list_sort(filelist, feh_cmp_filename);
  517         break;
  518     case SORT_DIRNAME:
  519         filelist = gib_list_sort(filelist, feh_cmp_dirname);
  520         break;
  521     case SORT_MTIME:
  522         filelist = gib_list_sort(filelist, feh_cmp_mtime);
  523         break;
  524     case SORT_WIDTH:
  525         filelist = gib_list_sort(filelist, feh_cmp_width);
  526         break;
  527     case SORT_HEIGHT:
  528         filelist = gib_list_sort(filelist, feh_cmp_height);
  529         break;
  530     case SORT_PIXELS:
  531         filelist = gib_list_sort(filelist, feh_cmp_pixels);
  532         break;
  533     case SORT_SIZE:
  534         filelist = gib_list_sort(filelist, feh_cmp_size);
  535         break;
  536     case SORT_FORMAT:
  537         filelist = gib_list_sort(filelist, feh_cmp_format);
  538         break;
  539     default:
  540         break;
  541     }
  542 
  543     /* no point reversing a random list */
  544     if (opt.reverse && (opt.sort != SORT_NONE)) {
  545         D(("Reversing filelist as requested\n"));
  546         filelist = gib_list_reverse(filelist);
  547     }
  548 
  549     return;
  550 }
  551 
  552 int feh_write_filelist(gib_list * list, char *filename)
  553 {
  554     FILE *fp;
  555     gib_list *l;
  556 
  557     if (!list || !filename || !strcmp(filename, "/dev/stdin"))
  558         return(0);
  559 
  560     errno = 0;
  561     if ((fp = fopen(filename, "w")) == NULL) {
  562         weprintf("can't write filelist %s:", filename);
  563         return(0);
  564     }
  565 
  566     for (l = list; l; l = l->next)
  567         fprintf(fp, "%s\n", (FEH_FILE(l->data)->filename));
  568 
  569     fclose(fp);
  570 
  571     return(1);
  572 }
  573 
  574 gib_list *feh_read_filelist(char *filename)
  575 {
  576     FILE *fp;
  577     gib_list *list = NULL;
  578     char s[1024], s1[1024];
  579     Imlib_Load_Error err = IMLIB_LOAD_ERROR_NONE;
  580     Imlib_Image tmp_im;
  581     struct stat st;
  582     signed short tmp_conversion_timeout;
  583 
  584     if (!filename)
  585         return(NULL);
  586 
  587     /*
  588      * feh_load_image will fail horribly if filename is not seekable
  589      */
  590     tmp_conversion_timeout = opt.conversion_timeout;
  591     opt.conversion_timeout = -1;
  592     if (!stat(filename, &st) && S_ISREG(st.st_mode)) {
  593         tmp_im = imlib_load_image_with_error_return(filename, &err);
  594         if (err == IMLIB_LOAD_ERROR_NONE) {
  595             gib_imlib_free_image_and_decache(tmp_im);
  596             weprintf("Filelist file %s is an image, refusing to use it.\n"
  597                 "Did you mix up -f and -F?", filename);
  598             opt.filelistfile = NULL;
  599             return NULL;
  600         }
  601     }
  602     opt.conversion_timeout = tmp_conversion_timeout;
  603 
  604     errno = 0;
  605 
  606     if (!strcmp(filename, "/dev/stdin"))
  607         fp = stdin;
  608     else
  609         fp = fopen(filename, "r");
  610 
  611     if (fp == NULL) {
  612         /* return quietly, as it's okay to specify a filelist file that doesn't
  613            exist. In that case we create it on exit. */
  614         return(NULL);
  615     }
  616 
  617     for (; fgets(s, sizeof(s), fp);) {
  618         D(("Got line '%s'\n", s));
  619         s1[0] = '\0';
  620         sscanf(s, "%[^\n]", (char *) &s1);
  621         if (!(*s1) || (*s1 == '\n'))
  622             continue;
  623         D(("Got filename %s from filelist file\n", s1));
  624         /* Add it to the new list */
  625         list = gib_list_add_front(list, feh_file_new(s1));
  626     }
  627     if (strcmp(filename, "/dev/stdin"))
  628         fclose(fp);
  629 
  630     return(list);
  631 }
  632 
  633 char *feh_absolute_path(char *path)
  634 {
  635     char cwd[PATH_MAX];
  636     char fullpath[PATH_MAX];
  637     char temp[PATH_MAX];
  638     char *ret;
  639 
  640     if (!path)
  641         return(NULL);
  642     if (path[0] == '/' || path_is_url(path))
  643         return(estrdup(path));
  644     /* This path is not relative. We're gonna convert it, so that a
  645        filelist file can be saved anywhere and feh will still find the
  646        images */
  647     D(("Need to convert %s to an absolute form\n", path));
  648     /* I SHOULD be able to just use a simple realpath() here, but dumb * 
  649        old Solaris's realpath doesn't return an absolute path if the
  650        path you give it is relative. Linux and BSD get this right... */
  651     if (getcwd(cwd, sizeof(cwd)) == NULL)
  652         eprintf("Cannot determine working directory:");
  653     snprintf(temp, sizeof(temp), "%s/%s", cwd, path);
  654     if (realpath(temp, fullpath) != NULL) {
  655         ret = estrdup(fullpath);
  656     } else {
  657         ret = estrdup(temp);
  658     }
  659     D(("Converted path to %s\n", ret));
  660     return(ret);
  661 }
  662 
  663 void feh_save_filelist()
  664 {
  665     char *tmpname;
  666 
  667     tmpname = feh_unique_filename("", "filelist");
  668 
  669     if (opt.verbose)
  670         fprintf(stderr, "saving filelist to filename '%s'\n", tmpname);
  671 
  672     feh_write_filelist(filelist, tmpname);
  673     free(tmpname);
  674     return;
  675 }