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
init_parse_options(int argc,char ** argv)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
feh_check_theme_options(char ** argv)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
feh_load_options_for_theme(char * theme)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 ;) */
feh_parse_options_from_string(char * opts)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
feh_string_normalize(char * str)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
feh_getopt_theme(int argc,char ** argv)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
feh_parse_option_array(int argc,char ** argv,int finalrun)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
check_options(void)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
show_version(void)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_STRVERSCMP
947 "verscmp "
948 #endif
949
950 #ifdef HAVE_LIBXINERAMA
951 "xinerama "
952 #endif
953
954 );
955
956 exit(0);
957 }
958
show_mini_usage(void)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
show_usage(void)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 }
982