"Fossies" - the Fresh Open Source Software Archive

Member "feh-3.4.1/src/options.c" (29 May 2020, 23211 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 "options.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 /* options.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 #include <strings.h>
   28 #include "feh.h"
   29 #include "filelist.h"
   30 #include "options.h"
   31 
   32 static void check_options(void);
   33 static void feh_getopt_theme(int argc, char **argv);
   34 static void feh_parse_option_array(int argc, char **argv, int finalrun);
   35 static void feh_check_theme_options(char **argv);
   36 static void feh_parse_options_from_string(char *opts);
   37 static void feh_load_options_for_theme(char *theme);
   38 static void show_usage(void);
   39 static void show_version(void);
   40 static char *theme;
   41 
   42 fehoptions opt;
   43 
   44 void init_parse_options(int argc, char **argv)
   45 {
   46     /* TODO: sort these to match declaration of __fehoptions */
   47 
   48     /* For setting the command hint on X windows */
   49     cmdargc = argc;
   50     cmdargv = argv;
   51 
   52     /* Set default options */
   53     memset(&opt, 0, sizeof(fehoptions));
   54     opt.display = 1;
   55     opt.aspect = 1;
   56     opt.slideshow_delay = 0.0;
   57     opt.conversion_timeout = -1;
   58     opt.thumb_w = 60;
   59     opt.thumb_h = 60;
   60     opt.thumb_redraw = 10;
   61     opt.scroll_step = 20;
   62     opt.menu_font = estrdup(DEFAULT_MENU_FONT);
   63     opt.font = NULL;
   64     opt.max_height = opt.max_width = UINT_MAX;
   65 
   66     opt.start_list_at = NULL;
   67     opt.jump_on_resort = 1;
   68 
   69     opt.screen_clip = 1;
   70     opt.cache_size = 4;
   71 #ifdef HAVE_LIBXINERAMA
   72     /* if we're using xinerama, then enable it by default */
   73     opt.xinerama = 1;
   74     opt.xinerama_index = -1;
   75 #endif              /* HAVE_LIBXINERAMA */
   76 #ifdef HAVE_INOTIFY
   77     opt.auto_reload = 1;
   78 #endif              /* HAVE_INOTIFY */
   79     opt.use_conversion_cache = 1;
   80 
   81     feh_getopt_theme(argc, argv);
   82 
   83     D(("About to check for theme configuration\n"));
   84     feh_check_theme_options(argv);
   85 
   86     D(("About to parse commandline options\n"));
   87     /* Parse the cmdline args */
   88     feh_parse_option_array(argc, argv, 1);
   89 
   90     /* If we have a filelist to read, do it now */
   91     if (opt.filelistfile) {
   92         /* joining two reverse-sorted lists in this manner works nicely for us
   93            here, as files specified on the commandline end up at the *end* of
   94            the combined filelist, in the specified order. */
   95         D(("About to load filelist from file\n"));
   96         filelist = gib_list_cat(filelist, feh_read_filelist(opt.filelistfile));
   97     }
   98 
   99     D(("Options parsed\n"));
  100 
  101     filelist_len = gib_list_length(filelist);
  102     if (!filelist_len)
  103         show_mini_usage();
  104 
  105     check_options();
  106 
  107     feh_prepare_filelist();
  108     return;
  109 }
  110 
  111 static void feh_check_theme_options(char **argv)
  112 {
  113     if (!theme) {
  114         /* This prevents screw up when running src/feh or ./feh */
  115         char *pos = strrchr(argv[0], '/');
  116 
  117         if (pos)
  118             theme = estrdup(pos + 1);
  119         else
  120             theme = estrdup(argv[0]);
  121     }
  122     D(("Theme name is %s\n", theme));
  123 
  124     feh_load_options_for_theme(theme);
  125 
  126     free(theme);
  127     return;
  128 }
  129 
  130 static void feh_load_options_for_theme(char *theme)
  131 {
  132     FILE *fp = NULL;
  133     char *home = getenv("HOME");
  134     char *rcpath = NULL;
  135     char *oldrcpath = NULL;
  136     char *confbase = getenv("XDG_CONFIG_HOME");
  137     // s, s1 and s2 must always have identical size
  138     char s[1024], s1[1024], s2[1024];
  139     int cont = 0;
  140     int bspos;
  141 
  142     if (confbase)
  143         rcpath = estrjoin("/", confbase, "feh/themes", NULL);
  144     else if (home)
  145         rcpath = estrjoin("/", home, ".config/feh/themes", NULL);
  146     else {
  147         weprintf("You have no HOME, cannot read configuration");
  148         return;
  149     }
  150 
  151     oldrcpath = estrjoin("/", home, ".fehrc", NULL);
  152 
  153     fp = fopen(rcpath, "r");
  154 
  155     free(rcpath);
  156 
  157     if (!fp && ((fp = fopen(oldrcpath, "r")) != NULL))
  158         weprintf("The theme config file was moved from ~/.fehrc to "
  159             "~/.config/feh/themes. Run\n"
  160             "    mkdir -p ~/.config/feh; mv ~/.fehrc ~/.config/feh/themes\n"
  161             "to fix this.");
  162 
  163     free(oldrcpath);
  164 
  165     if (!fp && ((fp = fopen("/etc/feh/themes", "r")) == NULL))
  166         return;
  167 
  168     /* Oooh. We have an options file :) */
  169     for (; fgets(s, sizeof(s), fp);) {
  170         s1[0] = '\0';
  171         s2[0] = '\0';
  172 
  173         if (cont) {
  174             /*
  175              * fgets ensures that s contains no more than 1023 characters
  176              * (+ 1 null byte)
  177              */
  178             sscanf(s, " %[^\n]\n", (char *) &s2);
  179             if (!*s2)
  180                 break;
  181             D(("Got continued options %s\n", s2));
  182         } else {
  183             /*
  184              * fgets ensures that s contains no more than 1023 characters
  185              * (+ 1 null byte)
  186              */
  187             sscanf(s, "%s %[^\n]\n", (char *) &s1, (char *) &s2);
  188             if (!(*s1) || (!*s2) || (*s1 == '\n') || (*s1 == '#')) {
  189                 cont = 0;
  190                 continue;
  191             }
  192             D(("Got theme/options pair %s/%s\n", s1, s2));
  193         }
  194 
  195         if (!strcmp(s1, theme) || cont) {
  196 
  197             bspos = strlen(s2)-1;
  198 
  199             if (s2[bspos] == '\\') {
  200                 D(("Continued line\n"));
  201                 s2[bspos] = '\0';
  202                 cont = 1;
  203                 /* A trailing whitespace confuses the option parser */
  204                 if (bspos && (s2[bspos-1] == ' '))
  205                     s2[bspos-1] = '\0';
  206             } else
  207                 cont = 0;
  208 
  209             D(("A match. Using options %s\n", s2));
  210             feh_parse_options_from_string(s2);
  211 
  212             if (!cont)
  213                 break;
  214         }
  215     }
  216     fclose(fp);
  217     return;
  218 }
  219 
  220 /* FIXME This function is a crufty bitch ;) */
  221 static void feh_parse_options_from_string(char *opts)
  222 {
  223     char *list[sizeof(char *) * 64];
  224     int num = 0;
  225     char *s;
  226     char *t;
  227     char last = 0;
  228     char inquote = 0;
  229     int i = 0;
  230 
  231     /* So we don't reinvent the wheel (not again, anyway), we use the
  232        getopt_long function to do this parsing as well. This means it has to
  233        look like the real argv ;) */
  234 
  235     list[num++] = estrdup(PACKAGE);
  236 
  237     for (s = opts, t = opts;; t++) {
  238 
  239         if (num > 64)
  240             eprintf(PACKAGE " does not support more than 64 words per "
  241                     "theme definition.\n Please shorten your lines.");
  242 
  243         if ((*t == ' ') && !inquote) {
  244             *t = '\0';
  245             num++;
  246 
  247             list[num - 1] = feh_string_normalize(s);
  248             s = t + 1;
  249         } else if (*t == '\0') {
  250             num++;
  251 
  252             list[num - 1] = feh_string_normalize(s);
  253             break;
  254         } else if ((*t == inquote) && (last != '\\')) {
  255             inquote = 0;
  256         } else if (((*t == '\"') || (*t == '\'')) && (last != '\\') && !inquote)
  257             inquote = *t;
  258         last = *t;
  259     }
  260 
  261     feh_parse_option_array(num, list, 0);
  262 
  263     for (i = 0; i < num; i++)
  264         if (list[i])
  265             free(list[i]);
  266     return;
  267 }
  268 
  269 char *feh_string_normalize(char *str)
  270 {
  271     char ret[4096];
  272     char *s;
  273     int i = 0;
  274     char last = 0;
  275 
  276     D(("normalizing %s\n", str));
  277     ret[0] = '\0';
  278 
  279     for (s = str;; s++) {
  280         if (*s == '\0')
  281             break;
  282         else if ((*s == '\"') && (last == '\\'))
  283             ret[i++] = '\"';
  284         else if ((*s == '\"') && (last == 0));
  285         else if ((*s == '\'') && (last == '\\'))
  286             ret[i++] = '\'';
  287         else if ((*s == '\'') && (last == 0));
  288         else if ((*s == ' ') && (last == '\\'))
  289             ret[i++] = ' ';
  290         else
  291             ret[i++] = *s;
  292 
  293         last = *s;
  294     }
  295     if (i && ((ret[i - 1] == '\"') || (ret[i - 1] == '\'')))
  296         ret[i - 1] = '\0';
  297     else
  298         ret[i] = '\0';
  299     D(("normalized to %s\n", ret));
  300 
  301     return(estrdup(ret));
  302 }
  303 
  304 static void feh_getopt_theme(int argc, char **argv)
  305 {
  306     static char stropts[] = "-T:";
  307     static struct option lopts[] = {
  308         {"theme", 1, 0, 'T'},
  309         {0, 0, 0, 0}
  310     };
  311     int optch = 0, cmdx = 0;
  312 
  313     opterr = 0;
  314 
  315     while ((optch = getopt_long(argc, argv, stropts, lopts, &cmdx)) != EOF) {
  316         if (optch == 'T')
  317             theme = estrdup(optarg);
  318     }
  319 
  320     opterr = 1;
  321     optind = 0;
  322 }
  323 
  324 static void feh_parse_option_array(int argc, char **argv, int finalrun)
  325 {
  326     int discard;
  327     static char stropts[] =
  328         "a:A:b:B:C:dD:e:E:f:Fg:GhH:iIj:J:kK:lL:mM:nNo:O:pPqrR:sS:tT:uUvVwW:xXy:YzZ"
  329         ".@:^:~:|:+:<:>:";
  330 
  331     /* (*name, has_arg, *flag, val) See: struct option in getopts.h */
  332     static struct option lopts[] = {
  333         {"debug"         , 0, 0, '+'},
  334         {"scale-down"    , 0, 0, '.'},
  335         {"max-dimension" , 1, 0, '<'},
  336         {"min-dimension" , 1, 0, '>'},
  337         {"title-font"    , 1, 0, '@'},
  338         {"action"        , 1, 0, 'A'},
  339         {"image-bg"      , 1, 0, 'B'},
  340         {"fontpath"      , 1, 0, 'C'},
  341         {"slideshow-delay",1, 0, 'D'},
  342         {"thumb-height"  , 1, 0, 'E'},
  343         {"full-screen"   , 0, 0, 'F'}, /* deprecated */
  344         {"fullscreen"    , 0, 0, 'F'},
  345         {"draw-actions"  , 0, 0, 'G'},
  346         {"limit-height"  , 1, 0, 'H'},
  347         {"fullindex"     , 0, 0, 'I'},
  348         {"thumb-redraw"  , 1, 0, 'J'},
  349         {"caption-path"  , 1, 0, 'K'},
  350         {"customlist"    , 1, 0, 'L'},
  351         {"menu-font"     , 1, 0, 'M'},
  352         {"no-menus"      , 0, 0, 'N'},
  353         {"output-only"   , 1, 0, 'O'},
  354         {"cache-thumbnails", 0, 0, 'P'},
  355         {"reload"        , 1, 0, 'R'},
  356         {"sort"          , 1, 0, 'S'},
  357         {"theme"         , 1, 0, 'T'},
  358         {"loadable"      , 0, 0, 'U'},
  359         {"verbose"       , 0, 0, 'V'},
  360         {"limit-width"   , 1, 0, 'W'},
  361         {"ignore-aspect" , 0, 0, 'X'},
  362         {"hide-pointer"  , 0, 0, 'Y'},
  363         {"auto-zoom"     , 0, 0, 'Z'},
  364         {"title"         , 1, 0, '^'},
  365         {"alpha"         , 1, 0, 'a'},
  366         {"bg"            , 1, 0, 'b'},
  367         {"draw-filename" , 0, 0, 'd'},
  368         {"font"          , 1, 0, 'e'},
  369         {"filelist"      , 1, 0, 'f'},
  370         {"geometry"      , 1, 0, 'g'},
  371         {"help"          , 0, 0, 'h'},
  372         {"index"         , 0, 0, 'i'},
  373         {"output-dir"    , 1, 0, 'j'},
  374         {"keep-http"     , 0, 0, 'k'},
  375         {"list"          , 0, 0, 'l'},
  376         {"montage"       , 0, 0, 'm'},
  377         {"reverse"       , 0, 0, 'n'},
  378         {"output"        , 1, 0, 'o'},
  379         {"preload"       , 0, 0, 'p'},
  380         {"quiet"         , 0, 0, 'q'},
  381         {"recursive"     , 0, 0, 'r'},
  382         {"stretch"       , 0, 0, 's'},
  383         {"thumbnails"    , 0, 0, 't'},
  384         {"unloadable"    , 0, 0, 'u'},
  385         {"version"       , 0, 0, 'v'},
  386         {"multiwindow"   , 0, 0, 'w'},
  387         {"borderless"    , 0, 0, 'x'},
  388         {"thumb-width"   , 1, 0, 'y'},
  389         {"randomize"     , 0, 0, 'z'},
  390         {"start-at"      , 1, 0, '|'},
  391         {"thumb-title"   , 1, 0, '~'},
  392         {"bg-tile"       , 0, 0, 200},
  393         {"bg-center"     , 0, 0, 201},
  394         {"bg-scale"      , 0, 0, 202},
  395         {"zoom"          , 1, 0, 205},
  396         {"no-screen-clip", 0, 0, 206},
  397         {"index-info"    , 1, 0, 207},
  398         {"magick-timeout", 1, 0, 208},
  399         {"action1"       , 1, 0, 209},
  400         {"action2"       , 1, 0, 210},
  401         {"action3"       , 1, 0, 211},
  402         {"action4"       , 1, 0, 212},
  403         {"action5"       , 1, 0, 213},
  404         {"action6"       , 1, 0, 214},
  405         {"action7"       , 1, 0, 215},
  406         {"action8"       , 1, 0, 216},
  407         {"action9"       , 1, 0, 217},
  408         {"bg-fill"       , 0, 0, 218},
  409         {"bg-max"        , 0, 0, 219},
  410         {"no-jump-on-resort", 0, 0, 220},
  411         {"edit"          , 0, 0, 221},
  412 #ifdef HAVE_LIBEXIF
  413         {"draw-exif"     , 0, 0, 223},
  414         {"auto-rotate"   , 0, 0, 242},
  415 #endif
  416         {"no-xinerama"   , 0, 0, 225},
  417         {"draw-tinted"   , 0, 0, 229},
  418         {"info"          , 1, 0, 234},
  419         {"force-aliasing", 0, 0, 235},
  420         {"no-fehbg"      , 0, 0, 236},
  421         {"keep-zoom-vp"  , 0, 0, 237},
  422         {"scroll-step"   , 1, 0, 238},
  423         {"xinerama-index", 1, 0, 239},
  424         {"insecure"      , 0, 0, 240},
  425         {"no-recursive"  , 0, 0, 241},
  426         {"cache-size"    , 1, 0, 243},
  427         {"on-last-slide" , 1, 0, 244},
  428         {"conversion-timeout" , 1, 0, 245},
  429         {"version-sort"  , 0, 0, 246},
  430         {"offset"        , 1, 0, 247},
  431 #ifdef HAVE_INOTIFY
  432         {"auto-reload"   , 0, 0, 248},
  433 #endif
  434         {"class"         , 1, 0, 249},
  435         {"no-conversion-cache", 0, 0, 250},
  436         {0, 0, 0, 0}
  437     };
  438     int optch = 0, cmdx = 0;
  439 
  440     while ((optch = getopt_long(argc, argv, stropts, lopts, &cmdx)) != EOF) {
  441         D(("Got option, getopt calls it %d, or %c\n", optch, optch));
  442         switch (optch) {
  443         case 0:
  444             break;
  445         case '+':
  446             opt.debug = 1;
  447             break;
  448         case '<':
  449             opt.filter_by_dimensions = 1;
  450             XParseGeometry(optarg, &discard, &discard, &opt.max_width, &opt.max_height);
  451             if (opt.max_width == 0)
  452                 opt.max_width = UINT_MAX;
  453             if (opt.max_height == 0)
  454                 opt.max_height = UINT_MAX;
  455             break;
  456         case '>':
  457             opt.filter_by_dimensions = 1;
  458             XParseGeometry(optarg, &discard, &discard, &opt.min_width, &opt.min_height);
  459             break;
  460         case '.':
  461             opt.scale_down = 1;
  462             break;
  463         case '@':
  464             opt.title_font = estrdup(optarg);
  465             break;
  466         case 'A':
  467             opt.actions[0] = estrdup(optarg);
  468             break;
  469         case 'B':
  470             opt.image_bg = estrdup(optarg);
  471             break;
  472         case 'C':
  473             D(("adding fontpath %s\n", optarg));
  474             imlib_add_path_to_font_path(optarg);
  475             break;
  476         case 'D':
  477             opt.slideshow_delay = atof(optarg);
  478             if (opt.slideshow_delay < 0.0) {
  479                 opt.slideshow_delay *= (-1);
  480                 opt.paused = 1;
  481             } else {
  482                 opt.paused = 0;
  483             }
  484             break;
  485         case 'E':
  486             opt.thumb_h = atoi(optarg);
  487             break;
  488         case 'F':
  489             opt.full_screen = 1;
  490             break;
  491         case 'G':
  492             opt.draw_actions = 1;
  493             break;
  494         case 'H':
  495             opt.limit_h = atoi(optarg);
  496             break;
  497         case 'I':
  498             opt.index = 1;
  499             opt.index_info = estrdup("%n\n%S\n%wx%h");
  500             break;
  501         case 'J':
  502             opt.thumb_redraw = atoi(optarg);
  503             break;
  504         case 'K':
  505             opt.caption_path = estrdup(optarg);
  506             break;
  507         case 'L':
  508             opt.customlist = estrdup(optarg);
  509             opt.display = 0;
  510             break;
  511         case 'M':
  512             free(opt.menu_font);
  513             opt.menu_font = estrdup(optarg);
  514             break;
  515         case 'N':
  516             opt.no_menus = 1;
  517             break;
  518         case 'O':
  519             opt.output = 1;
  520             opt.output_file = estrdup(optarg);
  521             opt.display = 0;
  522             break;
  523         case 'P':
  524             opt.cache_thumbnails = 1;
  525             break;
  526         case 'R':
  527             opt.reload = atof(optarg);
  528             opt.use_conversion_cache = 0;
  529 #ifdef HAVE_INOTIFY
  530             opt.auto_reload = 0;
  531 #endif
  532             break;
  533         case 'S':
  534             if (!strcasecmp(optarg, "name"))
  535                 opt.sort = SORT_NAME;
  536             else if (!strcasecmp(optarg, "filename"))
  537                 opt.sort = SORT_FILENAME;
  538             else if (!strcasecmp(optarg, "dirname"))
  539                 opt.sort = SORT_DIRNAME;
  540             else if (!strcasecmp(optarg, "mtime"))
  541                 opt.sort = SORT_MTIME;
  542             else if (!strcasecmp(optarg, "width"))
  543                 opt.sort = SORT_WIDTH;
  544             else if (!strcasecmp(optarg, "height"))
  545                 opt.sort = SORT_HEIGHT;
  546             else if (!strcasecmp(optarg, "pixels"))
  547                 opt.sort = SORT_PIXELS;
  548             else if (!strcasecmp(optarg, "size"))
  549                 opt.sort = SORT_SIZE;
  550             else if (!strcasecmp(optarg, "format"))
  551                 opt.sort = SORT_FORMAT;
  552             else {
  553                 weprintf("Unrecognised sort mode \"%s\". Defaulting to "
  554                         "sort by filename", optarg);
  555                 opt.sort = SORT_FILENAME;
  556             }
  557             if (opt.randomize) {
  558                 weprintf("commandline contains --randomize and --sort. "
  559                         "--randomize has been unset");
  560                 opt.randomize = 0;
  561             }
  562             break;
  563         case 'T':
  564             theme = estrdup(optarg);
  565             break;
  566         case 'U':
  567             opt.loadables = 1;
  568             opt.display = 0;
  569             break;
  570         case 'V':
  571             opt.verbose = 1;
  572             break;
  573         case 'W':
  574             opt.limit_w = atoi(optarg);
  575             break;
  576         case 'X':
  577             opt.aspect = 0;
  578             break;
  579         case 'Y':
  580             opt.hide_pointer = 1;
  581             break;
  582         case 'Z':
  583             opt.zoom_mode = ZOOM_MODE_MAX;
  584             break;
  585         case '^':
  586             opt.title = estrdup(optarg);
  587             break;
  588         case 'a':
  589             opt.alpha = 1;
  590             opt.alpha_level = 255 - atoi(optarg);
  591             break;
  592         case 'b':
  593             opt.bg = 1;
  594             opt.bg_file = estrdup(optarg);
  595             break;
  596         case 'd':
  597             opt.draw_filename = 1;
  598             break;
  599         case 'e':
  600             opt.font = estrdup(optarg);
  601             break;
  602         case 'f':
  603             if (!strcmp(optarg, "-"))
  604                 opt.filelistfile = estrdup("/dev/stdin");
  605             else
  606                 opt.filelistfile = estrdup(optarg);
  607             break;
  608         case 'g':
  609             opt.geom_enabled = 1;
  610             opt.geom_flags = XParseGeometry(optarg, &opt.geom_x,
  611                     &opt.geom_y, &opt.geom_w, &opt.geom_h);
  612             break;
  613         case 'h':
  614             show_usage();
  615             break;
  616         case 'i':
  617             opt.index = 1;
  618             opt.index_info = estrdup("%n");
  619             break;
  620         case 'j':
  621             opt.output_dir = estrdup(optarg);
  622             break;
  623         case 'k':
  624             opt.keep_http = 1;
  625             break;
  626         case 'l':
  627             opt.list = 1;
  628             opt.display = 0;
  629             break;
  630         case 'm':
  631             opt.index = 1;
  632             break;
  633         case 'n':
  634             opt.reverse = 1;
  635             break;
  636         case 'o':
  637             opt.output = 1;
  638             opt.output_file = estrdup(optarg);
  639             break;
  640         case 'p':
  641             opt.preload = 1;
  642             break;
  643         case 'q':
  644             opt.quiet = 1;
  645             break;
  646         case 'r':
  647             opt.recursive = 1;
  648             break;
  649         case 's':
  650             opt.stretch = 1;
  651             break;
  652         case 't':
  653             opt.thumbs = 1;
  654             opt.index_info = estrdup("%n");
  655             break;
  656         case 'u':
  657             opt.unloadables = 1;
  658             opt.display = 0;
  659             break;
  660         case 'v':
  661             show_version();
  662             break;
  663         case 'w':
  664             opt.multiwindow = 1;
  665             break;
  666         case 'x':
  667             opt.borderless = 1;
  668             break;
  669         case 'y':
  670             opt.thumb_w = atoi(optarg);
  671             break;
  672         case 'z':
  673             opt.randomize = 1;
  674             if (opt.sort != SORT_NONE) {
  675                 weprintf("commandline contains --sort and --randomize. "
  676                         "--sort has been unset");
  677                 opt.sort = SORT_NONE;
  678             }
  679             break;
  680         case '|':
  681             opt.start_list_at = estrdup(optarg);
  682             break;
  683         case '~':
  684             opt.thumb_title = estrdup(optarg);
  685             break;
  686         case 200:
  687             opt.bgmode = BG_MODE_TILE;
  688             break;
  689         case 201:
  690             opt.bgmode = BG_MODE_CENTER;
  691             break;
  692         case 202:
  693             opt.bgmode = BG_MODE_SCALE;
  694             break;
  695         case 205:
  696             if (!strcmp("fill", optarg))
  697                 opt.zoom_mode = ZOOM_MODE_FILL;
  698             else if (!strcmp("max", optarg))
  699                 opt.zoom_mode = ZOOM_MODE_MAX;
  700             else
  701                 opt.default_zoom = atoi(optarg);
  702             break;
  703         case 206:
  704             opt.screen_clip = 0;
  705             break;
  706         case 207:
  707             opt.index_info = estrdup(optarg);
  708             break;
  709         case 208:
  710             weprintf("--magick-timeout is deprecated, please use --conversion-timeout instead");
  711             opt.conversion_timeout = atoi(optarg);
  712             break;
  713         case 209:
  714             opt.actions[1] = estrdup(optarg);
  715             break;
  716         case 210:
  717             opt.actions[2] = estrdup(optarg);
  718             break;
  719         case 211:
  720             opt.actions[3] = estrdup(optarg);
  721             break;
  722         case 212:
  723             opt.actions[4] = estrdup(optarg);
  724             break;
  725         case 213:
  726             opt.actions[5] = estrdup(optarg);
  727             break;
  728         case 214:
  729             opt.actions[6] = estrdup(optarg);
  730             break;
  731         case 215:
  732             opt.actions[7] = estrdup(optarg);
  733             break;
  734         case 216:
  735             opt.actions[8] = estrdup(optarg);
  736             break;
  737         case 217:
  738             opt.actions[9] = estrdup(optarg);
  739             break;
  740         case 218:
  741             opt.bgmode = BG_MODE_FILL;
  742             break;
  743         case 219:
  744             opt.bgmode = BG_MODE_MAX;
  745             break;
  746         case 220:
  747             opt.jump_on_resort = 0;
  748             break;
  749         case 221:
  750             opt.edit = 1;
  751             break;
  752 #ifdef HAVE_LIBEXIF
  753         case 223:
  754             opt.draw_exif = 1;
  755             break;
  756         case 242:
  757             opt.auto_rotate = 1;
  758             break;
  759 #endif
  760         case 225:
  761             opt.xinerama = 0;
  762             break;
  763         case 229:
  764             opt.text_bg = TEXT_BG_TINTED;
  765             break;
  766         case 234:
  767             opt.info_cmd = estrdup(optarg);
  768             if (opt.info_cmd[0] == ';') {
  769                 opt.draw_info = 0;
  770                 opt.info_cmd++;
  771             } else {
  772                 opt.draw_info = 1;
  773             }
  774             break;
  775         case 235:
  776             opt.force_aliasing = 1;
  777             break;
  778         case 236:
  779             opt.no_fehbg = 1;
  780             break;
  781         case 237:
  782             opt.keep_zoom_vp = 1;
  783             break;
  784         case 238:
  785             opt.scroll_step = atoi(optarg);
  786             break;
  787         case 239:
  788             opt.xinerama_index = atoi(optarg);
  789             break;
  790         case 240:
  791             opt.insecure_ssl = 1;
  792             break;
  793         case 241:
  794             opt.recursive = 0;
  795             break;
  796         case 243:
  797             opt.cache_size = atoi(optarg);
  798             if (opt.cache_size < 0)
  799                 opt.cache_size = 0;
  800             if (opt.cache_size > 2048)
  801                 opt.cache_size = 2048;
  802             break;
  803         case 244:
  804             if (!strcmp(optarg, "quit")) {
  805                 opt.on_last_slide = ON_LAST_SLIDE_QUIT;
  806             } else if (!strcmp(optarg, "hold")) {
  807                 opt.on_last_slide = ON_LAST_SLIDE_HOLD;
  808             } else if (!strcmp(optarg, "resume")) {
  809                 opt.on_last_slide = ON_LAST_SLIDE_RESUME;
  810             } else {
  811                 weprintf("Unrecognized on-last-slide action \"%s\"."
  812                         "Supported actions: hold, resume, quit\n", optarg);
  813             }
  814             break;
  815         case 245:
  816             opt.conversion_timeout = atoi(optarg);
  817             break;
  818         case 246:
  819             opt.version_sort = 1;
  820             break;
  821         case 247:
  822             opt.offset_flags = XParseGeometry(optarg, &opt.offset_x,
  823                     &opt.offset_y, (unsigned int *)&discard, (unsigned int *)&discard);
  824             break;
  825 #ifdef HAVE_INOTIFY
  826         case 248:
  827             opt.auto_reload = 1;
  828             break;
  829 #endif
  830         case 249:
  831             opt.x11_class = estrdup(optarg);
  832             break;
  833         case 250:
  834             opt.use_conversion_cache = 0;
  835             break;
  836         default:
  837             break;
  838         }
  839     }
  840 
  841     /* Now the leftovers, which must be files */
  842     if (optind < argc) {
  843         while (optind < argc) {
  844             if (opt.reload)
  845                 original_file_items = gib_list_add_front(original_file_items, estrdup(argv[optind]));
  846             /* If recursive is NOT set, but the only argument is a directory
  847                name, we grab all the files in there, but not subdirs */
  848             add_file_to_filelist_recursively(argv[optind++], FILELIST_FIRST);
  849         }
  850     }
  851     else if (finalrun && !opt.filelistfile && !opt.bgmode) {
  852         /*
  853          * if --start-at is a non-local URL (i.e., does not start with file:///),
  854          * behave as if "feh URL" was called (there is no directory we can load)
  855          */
  856         if (opt.start_list_at && path_is_url(opt.start_list_at) && (strlen(opt.start_list_at) <= 8 || strncmp(opt.start_list_at, "file:///", 8) != 0)) {
  857             add_file_to_filelist_recursively(opt.start_list_at, FILELIST_FIRST);
  858         } else if (opt.start_list_at && strrchr(opt.start_list_at, '/')) {
  859             if (strlen(opt.start_list_at) > 8 && strncmp(opt.start_list_at, "file:///", 8) == 0) {
  860                 char *start_at_path = estrdup(opt.start_list_at + 7);
  861                 free(opt.start_list_at);
  862                 opt.start_list_at = start_at_path;
  863             }
  864             char *target_directory = estrdup(opt.start_list_at);
  865             char *filename_start = strrchr(target_directory, '/');
  866             if (filename_start) {
  867                 *filename_start = '\0';
  868             }
  869             add_file_to_filelist_recursively(target_directory, FILELIST_FIRST);
  870             free(target_directory);
  871         } else {
  872             add_file_to_filelist_recursively(".", FILELIST_FIRST);
  873         }
  874     }
  875 
  876     /* So that we can safely be called again */
  877     optind = 0;
  878     return;
  879 }
  880 
  881 static void check_options(void)
  882 {
  883     int i;
  884     char *endptr;
  885 
  886     for (i = 0; i < 10; i++) {
  887         if (opt.actions[i] && !opt.hold_actions[i] && (opt.actions[i][0] == ';')) {
  888             opt.hold_actions[i] = 1;
  889             opt.actions[i] = opt.actions[i] + 1;
  890         }
  891         opt.action_titles[i] = opt.actions[i];
  892         if (opt.actions[i] && (opt.actions[i][0] == '[')) {
  893             if (((endptr = strchr(opt.actions[i], ']')) != NULL)
  894                     && (opt.actions[i][1] != ' ')) {
  895                 opt.action_titles[i] = opt.actions[i] + 1;
  896                 opt.actions[i] = endptr + 1;
  897                 *endptr = 0;
  898             }
  899         }
  900     }
  901 
  902     if (opt.full_screen && opt.multiwindow) {
  903         eprintf("You cannot combine --fullscreen with --multiwindow");
  904     }
  905 
  906     if (opt.list && (opt.multiwindow || opt.index)) {
  907         eprintf("You cannot combine --list with other modes");
  908     }
  909 
  910     if (opt.loadables && opt.unloadables) {
  911         eprintf("You cannot combine --loadable with --unloadable");
  912     }
  913 
  914     return;
  915 }
  916 
  917 static void show_version(void)
  918 {
  919     puts(PACKAGE " version " VERSION);
  920     puts("Compile-time switches: "
  921 
  922 #ifdef HAVE_LIBCURL
  923         "curl "
  924 #endif
  925 
  926 #ifdef DEBUG
  927         "debug "
  928 #endif
  929 
  930 #ifdef HAVE_LIBEXIF
  931         "exif "
  932 #endif
  933 
  934 #ifdef HAVE_INOTIFY
  935         "inotify "
  936 #endif
  937 
  938 #ifdef INCLUDE_HELP
  939         "help "
  940 #endif
  941 
  942 #if _FILE_OFFSET_BITS == 64
  943         "stat64 "
  944 #endif
  945 
  946 #ifdef HAVE_VERSCMP
  947         "verscmp "
  948 #endif
  949 
  950 #ifdef HAVE_LIBXINERAMA
  951         "xinerama "
  952 #endif
  953 
  954     );
  955 
  956     exit(0);
  957 }
  958 
  959 void show_mini_usage(void)
  960 {
  961     fputs(PACKAGE ": No loadable images specified.\n"
  962 #ifdef INCLUDE_HELP
  963         "See '" PACKAGE " --help' or 'man " PACKAGE "' for detailed usage information\n",
  964 #else
  965         "See 'man " PACKAGE "' for detailed usage information\n",
  966 #endif
  967         stderr);
  968     exit(1);
  969 }
  970 
  971 static void show_usage(void)
  972 {
  973     fputs(
  974 #ifdef INCLUDE_HELP
  975 #include "help.inc"
  976 #else
  977     "See 'man " PACKAGE "'\n"
  978 #endif
  979     , stdout);
  980     exit(0);
  981 }