/** @file getopt_long.c ** @brief getopt_long - Definition ** @author Andrea Vedaldi **/ /* Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson. All rights reserved. This file is part of the VLFeat library and is made available under the terms of the BSD license (see legal/licenses/LICENSE.BSD.vlfeat). */ /** @file getopt_long.h @brief getopt_long @author Andrea Vedaldi This is a drop-in replacament of GNU getopt_long meant to be used on platforms that do not support such functionality. **/ #include #include #include #include "getopt.h" int opterr = 1 ; int optind = 1 ; int optopt ; char * optarg ; int optreset ; #define BADCH '?' #define BADARG ':' #define EEND -1 #define EMSG "" /** @brief Parse long options (BSD style) ** @param argc number of arguments. ** @param argv pointer to the vector of arguments. ** @param optstring list of abbreviated options ** @param longopts list of long options. ** @param longindex index of current option in @a longopts. ** @return the code of the next option. ** ** This function extract long and short options from the argument ** list @a argv of @a argc entries. ** ** A short options sequence is introduced by a single dash character ** @c -. Each short option is described by a single character in the ** string @a optstring, possibly followed by a @c : character to ** denote a (mandatory) argument of the short option. A short option ** with an argument cannot appear in the middle of a short option ** sequence, but only at the end. ** ** A long option is introduced by a double dash @c --. Each long ** option is described by an instance of the ::option structure in ** the @a longopts table (the last entry must be filled with zeroes ** to denote the end). ** ** Illegal options and missing arguments cause the function to skip ** the option and return '?'. If ::opterr is @c true (default), the ** function prints an error message to @a stderr. Finally, if @a ** optstring has a leading @c :, then error messages are suppressed ** and a missing argument causes @a : to be returned. ** ** @remark The function is currently not thread safe. **/ VL_EXPORT int getopt_long(int argc, char *const argv[], const char *optstring, const struct option * longopts, int *longindex) { static char *place = EMSG; /* option letter processing */ static int optbegin = 0 ; static int optend = 0 ; const char *oli; /* option letter list index */ int has_colon = 0 ; int ret_val = 0 ; /* A semicolon at the beginning of optstring has a special meaning. If we find one, we annote and remove it. */ has_colon = optstring && optstring[0] == ':' ; if (has_colon) ++ optstring ; /* Here we are either processing a short option sequence or we start processing a new option. This is indicated by optreset. */ if (optreset || *place == '\0') { /* --------------------------------------------------------------- * Look for next short/long option * ------------------------------------------------------------ */ optreset = 0 ; /* no more arguments ? */ if (optind >= argc) { place = EMSG ; return -1 ; } /* next argument that may hold an option */ optbegin = optind ; /* --------------------------------------------------------------- * Look for an option to parse * ------------------------------------------------------------ */ parse_option_at_optbegin : /* place points to the candidate option */ place = argv [optbegin] ; /* an option is introduced by '-' */ if (place [0] != '-') { /* this argument is not an option: try next argument */ ++ optbegin ; if (optbegin >= argc) { /* no more arguments to look for options */ place = EMSG ; return -1 ; } goto parse_option_at_optbegin ; } /* consume leading `-' */ ++ place ; /* assume the option is composed of one argument only */ optend = optbegin + 1 ; /* assume no argument */ optarg = 0 ; /* --------------------------------------------------------------- * option `--' * ------------------------------------------------------------ */ /* this special option (void long option) ends the option processing */ if (place[0] && place[0] == '-' && place[1] == '\0') { optind = optend ; place = EMSG ; ret_val = -1 ; goto done_option ; } /* --------------------------------------------------------------- * long option * ------------------------------------------------------------ */ if (place[0] && place[0] == '-' && place[1] ) { size_t namelen ; int i ; /* consume second `-' */ ++ place ; /* count characters before `=' */ namelen = strcspn(place, "=") ; /* scan longopts for this option */ for (i = 0 ; longopts[i].name != NULL ; ++ i) { if (strlen ( longopts[i].name) == namelen && strncmp (place, longopts[i].name, namelen) == 0 ) { /* save back long option index */ if (longindex) *longindex = i ; /* process long option argument */ if (longopts[i].has_arg == required_argument || longopts[i].has_arg == optional_argument) { /* --option=value style */ if (place[namelen] == '=') { optarg = place + namelen + 1 ; } /* --option value style (only required_argument) */ else if (longopts[i].has_arg == required_argument) { /* missing argument ? */ if (optbegin >= argc - 1) { if (! has_colon && opterr) fprintf(stderr, "%s: option requires an argument -- %s\n", argv[0], place); place = EMSG ; ret_val = has_colon ? BADARG : BADCH ; goto done_option ; } optarg = argv [optend] ; ++ optend ; } } /* determine return value */ if (longopts[i].flag == NULL) { ret_val = longopts[i].val ; } else { *longopts[i].flag = longopts[i].val; ret_val = 0 ; } /* mark sequence closed */ place = EMSG ; goto done_option ; } /* if match */ } /* scan longoptions */ /* no matching option found */ if (! has_colon && opterr) fprintf(stderr, "%s: illegal option -- %s\n", argv[0], place) ; place = EMSG ; ret_val = BADCH ; goto done_option ; } } /* end new option */ /* ----------------------------------------------------------------- * Finish short option sequence * -------------------------------------------------------------- */ optopt = (int) *place++ ; /* search charcater in option list */ oli = strchr(optstring, optopt); /* short option not found */ if (!oli) { if (! has_colon && opterr) fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt); if (*place) { /* more short options in the list */ return BADCH ; } else { /* error occured as last option in the list */ place = EMSG ; ret_val = BADCH ; goto done_option ; } } /* end short option not found */ if (oli[1] != ':') { /* short option with no argument */ if (*place) { /* more short options in the list */ return optopt ; } else { /* last option in the list */ place = EMSG ; ret_val = optopt ; goto done_option ; } } else { /* short option with argument */ /* -ovalue style */ if (*place) { optarg = place ; place = EMSG ; ret_val = optopt ; goto done_option ; } /* -o value style: missing argument */ else if (optbegin >= argc - 1) { if (! has_colon && opterr) fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], optopt); place = EMSG ; ret_val = has_colon ? BADARG : BADCH ; goto done_option ; } /* -o value style: process argument */ optarg = argv [optend] ; ++ optend ; place = EMSG ; ret_val = optopt ; goto done_option ; } /* short with argument */ done_option : { int pos = optend - optbegin ; /* n of circular shifts */ int c = pos ; while (c --) { int i ; char *tmp = argv [optend - 1] ; for (i = optend - 1 ; i > optind ; -- i) { ((char**)argv) [i] = argv [i-1] ; } ((char**)argv) [optind] = tmp ; } optind += pos ; } return ret_val ; }