176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * getopt.c 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * getopt_long(), or at least a common subset thereof: 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - Option reordering is not supported 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - -W foo is not supported 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - First optstring character "-" not supported. 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h> 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <getopt.h> 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanchar *optarg; 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint optind, opterr, optopt; 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct getopt_private_state { 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *optptr; 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *last_optstring; 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *const *last_argv; 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} pvt; 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline const char *option_matches(const char *arg_str, 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *opt_name) 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (*arg_str != '\0' && *arg_str != '=') { 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (*arg_str++ != *opt_name++) 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (*opt_name) 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return arg_str; 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint getopt_long(int argc, char *const *argv, const char *optstring, 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct option *longopts, int *longindex) 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *carg; 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *osptr; 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int opt; 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* getopt() relies on a number of different global state 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman variables, which can make this really confusing if there is 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman more than one use of getopt() in the same program. This 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attempts to detect that situation by detecting if the 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman "optstring" or "argv" argument have changed since last time 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman we were called; if so, reinitialize the query state. */ 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (optstring != pvt.last_optstring || argv != pvt.last_argv || 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind < 1 || optind > argc) { 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* optind doesn't match the current query */ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pvt.last_optstring = optstring; 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pvt.last_argv = argv; 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind = 1; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pvt.optptr = NULL; 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman carg = argv[optind]; 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* First, eliminate all non-option cases */ 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!carg || carg[0] != '-' || !carg[1]) 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (carg[1] == '-') { 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct option *lo; 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *opt_end = NULL; 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind++; 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Either it's a long option, or it's -- */ 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!carg[2]) { 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* It's -- */ 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (lo = longopts; lo->name; lo++) { 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((opt_end = option_matches(carg+2, lo->name))) 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!opt_end) 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return '?'; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (longindex) 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *longindex = lo-longopts; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (*opt_end == '=') { 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lo->has_arg) 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optarg = (char *)opt_end+1; 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return '?'; 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (lo->has_arg == 1) { 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(optarg = argv[optind])) 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return '?'; 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind++; 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lo->flag) { 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *lo->flag = lo->val; 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return lo->val; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) { 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Someone frobbed optind, change to new opt. */ 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pvt.optptr = carg + 1; 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman opt = *pvt.optptr++; 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (opt != ':' && (osptr = strchr(optstring, opt))) { 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (osptr[1] == ':') { 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (*pvt.optptr) { 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Argument-taking option with attached 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman argument */ 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optarg = (char *)pvt.optptr; 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind++; 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Argument-taking option with non-attached 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman argument */ 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (argv[optind + 1]) { 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optarg = (char *)argv[optind+1]; 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind += 2; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Missing argument */ 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind++; 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (optstring[0] == ':') 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ? ':' : '?'; 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return opt; 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Non-argument-taking option */ 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* pvt.optptr will remember the exact position to 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman resume at */ 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!*pvt.optptr) 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind++; 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return opt; 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Unknown option */ 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optopt = opt; 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!*pvt.optptr) 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman optind++; 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return '?'; 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 153