Quick Image Viewer (qiv) http://qiv.spiegl.de/ http://qiv.spiegl.de/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

431 lines
14 KiB

/*
Module : options.c
Purpose : Read and evaluate commandline options
More : see qiv README
Homepage : http://qiv.spiegl.de/
Original : http://www.klografx.net/qiv/
*/
#include "qiv.h"
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdio.h>
#include <libgen.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#endif
#include "xmalloc.h"
extern char *optarg;
extern int optind, opterr, optopt;
/* put longopt-only options to non ascii values */
#define LONGOPT_VIKEYS 256
#define LONGOPT_TRASHBIN 257
static char *short_options = "ab:c:Cd:efg:hilLmno:pq:rstuvw:xyzA:BDF:GIJKMNPRSTW:X:Y:Z:";
static struct option long_options[] =
{
{"do_grab", 0, NULL, 'a'},
{"brightness", 1, NULL, 'b'},
{"contrast", 1, NULL, 'c'},
{"delay", 1, NULL, 'd'},
{"center", 0, NULL, 'e'},
{"fullscreen", 0, NULL, 'f'},
{"gamma", 1, NULL, 'g'},
{"help", 0, NULL, 'h'},
{"no_statusbar", 0, NULL, 'i'},
#if GDK_PIXBUF_MINOR >= 12
{"autorotate", 0, NULL, 'l'},
#endif
{"maxpect", 0, NULL, 'm'},
{"no_filter", 0, NULL, 'n'},
{"bg_color", 1, NULL, 'o'},
{"transparency", 0, NULL, 'p'},
{"rotate", 1, NULL, 'q'},
{"random", 0, NULL, 'r'},
{"slide", 0, NULL, 's'},
{"scale_down", 0, NULL, 't'},
{"recursivedir", 0, NULL, 'u'},
{"followlinks", 0, NULL, 'L'},
{"version", 0, NULL, 'v'},
{"fixed_width", 1, NULL, 'w'},
{"root", 0, NULL, 'x'},
{"root_t", 0, NULL, 'y'},
{"root_s", 0, NULL, 'z'},
{"select_dir", 1, NULL, 'A'},
{"browse", 0, NULL, 'B'},
{"cycle", 0, NULL, 'C'},
{"no_sort", 0, NULL, 'D'},
{"file", 1, NULL, 'F'},
{"disable_grab", 0, NULL, 'G'},
{"statusbar", 0, NULL, 'I'},
{"showJPEGcomments", 0, NULL, 'J'},
{"mtime_sort", 0, NULL, 'K'},
{"merged_case_sort", 0, NULL, 'M'},
{"numeric_sort", 0, NULL, 'N'},
{"ignore_path_sort", 0, NULL, 'P'},
{"readonly", 0, NULL, 'R'},
{"shuffle", 0, NULL, 'S'},
{"watch", 0, NULL, 'T'},
{"fixed_zoom", 1, NULL, 'W'},
{"xineramascreen", 1, NULL, 'X'},
#ifdef SUPPORT_LCMS
{"source_profile", 1, NULL, 'Y'},
{"display_profile", 1, NULL, 'Z'},
#endif
{"trashbin", 0, NULL, LONGOPT_TRASHBIN},
{"vikeys", 0, NULL, LONGOPT_VIKEYS},
{0, 0, NULL, 0}
};
static int mtime_sort = 0, numeric_sort = 0, merged_case_sort = 0, ignore_path_sort = 0;
/* This array makes it easy to sort filenames into merged-case order
* (e.g. AaBbCcDdEeFf...). */
static unsigned char casemap[256] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
0x40,0x41,0x43,0x45,0x47,0x49,0x4B,0x4D, /* @ABCDEFG */
0x4F,0x51,0x53,0x55,0x57,0x59,0x5B,0x5D, /* HIJKLMNO */
0x5F,0x61,0x63,0x65,0x67,0x69,0x6B,0x6D, /* PQRSTUVW */
0x6F,0x71,0x73,0x75,0x76,0x77,0x78,0x79, /* XYZ[\]^_ */
0x7A,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E, /* `abcdefg */
0x50,0x52,0x54,0x56,0x58,0x5A,0x5C,0x5E, /* hijklmno */
0x60,0x62,0x64,0x66,0x68,0x6A,0x6C,0x6E, /* pqrstuvw */
0x70,0x72,0x74,0x7B,0x7C,0x7D,0x7E,0x7F, /* xyz{|}~ */
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};
static time_t get_mtime(unsigned char *fn) {
struct stat attrib;
if(stat((char *) fn, &attrib) == 0)
return attrib.st_mtime;
return 0;
}
static int my_strcmp(const void *v1, const void *v2)
{
unsigned char *cp1 = *(unsigned char **)v1;
unsigned char *cp2 = *(unsigned char **)v2;
unsigned char *sufptr1, *sufptr2;
int tmp;
sufptr1 = cp1 + strlen((char *)cp1);
while (--sufptr1 > cp1 && *sufptr1 != '.') {}
sufptr2 = cp2 + strlen((char *)cp2);
while (--sufptr2 > cp2 && *sufptr2 != '.') {}
if(mtime_sort) {
time_t diff = get_mtime(cp1) - get_mtime(cp2);
if(diff < 0)
return -1;
if(diff > 0)
return 1;
// fall through in case of same time stamp
}
if (ignore_path_sort) {
unsigned char *slash;
if ((slash = (unsigned char *)strrchr((char *)cp1, '/')) != NULL)
cp1 = slash + 1;
if ((slash = (unsigned char *)strrchr((char *)cp2, '/')) != NULL)
cp2 = slash + 1;
}
if (numeric_sort) {
int namelen = 0, diff = 0;
do {
if (sufptr1 && (isdigit(*cp1) || isdigit(*cp2))) {
unsigned char *ep1, *ep2;
if (diff)
return diff;
for (ep1 = cp1; isdigit(*ep1); ep1++) {}
if (ep1 == cp1)
return 1;
for (ep2 = cp2; isdigit(*ep2); ep2++) {}
if (cp2 == ep2)
return -1;
if ((diff = (ep1 - cp1) - (ep2 - cp2)) == 0) {
long val = atol((char *)cp1) - atol((char *)cp2);
diff = val < 0? -1 : val > 0? 1 : 0;
}
if (diff && sufptr1 - cp1 <= namelen &&
sufptr2 - cp2 <= namelen)
return diff;
namelen += ep1 - cp1;
cp1 = ep1;
cp2 = ep2 - 1;
}
else {
if (cp1 == sufptr1) {
if (cp2 != sufptr2)
return -1;
sufptr1 = sufptr2 = NULL;
}
else if (cp2 == sufptr2)
return 1;
if (merged_case_sort)
tmp = casemap[*cp1++] - casemap[*cp2];
else
tmp = *cp1++ - *cp2;
if (tmp != 0)
return tmp;
if (*cp2 == '/')
namelen = 0;
else
namelen++;
}
} while (*cp2++ != '\0');
return diff;
}
do {
if (cp1 == sufptr1) {
if (cp2 != sufptr2)
return -1;
}
else if (cp2 == sufptr2)
return 1;
if (merged_case_sort)
tmp = casemap[*cp1++] - casemap[*cp2];
else
tmp = *cp1++ - *cp2;
if (tmp != 0)
return tmp;
} while (*cp2++ != '\0');
return 0;
}
void options_read(int argc, char **argv, qiv_image *q)
{
int long_index, shuffle = 0, need_sort = 1;
int c, cnt;
int force_statusbar=-1; /* default is don't force */
struct stat sb;
while ((c = getopt_long(argc, argv, short_options,
long_options, &long_index)) != -1) {
switch(c) {
case 'a': do_grab=1;
break;
case 'b': q->mod.brightness = (checked_atoi(optarg)+32)*8;
if ((q->mod.brightness<0) || (q->mod.brightness>512))
usage(argv[0],1);
break;
case 'c': q->mod.contrast = (checked_atoi(optarg)+32)*8;
if ((q->mod.contrast<0) || (q->mod.contrast>512))
usage(argv[0],1);
break;
case 'd': delay=(int) (atof (optarg) * 1000);
if (delay < 0) {
g_print("Error: %s is an invalid slide show delay.\n",optarg);
exit(1);
}
else if (delay == 0)
/* make sure we get the "quit key" */
do_grab = 1;
break;
case 'e': center=0;
break;
case 'f': fullscreen=1;
break;
case 'g': q->mod.gamma = (checked_atoi(optarg)+32)*8;
if ((q->mod.gamma<0) || (q->mod.gamma>512))
usage(argv[0],1);
break;
case 'h': show_help(argv[0], 0); break;
case 'i': force_statusbar=0;
break;
#if GDK_PIXBUF_MINOR >= 12
case 'l': autorotate=0; /* turn autorotation OFF, default is ON */
break;
#endif
case 'm': maxpect=1;
break;
case 'n': filter=0;
break;
case 'o': image_bg_spec = optarg;
break;
case 'p': transparency=1;
break;
case 'q': rotation=checked_atoi(optarg);
if (rotation < 0 || (rotation > 3 && rotation != 11 && rotation != 13))
usage(argv[0],1);
break;
case 'r': random_order=1;
break;
case 's': slide=1;
break;
case 't': scale_down=1;
break;
case 'u': recursive = 1;
break;
case 'L': followlinks=1;
break;
case 'v': g_print("qiv (Quick Image Viewer) v%s\n", VERSION);
gdk_exit(0);
break;
case 'w': q->win_w = fixed_window_size = checked_atoi(optarg);
break;
case 'x': to_root=1;
break;
case 'y': to_root_t=1;
break;
case 'z': to_root_s=1;
break;
case 'A': snprintf(select_dir, sizeof select_dir, "%s", optarg);
break;
case 'B': browse=1;
break;
case 'C': cycle=1;
break;
case 'D': need_sort = 0;
break;
case 'F': if(rreadfile(optarg) < 0) {
g_print("Error: %s could not be opened: %s.\n",optarg, strerror(errno));
gdk_exit(1);
}
break;
case 'G': disable_grab=1;
break;
case 'I': force_statusbar=1;
break;
case 'J': comment_window=1;
break;
case 'K': mtime_sort = 1;
break;
case 'M': merged_case_sort = 1;
break;
case 'N': numeric_sort = 1;
break;
case 'P': ignore_path_sort = 1;
break;
case 'R': readonly=1;
break;
case 'S': shuffle=1; need_sort=0;
break;
case 'T': watch_file=1;
break;
case 'W': fixed_zoom_factor = (checked_atoi(optarg) - 100) / 10; zoom_factor = fixed_zoom_factor;
break;
case 'X': user_screen = checked_atoi(optarg);
// g_print("set xinerama screen: %i\n", user_screen);
break;
#ifdef SUPPORT_LCMS
case 'Y': source_profile = optarg;
cms_transform = 1;
break;
case 'Z': display_profile = optarg;
cms_transform = 1;
break;
#endif
case LONGOPT_TRASHBIN:
trashbin=1;
break;
case LONGOPT_VIKEYS: vikeys=1;
break;
case 0:
case '?': usage(argv[0], 1);
gdk_exit(0);
}
}
/* In case user specified -D and -K, -P, -M, or -N */
need_sort = need_sort | mtime_sort | ignore_path_sort | merged_case_sort | numeric_sort;
/* default: show statusbar only in fullscreen mode */
/* user wants to override? */
if (force_statusbar != -1) {
statusbar_window=statusbar_fullscreen = force_statusbar;
}
if((cnt = argc - optind) > 0) {
if (!images) {
max_image_cnt = 8192;
image_names = (char**)xmalloc(max_image_cnt * sizeof(char*));
}
while (cnt-- > 0) {
if (stat(argv[optind], &sb) >= 0 && S_ISDIR(sb.st_mode)) {
rreaddir(argv[optind++],recursive);
}
else {
if (images >= max_image_cnt) {
max_image_cnt += 8192;
image_names = (char**)xrealloc(image_names,
max_image_cnt*sizeof(char*));
}
image_names[images++] = argv[optind++];
}
}
}
if(shuffle) {
char *fn;
int i, p;
for (i=0;i<images;i++) { /* simple insertion sort, fine for small num */
p = (int)(((float)rand()/(float)RAND_MAX) * (images-i)) + i;
fn = image_names[i];
image_names[i] = image_names[p];
image_names[p] = fn;
}
}
if (browse && images) {
images = 0; /* avoid displaying same filename twice */
char *tmp = (char *)xmalloc(strlen(image_names[0])+3);
if(strchr(image_names[0], '/')==NULL) {
*tmp ='.';
*(tmp+1) ='/';
strcpy(tmp+2,image_names[0]);
}
else {
strcpy(tmp,image_names[0]);
}
rreaddir(dirname(image_names[0]),0);
if(filter)
filter_images(&images,image_names);
if(need_sort)
qsort(image_names, images, sizeof *image_names, my_strcmp);
image_idx = find_image(images,image_names,tmp);
free(tmp);
}
else {
if(filter)
filter_images(&images,image_names);
if(need_sort)
qsort(image_names, images, sizeof *image_names, my_strcmp);
}
}