diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index a21cd0e6..3f546ed5 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -53,11 +53,15 @@ if (MSVC) link_directories(${CMAKE_INSTALL_PREFIX}/lib) endif() -add_executable( metacopy metacopy.cpp ../src/utils.cpp) +add_executable( getopt-test getopt-test.cpp ../src/utils.cpp ../src/getopt.cpp) +list(APPEND APPLICATIONS getopt-test) +target_include_directories(getopt-test PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find utils.hpp + +add_executable( metacopy metacopy.cpp ../src/utils.cpp ../src/getopt.cpp) list(APPEND APPLICATIONS metacopy) target_include_directories(metacopy PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find utils.hpp -add_executable( pathtest path-test.cpp ../src/utils.cpp) +add_executable( pathtest path-test.cpp ../src/utils.cpp ../src/getopt.cpp) list(APPEND APPLICATIONS pathtest) set_target_properties( pathtest PROPERTIES OUTPUT_NAME path-test ) target_include_directories(pathtest PRIVATE ${CMAKE_SOURCE_DIR}/src) # To find utils.hpp @@ -67,11 +71,6 @@ list(APPEND APPLICATIONS exiv2json) install( TARGETS metacopy pathtest exiv2json RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -if (MSVC) - target_sources(pathtest PRIVATE ../src/getopt_win32.c) - target_sources(metacopy PRIVATE ../src/getopt_win32.c) -endif() - if( EXPAT_FOUND ) add_executable( geotag geotag.cpp) list(APPEND APPLICATIONS geotag) diff --git a/samples/getopt-test.cpp b/samples/getopt-test.cpp new file mode 100644 index 00000000..a75d8137 --- /dev/null +++ b/samples/getopt-test.cpp @@ -0,0 +1,126 @@ +// ***************************************************************** -*- C++ -*- +// getopt-test.cpp +// Sample program to test getopt() +// Command: +// $ getopt-test -v pr -P EIXxgklnycsvth file1 file2 +// +// Output: +// standard getopt() +// 118 = v optind = 2 opterr = 1 optopt = 118 optarg = unknown +// -1 optind = 2 opterr = 1 optopt = 118 optarg = unknown +// +// homemade getopt() +// 118 = v optind = 2 opterr = 1 optopt = 118 optarg = unknown +// -1 optind = 2 opterr = 1 optopt = 118 optarg = unknown +// +// Params::option() opt = 118 optarg = optopt = 118 +// Params::nonoption() pr +// Params::nonoption() -P +// Params::nonoption() EIXxgklnycsvth +// Params::nonoption() file1 +// Params::nonoption() file2 +// Params::getopt() rc = 0 + +#include +#include "getopt.hpp" + +#include +#include +#include +#include + +#define Safe(x) (x?x:"unknown") +const char* optstring = ":hVvqfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:K:n:Q:"; + + +// ***************************************************************************** +// class Params +class Params : public Util::Getopt { + +public: + /*! + @brief Call Getopt::getopt() with optstring, to inititate command line + argument parsing, perform consistency checks after all command line + arguments are parsed. + + @param argc Argument count as passed to main() on program invocation. + @param argv Argument array as passed to main() on program invocation. + + @return 0 if successful, >0 in case of errors. + */ + int getopt(int argc, char** const argv) + { + int rc = Util::Getopt::getopt(argc, argv, ::optstring); + std::cout << "Params::getopt()" + << " rc = " << rc + << std::endl; + return rc ; + } + + //! Handle options and their arguments. + int option(int opt, const std::string& optarg, int optopt) + { + std::cout << "Params::option()" + << " opt = " << opt + << " optarg = " << optarg + << " optopt = " << optopt + << std::endl; + return 0; + } + + //! Handle non-option parameters. + int nonoption(const std::string& argv) + { + std::cout << "Params::nonoption()" + << " " << argv + << std::endl; + return 0 ; + } +}; // class Params + +int main(int argc, char** const argv) +{ + int n; + + std::cout << "standard getopt()" << std::endl; + do { + n = ::getopt(argc,argv,::optstring); + if ( n >= 0 ) { + char N = (char) n; + std::cout << n << " = " << N ; + } else { + std::cout << n ; + } + std::cout << " optind = " << ::optind + << " opterr = " << ::opterr + << " optopt = " << ::optopt + << " optarg = " << Safe(::optarg) + << std::endl; + } while ( n >= 0 ); + std::cout << std::endl; + + std::cout << "homemade getopt()" << std::endl; + do { + n = Util::getopt(argc,argv,::optstring); + if ( n >= 0 ) { + char N = (char) n; + std::cout << n << " = " << N ; + } else { + std::cout << n ; + } + std::cout << " optind = " << Util::optind + << " opterr = " << Util::opterr + << " optopt = " << Util::optopt + << " optarg = " << Safe(::optarg) + << std::endl; + + } while ( n >= 0 ); + std::cout << std::endl; + + // Handle command line arguments + Params params; + params.getopt(argc, argv); + + return 0; +} + diff --git a/samples/metacopy.cpp b/samples/metacopy.cpp index b619aa90..a4b1c93f 100644 --- a/samples/metacopy.cpp +++ b/samples/metacopy.cpp @@ -33,7 +33,7 @@ #include #include -#include "utils.hpp" +#include "getopt.hpp" #include "metacopy.hpp" // ***************************************************************************** diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1fcf2a2..56af1863 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -302,6 +302,8 @@ set( EXIV2_SRC exiv2app.hpp actions.cpp actions.hpp + getopt.cpp + getopt.hpp utils.cpp utils.hpp ) @@ -328,8 +330,6 @@ if(EXIV2_BUILD_EXIV2_COMMAND) # TODO This should not be needed here! we need to fix the previous TODO target_include_directories(exiv2 PRIVATE ${CMAKE_SOURCE_DIR}/include/) - target_sources(exiv2 PRIVATE getopt_win32.c) - # Copy DLLs from conan packages to the bin folder if (USING_CONAN AND WIN32) add_custom_command(TARGET exiv2 POST_BUILD diff --git a/src/exiv2app.hpp b/src/exiv2app.hpp index d1ef6806..f215ffdd 100644 --- a/src/exiv2app.hpp +++ b/src/exiv2app.hpp @@ -34,6 +34,7 @@ #include "utils.hpp" #include "types.hpp" +#include "getopt.hpp" // + standard includes #include diff --git a/src/getopt.cpp b/src/getopt.cpp new file mode 100644 index 00000000..ee38ab4b --- /dev/null +++ b/src/getopt.cpp @@ -0,0 +1,123 @@ + +#if _MSC_VER >= 1400 +# pragma warning(disable : 4996) +#endif + +// included header files +#include +#include +#include +#include +#include +#include +#include + +#include "utils.hpp" +#include "getopt.hpp" + +namespace Util { + + // https://raw.githubusercontent.com/skeeto/getopt/master/getopt.h + int optind = 0; + int opterr = 1; + int optopt; + int optpos = 1; + const char* optarg; + + /* A minimal POSIX getopt() implementation in ANSI C + * + * This is free and unencumbered software released into the public domain. + * + * This implementation supports the convention of resetting the option + * parser by assigning optind to 0. This resets the internal state + * appropriately. + * + * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html + */ + + int getopt(int argc, char * const argv[], const char *optstring) + { + const char *arg; + (void)argc; + + /* Reset? */ + if (optind == 0) { + optind = 1; + optpos = 1; + } + + arg = argv[optind]; + if (arg && strcmp(arg, "--") == 0) { + optind++; + return -1; + } else if (!arg || arg[0] != '-' || !isalnum(arg[1])) { + return -1; + } else { + const char *opt = strchr(optstring, arg[optpos]); + optopt = arg[optpos]; + if (!opt) { + if (opterr && *optstring != ':') + fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt); + return '?'; + } else if (opt[1] == ':') { + if (arg[optpos + 1]) { + optarg = (char *)arg + optpos + 1; + optind++; + optpos = 1; + return optopt; + } else if (argv[optind + 1]) { + optarg = (char *)argv[optind + 1]; + optind += 2; + optpos = 1; + return optopt; + } else { + if (opterr && *optstring != ':') + fprintf(stderr, + "%s: option requires an argument: %c\n", + argv[0], optopt); + return *optstring == ':' ? ':' : '?'; + } + } else { + if (!arg[++optpos]) { + optind++; + optpos = 1; + } + return optopt; + } + } + } + +// ***************************************************************************** +// class Getopt + Getopt::Getopt() + : errcnt_(0) + { + } + + Getopt::~Getopt() + { + } + + int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) + { + progname_ = Util::basename(argv[0]); + Util::optind = 0; // reset the Util::Getopt scanner + + for (;;) { + int c = Util::getopt(argc, argv, optstring.c_str()); + if (c == -1) break; + errcnt_ += option(c, Util::optarg == 0 ? "" : Util::optarg, Util::optopt); + } + for (int i = Util::optind; i < argc; i++) { + errcnt_ += nonoption(argv[i]); + } + + return errcnt_; + } + + int Getopt::nonoption(const std::string& /*argv*/) + { + return 0; + } + +} // namespace Util diff --git a/src/getopt.hpp b/src/getopt.hpp new file mode 100644 index 00000000..ca536b54 --- /dev/null +++ b/src/getopt.hpp @@ -0,0 +1,101 @@ +#ifndef GETOPT_H +#define GETOPT_H + +#include +#include +#include + +namespace Util { + + extern int optind ; + extern int opterr ; + extern int optopt ; + extern int optpos ; + extern const char* optarg; + + int getopt(int argc, char * const argv[], const char *optstring); + + // ********************************************************************* + // class definitions + + /*! + @brief Parse the command line options of a program. + + A wrapper around the POSIX %getopt(3) function. Parses the command line + options and passes each option to virtual option(). A derived class + implements this method to handle options as needed. Similarly, + remaining non-option parameters are passed to the virtual nonoption() + method. + */ + class Getopt { + public: + //! Default constructor. + Getopt(); + + //! Destructor. + virtual ~Getopt(); + + /*! + @brief Parse command line arguments. + + Parses the command line arguments. Calls option() with the + character value of the option and its argument (if any) for each + recognized option and with ':' or '?' for unrecognized options. + See the manual pages for %getopt(3) for details. In addition, + nonoption() is invoked for each remaining non-option parameter on + the command line. + + @param argc Argument count as passed to main() on program invocation. + @param argv Argument array as passed to main() on program invocation. + @param optstring String containing the legitimate option characters. + + @return Number of errors (the sum of the return values from option() + and nonoption()). + */ + int getopt(int argc, char* const argv[], const std::string& optstring); + + /*! + @brief Callback used by getopt() to pass on each option and its + argument (if any). + + Implement this method in a derived class to handle the options as + needed. See the manual pages for %getopt(3) for further details, in + particular, the semantics of optarg and optopt. + + @param opt Value of the option character as returned by %getopt(3). + @param optarg The corresponding option argument. + @param optopt The actual option character in case of an unrecognized + option or a missing option argument (opt is '?' or ':'). + + @return 0 if successful, 1 in case of an error. + */ + virtual int option(int opt, const std::string& optarg, int optopt) = 0; + + /*! + @brief Callback used by getopt() to pass on each non-option parameter + found on the command line. + + Implement this method in a derived class to handle the non-option + parameters as needed. The default implementation ignores all non-option + parameters. + + @param argv The non-option parameter from the command line. + + @return 0 if successful, 1 in case of an error. + */ + virtual int nonoption(const std::string& argv); + + //! Program name (argv[0]) + const std::string& progname() const { return progname_; } + + //! Total number of errors returned by calls to option() + int errcnt() const { return errcnt_; } + + private: + std::string progname_; + int errcnt_; + }; + +}; // namespace Util + +#endif diff --git a/src/getopt_win32.c b/src/getopt_win32.c deleted file mode 100644 index 18dfcfbf..00000000 --- a/src/getopt_win32.c +++ /dev/null @@ -1,521 +0,0 @@ -/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ - -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#if _MSC_VER >= 1400 -# pragma warning(disable : 4996) -#endif - -// included header files -#include -#include -#include -#include -#include "getopt_win32.h" -#include -#include - -#define REPLACE_GETOPT - -#define _DIAGASSERT(x) do {} while (0) - -#ifdef REPLACE_GETOPT -#ifdef __weak_alias -__weak_alias(getopt,_getopt) -#endif -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ -#endif - -#ifdef __weak_alias -__weak_alias(getopt_long,_getopt_long) -#endif - -#ifndef __CYGWIN__ -#define __progname __argv[0] -#else -extern char __declspec(dllimport) *__progname; -#endif - -#define IGNORE_FIRST (*options == '-' || *options == '+') -#define PRINT_ERROR ((opterr) && ((*options != ':') \ - || (IGNORE_FIRST && options[1] != ':'))) - -/* This differs from the cygwin implementation, which effectively defaults to - PC, but is consistent with the NetBSD implementation and doc's. */ -#ifndef IS_POSIXLY_CORRECT -#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) -#endif - -#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) -/* XXX: GNU ignores PC if *options == '-' */ -#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') - -/* return values */ -#define BADCH (int)'?' -#define BADARG ((IGNORE_FIRST && options[1] == ':') \ - || (*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 - -static char EMSG[1]; - -static int getopt_internal (int, char * const *, const char *); -static int gcd (int, int); -static void permute_args (int, int, int, char * const *); - -static char *place = EMSG; /* option letter processing */ - -/* XXX: set optreset to 1 rather than these two */ -static int nonopt_start = -1; /* first non option argument (for permute) */ -static int nonopt_end = -1; /* first option after non options (for permute) */ - -/* Error messages */ -static const char recargchar[] = "option requires an argument -- %c"; -static const char recargstring[] = "option requires an argument -- %s"; -static const char ambig[] = "ambiguous option -- %.*s"; -static const char noarg[] = "option doesn't take an argument -- %.*s"; -static const char illoptchar[] = "unknown option -- %c"; -static const char illoptstring[] = "unknown option -- %s"; - -static void -_vwarnx(const char *fmt, va_list ap) -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); -} - -static void -warnx(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - _vwarnx(fmt, ap); - va_end(ap); -} - -/* - * Compute the greatest common divisor of a and b. - */ -static int -gcd(a, b) - int a; - int b; -{ - int c; - - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } - - return b; -} - -/* - * Exchange the block from nonopt_start to nonopt_end with the block - * from nonopt_end to opt_end (keeping the same order of arguments - * in each block). - */ -static void -permute_args(panonopt_start, panonopt_end, opt_end, nargv) - int panonopt_start; - int panonopt_end; - int opt_end; - char * const *nargv; -{ - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - _DIAGASSERT(nargv != NULL); - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } -} - -#ifdef __GETOPT_DEFINE_ARGV__ -char * const *__argv; -#endif - -/* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - * Returns -2 if -- is found (can be long option or end of options marker). - */ -static int -getopt_internal(nargc, nargv, options) - int nargc; - char * const *nargv; - const char *options; -{ - -#ifdef __GETOPT_DEFINE_ARGV__ - __argv=nargv; -#endif - - char *oli; /* option letter list index */ - int optchar; - - _DIAGASSERT(nargv != NULL); - _DIAGASSERT(options != NULL); - - optarg = NULL; - - /* - * XXX Some programs (like rsyncd) expect to be able to - * XXX re-initialize optind to 0 and have getopt_long(3) - * XXX properly function again. Work around this braindamage. - */ - if (optind == 0) - optind = 1; - - if (optreset) - nonopt_start = nonopt_end = -1; -start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = EMSG; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return -1; - } - if ((*(place = nargv[optind]) != '-') - || (place[1] == '\0')) { /* found non-option */ - place = EMSG; - if (IN_ORDER) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return INORDER; - } - if (!PERMUTE) { - /* - * if no permutation wanted, stop parsing - * at first non-option - */ - return -1; - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; - if (place[1] && *++place == '-') { /* found "--" */ - place++; - return -2; - } - } - if ((optchar = (int)*place++) == (int)':' || - (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { - /* option letter unknown or ':' */ - if (!*place) - ++optind; - if (PRINT_ERROR) - warnx(illoptchar, optchar); - optopt = optchar; - return BADCH; - } - if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ - /* XXX: what if no long options provided (called by getopt)? */ - if (*place) - return -2; - - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return BADARG; - } else /* white space */ - place = nargv[optind]; - /* - * Handle -W arg the same as --arg (which causes getopt to - * stop parsing). - */ - return -2; - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - /* XXX: disable test for :: if PC? (GNU doesn't) */ - else if (oli[1] != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return BADARG; - } else - optarg = nargv[optind]; - } - place = EMSG; - ++optind; - } - /* dump back option letter */ - return optchar; -} - -#ifdef REPLACE_GETOPT -/* - * getopt -- - * Parse argc/argv argument vector. - * - * [eventually this will replace the real getopt] - */ -int -getopt(nargc, nargv, options) - int nargc; - char * const *nargv; - const char *options; -{ - int retval; - - _DIAGASSERT(nargv != NULL); - _DIAGASSERT(options != NULL); - - if ((retval = getopt_internal(nargc, nargv, options)) == -2) { - ++optind; - /* - * We found an option (--), so if we skipped non-options, - * we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, optind, - nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - retval = -1; - } - return retval; -} -#endif - -/* - * getopt_long -- - * Parse argc/argv argument vector. - */ -int -getopt_long(nargc, nargv, options, long_options, idx) - int nargc; - char * const *nargv; - const char *options; - const struct option *long_options; - int *idx; -{ - int retval; - - _DIAGASSERT(nargv != NULL); - _DIAGASSERT(options != NULL); - _DIAGASSERT(long_options != NULL); - /* idx may be NULL */ - - if ((retval = getopt_internal(nargc, nargv, options)) == -2) { - char *current_argv, *has_equal; - size_t current_argv_len; - int i, match; - - current_argv = place; - match = -1; - - optind++; - place = EMSG; - - if (*current_argv == '\0') { /* found "--" */ - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return -1; - } - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else - current_argv_len = strlen(current_argv); - - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == - (unsigned)current_argv_len) { - /* exact match */ - match = i; - break; - } - if (match == -1) /* partial match */ - match = i; - else { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return BADCH; - } - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of - * flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - return BADARG; - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use - * next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' - * indicates no error should be generated - */ - if (PRINT_ERROR) - warnx(recargstring, current_argv); - /* - * XXX: GNU sets optopt to val regardless - * of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return BADARG; - } - } else { /* unknown option */ - if (PRINT_ERROR) - warnx(illoptstring, current_argv); - optopt = 0; - return BADCH; - } - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - retval = 0; - } else - retval = long_options[match].val; - if (idx) - *idx = match; - } - return retval; -} diff --git a/src/getopt_win32.h b/src/getopt_win32.h deleted file mode 100644 index cd5760a3..00000000 --- a/src/getopt_win32.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 1987, 1993, 1994, 1996 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __GETOPT_H__ -#define __GETOPT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW__) && !defined(_MSC_VER) -// the symbol __argv (and __argc and __progname and __env) are defined in Windows environments -// for *ix environments, __argv is declared here, defined: getopt_win32.c, init'd: getopt_internal() -#define __GETOPT_DEFINE_ARGV__ -extern char * const *__argv; -#endif - -extern int opterr; /* if error message should be printed */ -extern int optind; /* index into parent argv vector */ -extern int optopt; /* character checked for validity */ -extern int optreset; /* reset getopt */ -extern char *optarg; /* argument associated with option */ - -int getopt (int, char * const *, const char *); - -#ifdef __cplusplus -} -#endif - -#endif /* __GETOPT_H__ */ - -#ifndef __UNISTD_GETOPT__ -#ifndef __GETOPT_LONG_H__ -#define __GETOPT_LONG_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct option { - const char *name; - int has_arg; - int *flag; - int val; -}; - -int getopt_long (int, char *const *, const char *, const struct option *, int *); -#ifndef HAVE_DECL_GETOPT -#define HAVE_DECL_GETOPT 1 -#endif - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#ifdef __cplusplus -} -#endif - -#endif /* __GETOPT_LONG_H__ */ -#endif /* __UNISTD_GETOPT__ */ diff --git a/src/utils.cpp b/src/utils.cpp index 7eced113..53740cbf 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -28,7 +28,6 @@ #include "config.h" #include "utils.hpp" -#include "getopt_win32.h" #if defined(_MSC_VER) # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) @@ -51,37 +50,6 @@ namespace Util { -// ***************************************************************************** -// class Getopt - Getopt::Getopt() - : errcnt_(0) - { - } - - Getopt::~Getopt() - { - } - - int Getopt::getopt(int argc, char* const argv[], const std::string& optstring) - { - progname_ = Util::basename(argv[0]); - - for (;;) { - int c = ::getopt(argc, argv, optstring.c_str()); - if (c == -1) break; - errcnt_ += option(c, ::optarg == 0 ? "" : ::optarg, ::optopt); - } - for (int i = ::optind; i < argc; i++) { - errcnt_ += nonoption(argv[i]); - } - return errcnt_; - } - - int Getopt::nonoption(const std::string& /*argv*/) - { - return 0; - } - // ***************************************************************************** // free functions diff --git a/src/utils.hpp b/src/utils.hpp index 9e277320..fb622657 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -43,87 +43,6 @@ */ namespace Util { -// ********************************************************************* -// class definitions - -/*! - @brief Parse the command line options of a program. - - A wrapper around the POSIX %getopt(3) function. Parses the command line - options and passes each option to virtual option(). A derived class - implements this method to handle options as needed. Similarly, - remaining non-option parameters are passed to the virtual nonoption() - method. - */ -class Getopt { -public: - //! Default constructor. - Getopt(); - - //! Destructor. - virtual ~Getopt(); - - /*! - @brief Parse command line arguments. - - Parses the command line arguments. Calls option() with the - character value of the option and its argument (if any) for each - recognized option and with ':' or '?' for unrecognized options. - See the manual pages for %getopt(3) for details. In addition, - nonoption() is invoked for each remaining non-option parameter on - the command line. - - @param argc Argument count as passed to main() on program invocation. - @param argv Argument array as passed to main() on program invocation. - @param optstring String containing the legitimate option characters. - - @return Number of errors (the sum of the return values from option() - and nonoption()). - */ - int getopt(int argc, char* const argv[], const std::string& optstring); - - /*! - @brief Callback used by getopt() to pass on each option and its - argument (if any). - - Implement this method in a derived class to handle the options as - needed. See the manual pages for %getopt(3) for further details, in - particular, the semantics of optarg and optopt. - - @param opt Value of the option character as returned by %getopt(3). - @param optarg The corresponding option argument. - @param optopt The actual option character in case of an unrecognized - option or a missing option argument (opt is '?' or ':'). - - @return 0 if successful, 1 in case of an error. - */ - virtual int option(int opt, const std::string& optarg, int optopt) = 0; - - /*! - @brief Callback used by getopt() to pass on each non-option parameter - found on the command line. - - Implement this method in a derived class to handle the non-option - parameters as needed. The default implementation ignores all non-option - parameters. - - @param argv The non-option parameter from the command line. - - @return 0 if successful, 1 in case of an error. - */ - virtual int nonoption(const std::string& argv); - - //! Program name (argv[0]) - const std::string& progname() const { return progname_; } - - //! Total number of errors returned by calls to option() - int errcnt() const { return errcnt_; } - -private: - std::string progname_; - int errcnt_; -}; - // ********************************************************************* // free functions diff --git a/tests/bugfixes/github/test_CVE_2017_18005.py b/tests/bugfixes/github/test_CVE_2017_18005.py index bb0314a0..0880b486 100644 --- a/tests/bugfixes/github/test_CVE_2017_18005.py +++ b/tests/bugfixes/github/test_CVE_2017_18005.py @@ -15,7 +15,7 @@ Error: Offset of directory Image, entry 0x0117 is out of bounds: Offset = 0x3030 filename = "$data_path/cve_2017_18005_reproducer.tiff" commands = [ - "$exiv2 -v pr -P EIXxgklnycsvth " + filename, + "$exiv2 -vPEIXxgklnycsvth " + filename, "$exiv2json " + filename ]