#include #include #include #include #include #include #include #include "options.h" #include "../config.h" static const char *usage_str = "" "Usage: fzy [OPTION]...\n" " -l, --lines=LINES Specify how many lines of results to show (default 10)\n" " -p, --prompt=PROMPT Input prompt (default '> ')\n" " -q, --query=QUERY Use QUERY as the initial search string\n" " -e, --show-matches=QUERY Output the sorted matches of QUERY\n" " -t, --tty=TTY Specify file to use as TTY device (default /dev/tty)\n" " -s, --show-scores Show the scores of each match\n" " -0, --read-null Read input delimited by ASCII NUL characters\n" " -j, --workers NUM Use NUM workers for searching. (default is # of CPUs)\n" " -i, --show-info Show selection info line\n" " -f, --search-fields=SELECTOR Use these fields for searching. Default is the whole line.\n" " -F, --output-fields=SELECTOR Use these fields for output. Default is the whole line)\n" " -d, --delimiters=DELIM Use these delimiters to split input lines into fields. Default is ''.\n" " -h, --help Display this help and exit\n" " -v, --version Output version information and exit\n"; static void usage(const char *argv0) { fprintf(stderr, usage_str, argv0); } static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e'}, {"query", required_argument, NULL, 'q'}, {"lines", required_argument, NULL, 'l'}, {"tty", required_argument, NULL, 't'}, {"prompt", required_argument, NULL, 'p'}, {"show-scores", no_argument, NULL, 's'}, {"read-null", no_argument, NULL, '0'}, {"version", no_argument, NULL, 'v'}, {"benchmark", optional_argument, NULL, 'b'}, {"workers", required_argument, NULL, 'j'}, {"show-info", no_argument, NULL, 'i'}, {"search-fields", required_argument, NULL, 'f'}, {"output-fields", required_argument, NULL, 'F'}, {"delimiter", required_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}}; static void field_selector_uninit(FieldSelector *fs) { if (!fs) return; free(fs->ranges); fs->ranges = NULL; fs->nb_ranges = 0; } static int field_selector_parse(FieldSelector *fs, char *str) { size_t nb_ranges; int cur_range; field_selector_uninit(fs); if (!str || !*str) return 0; nb_ranges = 1; for (const char *p = str; *p; p++) { if (*p == ',') nb_ranges++; } fs->ranges = calloc(nb_ranges, sizeof(*fs->ranges)); if (!fs->ranges) return -ENOMEM; fs->nb_ranges = nb_ranges; cur_range = 0; while (*str) { int start, end; start = 0; if (*str == '-' || isdigit(*str)) start = strtol(str, &str, 0); if (*str == ':') { str++; end = (*str == '-' || isdigit(*str)) ? strtol(str, &str, 0) : -1; } else end = start; if (*str) { if (*str != ',') { field_selector_uninit(fs); return -EINVAL; } str++; } fs->ranges[cur_range].start = start; fs->ranges[cur_range].end = end; cur_range++; } return 0; } void options_uninit(options_t *options) { field_selector_uninit(&options->search_fields); field_selector_uninit(&options->output_fields); memset(options, 0, sizeof(*options)); } void options_init(options_t *options) { /* set defaults */ memset(options, 0, sizeof(*options)); options->benchmark = 0; options->filter = NULL; options->init_search = NULL; options->show_scores = 0; options->scrolloff = 1; options->tty_filename = DEFAULT_TTY; options->num_lines = DEFAULT_NUM_LINES; options->prompt = DEFAULT_PROMPT; options->workers = DEFAULT_WORKERS; options->input_delimiter = '\n'; options->show_info = DEFAULT_SHOW_INFO; options->delimiters = DEFAULT_DELIMITERS; } void options_parse(options_t *options, int argc, char *argv[]) { options_init(options); int c; while ((c = getopt_long(argc, argv, "vhs0e:q:l:t:p:j:id:f:F:", longopts, NULL)) != -1) { switch (c) { case 'v': printf("%s " VERSION " © 2014-2018 John Hawthorn\n", argv[0]); exit(EXIT_SUCCESS); case 's': options->show_scores = 1; break; case '0': options->input_delimiter = '\0'; break; case 'q': options->init_search = optarg; break; case 'e': options->filter = optarg; break; case 'b': if (optarg) { if (sscanf(optarg, "%d", &options->benchmark) != 1) { usage(argv[0]); exit(EXIT_FAILURE); } } else { options->benchmark = 100; } break; case 't': options->tty_filename = optarg; break; case 'p': options->prompt = optarg; break; case 'j': if (sscanf(optarg, "%u", &options->workers) != 1) { usage(argv[0]); exit(EXIT_FAILURE); } break; case 'l': { int l; if (!strcmp(optarg, "max")) { l = INT_MAX; } else if (sscanf(optarg, "%d", &l) != 1 || l < 3) { fprintf(stderr, "Invalid format for --lines: %s\n", optarg); fprintf(stderr, "Must be integer in range 3..\n"); usage(argv[0]); exit(EXIT_FAILURE); } options->num_lines = l; } break; case 'i': options->show_info = 1; break; case 'd': options->delimiters = optarg; break; case 'f': { int ret = field_selector_parse(&options->search_fields, optarg); if (ret < 0) { fprintf(stderr, "Invalid format for --search-fields: %s\n", optarg); usage(argv[0]); exit(EXIT_FAILURE); } } break; case 'F': { int ret = field_selector_parse(&options->output_fields, optarg); if (ret < 0) { fprintf(stderr, "Invalid format for --output-field: %s\n", optarg); usage(argv[0]); exit(EXIT_FAILURE); } } break; case 'h': default: usage(argv[0]); exit(EXIT_SUCCESS); } } if (optind != argc) { usage(argv[0]); exit(EXIT_FAILURE); } }