From 1d3223e9c61dcb00fad32de92cab922ee97b404b Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sun, 30 Apr 2023 02:06:27 +0200 Subject: [PATCH] Add getopt supporting unicode Fixes #1191 --- 3rdparty/README.md | 2 +- 3rdparty/getopt/CMakeLists.txt | 3 +- 3rdparty/getopt/getopt.c | 562 ------------------------ 3rdparty/getopt/getopt.cpp | 753 ++++++++++++++++++++++++++++++++ 3rdparty/getopt/getopt.h | 230 ++++++---- CMakeLists.txt | 3 +- src/CMakeLists.txt | 12 +- src/core/commandlineoptions.cpp | 231 ++++++---- src/core/commandlineoptions.h | 18 +- 9 files changed, 1068 insertions(+), 746 deletions(-) delete mode 100644 3rdparty/getopt/getopt.c create mode 100644 3rdparty/getopt/getopt.cpp diff --git a/3rdparty/README.md b/3rdparty/README.md index 607009d0..783f7684 100644 --- a/3rdparty/README.md +++ b/3rdparty/README.md @@ -27,4 +27,4 @@ Can safely be deleted on other platforms. getopt ------ -getopt included only when compiling with MSVC on Windows. +getopt included only when compiling on Windows. diff --git a/3rdparty/getopt/CMakeLists.txt b/3rdparty/getopt/CMakeLists.txt index c73fcdca..7a7c4717 100644 --- a/3rdparty/getopt/CMakeLists.txt +++ b/3rdparty/getopt/CMakeLists.txt @@ -1,2 +1,3 @@ -add_library(getopt STATIC getopt.c) +add_library(getopt STATIC getopt.cpp) +target_compile_definitions(getopt PRIVATE -DSTATIC_GETOPT -D_UNICODE) target_include_directories(getopt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/3rdparty/getopt/getopt.c b/3rdparty/getopt/getopt.c deleted file mode 100644 index ac7f9fe1..00000000 --- a/3rdparty/getopt/getopt.c +++ /dev/null @@ -1,562 +0,0 @@ -/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */ -/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ - -/* - * Copyright (c) 2002 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ -/*- - * 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. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ - -#ifdef REPLACE_GETOPT -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -#undef optreset /* see getopt.h */ -#define optreset __mingw_optreset -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ -#endif - -#define PRINT_ERROR ((opterr) && (*options != ':')) - -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ - -/* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 - -#ifndef __CYGWIN__ -#define __progname __argv[0] -#else -extern char __declspec(dllimport) *__progname; -#endif - -#ifdef __CYGWIN__ -static char EMSG[] = ""; -#else -#define EMSG "" -#endif - -static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); -static int parse_long_options(char * const *, const char *, - const struct option *, int *, int); -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(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(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) -{ - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * 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; - } - } -} - -/* - * parse_long_options -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ -static int -parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) -{ - char *current_argv, *has_equal; - size_t current_argv_len; - int i, ambiguous, match; - -#define IDENTICAL_INTERPRETATION(_x, _y) \ - (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ - long_options[(_x)].flag == long_options[(_y)].flag && \ - long_options[(_x)].val == long_options[(_y)].val) - - current_argv = place; - match = -1; - ambiguous = 0; - - optind++; - - 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) == current_argv_len) { - /* exact match */ - match = i; - ambiguous = 0; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) /* partial match */ - match = i; - else if (!IDENTICAL_INTERPRETATION(i, match)) - ambiguous = 1; - } - if (ambiguous) { - /* 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 (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, current_argv); - optopt = 0; - return (BADCH); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); -#undef IDENTICAL_INTERPRETATION -} - -/* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - */ -static int -getopt_internal(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) -{ - char *oli; /* option letter list index */ - int optchar, short_too; - static int posixly_correct = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - * - * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or - * optreset != 0 for GNU compatibility. - */ - if (posixly_correct == -1 || optreset != 0) - posixly_correct = (GetEnvironmentVariableW(L"POSIXLY_CORRECT", NULL, 0) != 0); - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - if (*options == '+' || *options == '-') - options++; - - optarg = NULL; - 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' && strchr(options, '-') == NULL)) { - place = EMSG; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return (INORDER); - } - if (!(flags & FLAG_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 we have "-" do nothing, if "--" we are done. - */ - if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { - optind++; - place = EMSG; - /* - * 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); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() - */ - if (long_options != NULL && place != nargv[optind] && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; - if (*place == '-') - place++; /* --foo long option */ - else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ - - optchar = parse_long_options(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - place = EMSG; - return (optchar); - } - } - - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; - if (PRINT_ERROR) - warnx(illoptchar, optchar); - optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else /* white space */ - place = nargv[optind]; - optchar = parse_long_options(nargv, options, long_options, - idx, 0); - place = EMSG; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - 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 BSD getopt] - */ -int -getopt(int nargc, char * const *nargv, const char *options) -{ - - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); -} -#endif /* REPLACE_GETOPT */ - -/* - * getopt_long -- - * Parse argc/argv argument vector. - */ -int -getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); -} - -/* - * getopt_long_only -- - * Parse argc/argv argument vector. - */ -int -getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE|FLAG_LONGONLY)); -} diff --git a/3rdparty/getopt/getopt.cpp b/3rdparty/getopt/getopt.cpp new file mode 100644 index 00000000..d1e7935e --- /dev/null +++ b/3rdparty/getopt/getopt.cpp @@ -0,0 +1,753 @@ +/* Getopt for Microsoft C +This code is a modification of the Free Software Foundation, Inc. +Getopt library for parsing command line argument the purpose was +to provide a Microsoft Visual C friendly derivative. This code +provides functionality for both Unicode and Multibyte builds. + +Date: 02/03/2011 - Ludvik Jerabek - Initial Release +Version: 1.1 +Comment: Supports getopt, getopt_long, and getopt_long_only +and POSIXLY_CORRECT environment flag +License: LGPL + +Revisions: + +02/03/2011 - Ludvik Jerabek - Initial Release +02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 +07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs +08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception +08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB +02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file +08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi +10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features +06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable +09/24/2022 - Ludvik Jerabek - Updated to match most recent getopt release +09/25/2022 - Ludvik Jerabek - Fixed memory allocation (malloc call) issue for wchar_t* + +**DISCLAIMER** +THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT +APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY +USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST +PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON +YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE +EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +*/ +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include "getopt.h" + +#ifdef __cplusplus +# define _GETOPT_THROW throw() +#else +# define _GETOPT_THROW +#endif + +int optind = 1; +int opterr = 1; +int optopt = '?'; +enum ENUM_ORDERING { + REQUIRE_ORDER, + PERMUTE, + RETURN_IN_ORDER +}; + +// +// +// Ansi structures and functions follow +// +// + +static struct _getopt_data_a { + int optind; + int opterr; + int optopt; + char *optarg; + int __initialized; + char *__nextchar; + enum ENUM_ORDERING __ordering; + int __first_nonopt; + int __last_nonopt; +} getopt_data_a; +char *optarg_a; + +static void exchange_a(char **argv, struct _getopt_data_a *d) { + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + char *tem; + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + int len = middle - bottom; + int i; + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + top -= len; + } + else { + int len = top - middle; + int i; + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + bottom += len; + } + } + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} + +static int process_long_option_a(int argc, char **argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int print_errors, const char *prefix); +static int process_long_option_a(int argc, char **argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int print_errors, const char *prefix) { + assert(longopts != NULL); + char *nameend; + size_t namelen; + const struct option_a *p; + const struct option_a *pfound = NULL; + int n_options; + int option_index = 0; + for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) + ; + namelen = nameend - d->__nextchar; + for (p = longopts, n_options = 0; p->name; p++, n_options++) + if (!strncmp(p->name, d->__nextchar, namelen) && namelen == strlen(p->name)) { + pfound = p; + option_index = n_options; + break; + } + if (pfound == NULL) { + unsigned char *ambig_set = NULL; + int ambig_fallback = 0; + int indfound = -1; + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->__nextchar, namelen)) { + if (pfound == NULL) { + pfound = p; + indfound = option_index; + } + else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) { + if (!ambig_fallback) { + if (!print_errors) + ambig_fallback = 1; + + else if (!ambig_set) { + if ((ambig_set = reinterpret_cast(malloc(n_options * sizeof(char)))) == NULL) + ambig_fallback = 1; + + if (ambig_set) { + memset(ambig_set, 0, n_options * sizeof(char)); + ambig_set[indfound] = 1; + } + } + if (ambig_set) + ambig_set[option_index] = 1; + } + } + } + if (ambig_set || ambig_fallback) { + if (print_errors) { + if (ambig_fallback) + fprintf(stderr, "%s: option '%s%s' is ambiguous\n", argv[0], prefix, d->__nextchar); + else { + _lock_file(stderr); + fprintf(stderr, "%s: option '%s%s' is ambiguous; possibilities:", argv[0], prefix, d->__nextchar); + for (option_index = 0; option_index < n_options; option_index++) + if (ambig_set[option_index]) + fprintf(stderr, " '%s%s'", prefix, longopts[option_index].name); + fprintf(stderr, "\n"); + _unlock_file(stderr); + } + } + free(ambig_set); + d->__nextchar += strlen(d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } + option_index = indfound; + } + if (pfound == NULL) { + if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL) { + if (print_errors) + fprintf(stderr, "%s: unrecognized option '%s%s'\n", argv[0], prefix, d->__nextchar); + d->__nextchar = NULL; + d->optind++; + d->optopt = 0; + return '?'; + } + return -1; + } + d->optind++; + d->__nextchar = NULL; + if (*nameend) { + if (pfound->has_arg) + d->optarg = nameend + 1; + else { + if (print_errors) + fprintf(stderr, "%s: option '%s%s' doesn't allow an argument\n", argv[0], prefix, pfound->name); + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else { + if (print_errors) + fprintf(stderr, "%s: option '%s%s' requires an argument\n", argv[0], prefix, pfound->name); + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + if (longind != NULL) + *longind = option_index; + + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; +} + +static const char *_getopt_initialize_a(const char *optstring, struct _getopt_data_a *d, int posixly_correct) { + if (d->optind == 0) + d->optind = 1; + + d->__first_nonopt = d->__last_nonopt = d->optind; + d->__nextchar = NULL; + + if (optstring[0] == '-') { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct | !!getenv("POSIXLY_CORRECT")) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + + d->__initialized = 1; + return optstring; +} + +int _getopt_internal_r_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct); +int _getopt_internal_r_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct) { + int print_errors = d->opterr; + if (argc < 1) + return -1; + d->optarg = NULL; + if (d->optind == 0 || !d->__initialized) + optstring = _getopt_initialize_a(optstring, d, posixly_correct); + else if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + if (optstring[0] == ':') + print_errors = 0; + + if (d->__nextchar == NULL || *d->__nextchar == '\0') { + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + if (d->__ordering == PERMUTE) { + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_a(const_cast(argv), d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) + d->optind++; + d->__last_nonopt = d->optind; + } + if (d->optind != argc && !strcmp(argv[d->optind], "--")) { + d->optind++; + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_a(const_cast(argv), d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + d->optind = argc; + } + if (d->optind == argc) { + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + if (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + if (longopts) { + if (argv[d->optind][1] == '-') { + d->__nextchar = argv[d->optind] + 2; + return process_long_option_a(argc, const_cast(argv), optstring, longopts, longind, long_only, d, print_errors, "--"); + } + if (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1]))) { + int code; + d->__nextchar = argv[d->optind] + 1; + code = process_long_option_a(argc, const_cast(argv), optstring, longopts, + longind, long_only, d, + print_errors, "-"); + if (code != -1) + return code; + } + } + d->__nextchar = argv[d->optind] + 1; + } + { + char c = *d->__nextchar++; + const char *temp = strchr(optstring, c); + if (*d->__nextchar == '\0') + ++d->optind; + if (temp == NULL || c == ':' || c == ';') { + if (print_errors) + fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c); + d->optopt = c; + return '?'; + } + if (temp[0] == 'W' && temp[1] == ';' && longopts != NULL) { + if (*d->__nextchar != '\0') + d->optarg = d->__nextchar; + else if (d->optind == argc) { + if (print_errors) + fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c); + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + d->optarg = argv[d->optind]; + d->__nextchar = d->optarg; + d->optarg = NULL; + return process_long_option_a(argc, const_cast(argv), optstring, longopts, longind, 0, d, print_errors, "-W "); + } + if (temp[1] == ':') { + if (temp[2] == ':') { + if (*d->__nextchar != '\0') { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else { + if (*d->__nextchar != '\0') { + d->optarg = d->__nextchar; + d->optind++; + } + else if (d->optind == argc) { + if (print_errors) + fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c); + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} + +int _getopt_internal_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct); +int _getopt_internal_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct) { + int result; + getopt_data_a.optind = optind; + getopt_data_a.opterr = opterr; + result = _getopt_internal_r_a(argc, argv, optstring, longopts, longind, long_only, &getopt_data_a, posixly_correct); + optind = getopt_data_a.optind; + optarg_a = getopt_data_a.optarg; + optopt = getopt_data_a.optopt; + return result; +} + +int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW { + return _getopt_internal_a(argc, argv, optstring, static_cast(0), static_cast(0), 0, 0); +} + +int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW { + return _getopt_internal_a(argc, argv, options, long_options, opt_index, 0, 0); +} + +int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW { + return _getopt_internal_a(argc, argv, options, long_options, opt_index, 1, 0); +} + +int _getopt_long_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d); +int _getopt_long_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) { + return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 0, d, 0); +} + +int _getopt_long_only_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d); +int _getopt_long_only_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) { + return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 1, d, 0); +} + +// +// +// Unicode Structures and Functions +// +// + +static struct _getopt_data_w { + int optind; + int opterr; + int optopt; + wchar_t *optarg; + int __initialized; + wchar_t *__nextchar; + enum ENUM_ORDERING __ordering; + int __first_nonopt; + int __last_nonopt; +} getopt_data_w; +wchar_t *optarg_w; + +static void exchange_w(wchar_t **argv, struct _getopt_data_w *d) { + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + wchar_t *tem; + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + int len = middle - bottom; + int i; + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + top -= len; + } + else { + int len = top - middle; + int i; + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + bottom += len; + } + } + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} + +static int process_long_option_w(int argc, wchar_t **argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int print_errors, const wchar_t *prefix) { + assert(longopts != NULL); + wchar_t *nameend; + size_t namelen; + const struct option_w *p; + const struct option_w *pfound = NULL; + int n_options; + int option_index = 0; + for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++) + ; + namelen = nameend - d->__nextchar; + for (p = longopts, n_options = 0; p->name; p++, n_options++) + if (!wcsncmp(p->name, d->__nextchar, namelen) && namelen == wcslen(p->name)) { + pfound = p; + option_index = n_options; + break; + } + if (pfound == NULL) { + wchar_t *ambig_set = NULL; + int ambig_fallback = 0; + int indfound = -1; + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!wcsncmp(p->name, d->__nextchar, namelen)) { + if (pfound == NULL) { + pfound = p; + indfound = option_index; + } + else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) { + if (!ambig_fallback) { + if (!print_errors) + ambig_fallback = 1; + + else if (!ambig_set) { + if ((ambig_set = reinterpret_cast(malloc(n_options * sizeof(wchar_t)))) == NULL) + ambig_fallback = 1; + + if (ambig_set) { + memset(ambig_set, 0, n_options * sizeof(wchar_t)); + ambig_set[indfound] = 1; + } + } + if (ambig_set) + ambig_set[option_index] = 1; + } + } + } + if (ambig_set || ambig_fallback) { + if (print_errors) { + if (ambig_fallback) + fwprintf(stderr, L"%s: option '%s%s' is ambiguous\n", argv[0], prefix, d->__nextchar); + else { + _lock_file(stderr); + fwprintf(stderr, L"%s: option '%s%s' is ambiguous; possibilities:", argv[0], prefix, d->__nextchar); + for (option_index = 0; option_index < n_options; option_index++) + if (ambig_set[option_index]) + fwprintf(stderr, L" '%s%s'", prefix, longopts[option_index].name); + fwprintf(stderr, L"\n"); + _unlock_file(stderr); + } + } + free(ambig_set); + d->__nextchar += wcslen(d->__nextchar); + d->optind++; + d->optopt = 0; + return L'?'; + } + option_index = indfound; + } + if (pfound == NULL) { + if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL) { + if (print_errors) + fwprintf(stderr, L"%s: unrecognized option '%s%s'\n", argv[0], prefix, d->__nextchar); + d->__nextchar = NULL; + d->optind++; + d->optopt = 0; + return L'?'; + } + return -1; + } + d->optind++; + d->__nextchar = NULL; + if (*nameend) { + if (pfound->has_arg) + d->optarg = nameend + 1; + else { + if (print_errors) + fwprintf(stderr, L"%s: option '%s%s' doesn't allow an argument\n", argv[0], prefix, pfound->name); + d->optopt = pfound->val; + return L'?'; + } + } + else if (pfound->has_arg == 1) { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else { + if (print_errors) + fwprintf(stderr, L"%s: option '%s%s' requires an argument\n", argv[0], prefix, pfound->name); + d->optopt = pfound->val; + return optstring[0] == L':' ? L':' : L'?'; + } + } + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; +} + +static const wchar_t *_getopt_initialize_w(const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct) { + if (d->optind == 0) + d->optind = 1; + + d->__first_nonopt = d->__last_nonopt = d->optind; + d->__nextchar = NULL; + + if (optstring[0] == L'-') { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == L'+') { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT")) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + + d->__initialized = 1; + return optstring; +} + +int _getopt_internal_r_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct); +int _getopt_internal_r_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct) { + int print_errors = d->opterr; + if (argc < 1) + return -1; + d->optarg = NULL; + if (d->optind == 0 || !d->__initialized) + optstring = _getopt_initialize_w(optstring, d, posixly_correct); + else if (optstring[0] == L'-' || optstring[0] == L'+') + optstring++; + if (optstring[0] == L':') + print_errors = 0; +#define NONOPTION_P (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0') + + if (d->__nextchar == NULL || *d->__nextchar == L'\0') { + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + if (d->__ordering == PERMUTE) { + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_w(const_cast(argv), d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + while (d->optind < argc && NONOPTION_P) + d->optind++; + d->__last_nonopt = d->optind; + } + if (d->optind != argc && !wcscmp(argv[d->optind], L"--")) { + d->optind++; + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_w(const_cast(argv), d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + d->optind = argc; + } + if (d->optind == argc) { + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + if (NONOPTION_P) { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + if (longopts) { + if (argv[d->optind][1] == L'-') { + d->__nextchar = argv[d->optind] + 2; + return process_long_option_w(argc, const_cast(argv), optstring, longopts, longind, long_only, d, print_errors, L"--"); + } + if (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1]))) { + int code; + d->__nextchar = argv[d->optind] + 1; + code = process_long_option_w(argc, const_cast(argv), optstring, longopts, longind, long_only, d, print_errors, L"-"); + if (code != -1) + return code; + } + } + d->__nextchar = argv[d->optind] + 1; + } + { + wchar_t c = *d->__nextchar++; + const wchar_t *temp = wcschr(optstring, c); + if (*d->__nextchar == L'\0') + ++d->optind; + if (temp == NULL || c == L':' || c == L';') { + if (print_errors) + fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c); + d->optopt = c; + return L'?'; + } + if (temp[0] == L'W' && temp[1] == L';' && longopts != NULL) { + if (*d->__nextchar != L'\0') + d->optarg = d->__nextchar; + else if (d->optind == argc) { + if (print_errors) + fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c); + d->optopt = c; + if (optstring[0] == L':') + c = L':'; + else + c = L'?'; + return c; + } + else + d->optarg = argv[d->optind]; + d->__nextchar = d->optarg; + d->optarg = NULL; + return process_long_option_w(argc, const_cast(argv), optstring, longopts, longind, + 0, d, print_errors, L"-W "); + } + if (temp[1] == L':') { + if (temp[2] == L':') { + if (*d->__nextchar != L'\0') { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else { + if (*d->__nextchar != L'\0') { + d->optarg = d->__nextchar; + d->optind++; + } + else if (d->optind == argc) { + if (print_errors) + fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c); + d->optopt = c; + if (optstring[0] == L':') + c = L':'; + else + c = L'?'; + } + else + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} + +int _getopt_internal_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct); +int _getopt_internal_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct) { + int result; + getopt_data_w.optind = optind; + getopt_data_w.opterr = opterr; + result = _getopt_internal_r_w(argc, argv, optstring, longopts, longind, long_only, &getopt_data_w, posixly_correct); + optind = getopt_data_w.optind; + optarg_w = getopt_data_w.optarg; + optopt = getopt_data_w.optopt; + return result; +} + +int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW { + return _getopt_internal_w(argc, argv, optstring, static_cast(0), static_cast(0), 0, 0); +} + +int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW { + return _getopt_internal_w(argc, argv, options, long_options, opt_index, 0, 0); +} + +int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW { + return _getopt_internal_w(argc, argv, options, long_options, opt_index, 1, 0); +} + +int _getopt_long_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d); +int _getopt_long_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) { + return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 0, d, 0); +} + +int _getopt_long_only_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d); +int _getopt_long_only_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) { + return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 1, d, 0); +} \ No newline at end of file diff --git a/3rdparty/getopt/getopt.h b/3rdparty/getopt/getopt.h index 1922a0ef..a9393887 100644 --- a/3rdparty/getopt/getopt.h +++ b/3rdparty/getopt/getopt.h @@ -1,95 +1,135 @@ -#ifndef __GETOPT_H__ -/** - * DISCLAIMER - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the mingw-w64 runtime package. - * - * The mingw-w64 runtime package and its code is distributed in the hope that it - * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR - * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to - * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#define __GETOPT_H__ - -/* All the headers include this file. */ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern int optind; /* index of first non-option in argv */ -extern int optopt; /* single option character, as parsed */ -extern int opterr; /* flag to enable built-in diagnostics... */ - /* (user may set to zero, to suppress) */ - -extern char *optarg; /* pointer to argument of current option */ - -extern int getopt(int nargc, char * const *nargv, const char *options); - -#ifdef _BSD_SOURCE -/* - * BSD adds the non-standard `optreset' feature, for reinitialisation - * of `getopt' parsing. We support this feature, for applications which - * proclaim their BSD heritage, before including this header; however, - * to maintain portability, developers are advised to avoid it. - */ -# define optreset __mingw_optreset -extern int optreset; -#endif -#ifdef __cplusplus -} -#endif -/* - * POSIX requires the `getopt' API to be specified in `unistd.h'; - * thus, `unistd.h' includes this header. However, we do not want - * to expose the `getopt_long' or `getopt_long_only' APIs, when - * included in this manner. Thus, close the standard __GETOPT_H__ - * declarations block, and open an additional __GETOPT_LONG_H__ - * specific block, only when *not* __UNISTD_H_SOURCED__, in which - * to declare the extended API. - */ -#endif /* !defined(__GETOPT_H__) */ - -#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) -#define __GETOPT_LONG_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct option /* specification for a long form option... */ -{ - const char *name; /* option name, without leading hyphens */ - int has_arg; /* does it take an argument? */ - int *flag; /* where to save its status, or NULL */ - int val; /* its associated status value */ -}; - -enum /* permitted values for its `has_arg' field... */ -{ - no_argument = 0, /* option never takes an argument */ - required_argument, /* option always requires an argument */ - optional_argument /* option may take an argument */ -}; - -extern int getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx); -extern int getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx); -/* - * Previous MinGW implementation had... - */ -#ifndef HAVE_DECL_GETOPT -/* - * ...for the long form API only; keep this for compatibility. - */ -# define HAVE_DECL_GETOPT 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ +/* Getopt for Microsoft C +This code is a modification of the Free Software Foundation, Inc. +Getopt library for parsing command line argument the purpose was +to provide a Microsoft Visual C friendly derivative. This code +provides functionality for both Unicode and Multibyte builds. + +Date: 02/03/2011 - Ludvik Jerabek - Initial Release +Version: 1.1 +Comment: Supports getopt, getopt_long, and getopt_long_only +and POSIXLY_CORRECT environment flag +License: LGPL + +Revisions: + +02/03/2011 - Ludvik Jerabek - Initial Release +02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 +07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs +08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception +08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB +02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file +08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi +10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features +06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable +09/24/2022 - Ludvik Jerabek - Updated to match most recent getopt release +09/25/2022 - Ludvik Jerabek - Fixed memory allocation (malloc call) issue for wchar_t* + +**DISCLAIMER** +THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT +APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY +USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST +PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON +YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE +EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +*/ +#ifndef __GETOPT_H_ +#define __GETOPT_H_ + +#ifdef _GETOPT_API +# undef _GETOPT_API +#endif + +#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) +# error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" +#elif defined(STATIC_GETOPT) +# define _GETOPT_API +#elif defined(EXPORTS_GETOPT) +# pragma message("Exporting getopt library") +# define _GETOPT_API __declspec(dllexport) +#else +# pragma message("Importing getopt library") +# define _GETOPT_API __declspec(dllimport) +#endif + +// Change behavior for C\C++ +#ifdef __cplusplus +# define _BEGIN_EXTERN_C extern "C" { +# define _END_EXTERN_C } +# define _GETOPT_THROW throw() +#else +# define _BEGIN_EXTERN_C +# define _END_EXTERN_C +# define _GETOPT_THROW +#endif + +// Standard GNU options +#define null_argument 0 /*Argument Null*/ +#define no_argument 0 /*Argument Switch Only*/ +#define required_argument 1 /*Argument Required*/ +#define optional_argument 2 /*Argument Optional*/ + +// Shorter Options +#define ARG_NULL 0 /*Argument Null*/ +#define ARG_NONE 0 /*Argument Switch Only*/ +#define ARG_REQ 1 /*Argument Required*/ +#define ARG_OPT 2 /*Argument Optional*/ + +#include +#include + +_BEGIN_EXTERN_C + +extern _GETOPT_API int optind; +extern _GETOPT_API int opterr; +extern _GETOPT_API int optopt; + +// Ansi +struct option_a { + const char *name; + int has_arg; + int *flag; + int val; +}; +extern _GETOPT_API char *optarg_a; +extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; +extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; +extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; + +// Unicode +struct option_w { + const wchar_t *name; + int has_arg; + int *flag; + int val; +}; +extern _GETOPT_API wchar_t *optarg_w; +extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; +extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; +extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; + +_END_EXTERN_C + +#undef _BEGIN_EXTERN_C +#undef _END_EXTERN_C +#undef _GETOPT_THROW +#undef _GETOPT_API + +#ifdef _UNICODE +# define getopt getopt_w +# define getopt_long getopt_long_w +# define getopt_long_only getopt_long_only_w +# define option option_w +# define optarg optarg_w +#else +# define getopt getopt_a +# define getopt_long getopt_long_a +# define getopt_long_only getopt_long_only_a +# define option option_a +# define optarg optarg_a +#endif +#endif // __GETOPT_H_ diff --git a/CMakeLists.txt b/CMakeLists.txt index 74884306..f8907f99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,10 +355,11 @@ if(WIN32) endif() endif() -if(WIN32 AND MSVC) +if(WIN32) add_subdirectory(3rdparty/getopt) set(GETOPT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/getopt) set(GETOPT_LIBRARIES getopt) + add_definitions(-DSTATIC_GETOPT -D_UNICODE) endif() if(WIN32 AND NOT MSVC) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 93dde211..9d808450 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1203,12 +1203,12 @@ if(WIN32) target_link_libraries(strawberry_lib PRIVATE dsound dwmapi) if(MSVC) target_link_libraries(strawberry_lib PRIVATE sqlite3) - if (GETOPT_INCLUDE_DIRS) - target_include_directories(strawberry_lib SYSTEM PRIVATE ${GETOPT_INCLUDE_DIRS}) - endif() - if(GETOPT_LIBRARIES) - target_link_libraries(strawberry_lib PRIVATE ${GETOPT_LIBRARIES}) - endif() + endif() + if(GETOPT_INCLUDE_DIRS) + target_include_directories(strawberry_lib SYSTEM PRIVATE ${GETOPT_INCLUDE_DIRS}) + endif() + if(GETOPT_LIBRARIES) + target_link_libraries(strawberry_lib PRIVATE ${GETOPT_LIBRARIES}) endif() endif() diff --git a/src/core/commandlineoptions.cpp b/src/core/commandlineoptions.cpp index 2b9b9f0b..ef62d84c 100644 --- a/src/core/commandlineoptions.cpp +++ b/src/core/commandlineoptions.cpp @@ -22,10 +22,14 @@ #include "version.h" #include -#include #include #include + +#ifdef Q_OS_WIN32 +# include +#endif + #include #include #include @@ -39,6 +43,8 @@ #include "commandlineoptions.h" #include "core/logging.h" +#include + const char *CommandlineOptions::kHelpText = "%1: strawberry [%2] [%3]\n" "\n" @@ -80,7 +86,11 @@ const char *CommandlineOptions::kVersionText = "Strawberry %1"; CommandlineOptions::CommandlineOptions(int argc, char **argv) : argc_(argc), +#ifdef Q_OS_WIN32 + argv_(CommandLineToArgvW(GetCommandLineW(), &argc)), +#else argv_(argv), +#endif url_list_action_(UrlListAction::None), player_action_(PlayerAction::None), set_volume_(-1), @@ -92,6 +102,10 @@ CommandlineOptions::CommandlineOptions(int argc, char **argv) toggle_pretty_osd_(false), log_levels_(logging::kDefaultLogLevels) { +#ifdef Q_OS_WIN32 + Q_UNUSED(argv); +#endif + #ifdef Q_OS_MACOS // Remove -psn_xxx option that Mac passes when opened from Finder. RemoveArg("-psn", 1); @@ -99,12 +113,13 @@ CommandlineOptions::CommandlineOptions(int argc, char **argv) // Remove the -session option that KDE passes RemoveArg("-session", 2); + } void CommandlineOptions::RemoveArg(const QString &starts_with, int count) { for (int i = 0; i < argc_; ++i) { - QString opt(argv_[i]); + const QString opt = OptArgToString(argv_[i]); if (opt.startsWith(starts_with)) { for (int j = i; j < argc_ - count + 1; ++j) { argv_[j] = argv_[j + count]; @@ -119,41 +134,79 @@ void CommandlineOptions::RemoveArg(const QString &starts_with, int count) { bool CommandlineOptions::Parse() { static const struct option kOptions[] = { - {"help", no_argument, nullptr, 'h'}, - {"play", no_argument, nullptr, 'p'}, - {"play-pause", no_argument, nullptr, 't'}, - {"pause", no_argument, nullptr, 'u'}, - {"stop", no_argument, nullptr, 's'}, - {"stop-after-current", no_argument, nullptr, 'q'}, - {"previous", no_argument, nullptr, 'r'}, - {"next", no_argument, nullptr, 'f'}, - {"volume", required_argument, nullptr, 'v'}, - {"volume-up", no_argument, nullptr, LongOptions::VolumeUp}, - {"volume-down", no_argument, nullptr, LongOptions::VolumeDown}, - {"volume-increase-by", required_argument, nullptr, LongOptions::VolumeIncreaseBy}, - {"volume-decrease-by", required_argument, nullptr, LongOptions::VolumeDecreaseBy}, - {"seek-to", required_argument, nullptr, LongOptions::SeekTo}, - {"seek-by", required_argument, nullptr, LongOptions::SeekBy}, - {"restart-or-previous", no_argument, nullptr, LongOptions::RestartOrPrevious}, - {"create", required_argument, nullptr, 'c'}, - {"append", no_argument, nullptr, 'a'}, - {"load", no_argument, nullptr, 'l'}, - {"play-track", required_argument, nullptr, 'k'}, - {"play-playlist", required_argument, nullptr, 'i'}, - {"show-osd", no_argument, nullptr, 'o'}, - {"toggle-pretty-osd", no_argument, nullptr, 'y'}, - {"language", required_argument, nullptr, 'g'}, - {"resize-window", required_argument, nullptr, 'w'}, - {"quiet", no_argument, nullptr, LongOptions::Quiet}, - {"verbose", no_argument, nullptr, LongOptions::Verbose}, - {"log-levels", required_argument, nullptr, LongOptions::LogLevels}, - {"version", no_argument, nullptr, LongOptions::Version}, - {nullptr, 0, nullptr, 0}}; +#ifdef Q_OS_WIN32 + {L"help", no_argument, nullptr, 'h'}, + {L"play", no_argument, nullptr, 'p'}, + {L"play-pause", no_argument, nullptr, 't'}, + {L"pause", no_argument, nullptr, 'u'}, + {L"stop", no_argument, nullptr, 's'}, + {L"stop-after-current", no_argument, nullptr, 'q'}, + {L"previous", no_argument, nullptr, 'r'}, + {L"next", no_argument, nullptr, 'f'}, + {L"volume", required_argument, nullptr, 'v'}, + {L"volume-up", no_argument, nullptr, LongOptions::VolumeUp}, + {L"volume-down", no_argument, nullptr, LongOptions::VolumeDown}, + {L"volume-increase-by", required_argument, nullptr, LongOptions::VolumeIncreaseBy}, + {L"volume-decrease-by", required_argument, nullptr, LongOptions::VolumeDecreaseBy}, + {L"seek-to", required_argument, nullptr, LongOptions::SeekTo}, + {L"seek-by", required_argument, nullptr, LongOptions::SeekBy}, + {L"restart-or-previous", no_argument, nullptr, LongOptions::RestartOrPrevious }, + {L"create", required_argument, nullptr, 'c' }, + {L"append", no_argument, nullptr, 'a' }, + {L"load", no_argument, nullptr, 'l'}, + {L"play-track", required_argument, nullptr, 'k'}, + {L"play-playlist", required_argument, nullptr, 'i'}, + {L"show-osd", no_argument, nullptr, 'o'}, + {L"toggle-pretty-osd", no_argument, nullptr, 'y'}, + {L"language", required_argument, nullptr, 'g'}, + {L"resize-window", required_argument, nullptr, 'w'}, + {L"quiet", no_argument, nullptr, LongOptions::Quiet}, + {L"verbose", no_argument, nullptr, LongOptions::Verbose}, + {L"log-levels", required_argument, nullptr, LongOptions::LogLevels}, + {L"version", no_argument, nullptr, LongOptions::Version}, + {nullptr, 0, nullptr, 0} +#else + { "help", no_argument, nullptr, 'h' }, + { "play", no_argument, nullptr, 'p' }, + { "play-pause", no_argument, nullptr, 't' }, + { "pause", no_argument, nullptr, 'u' }, + { "stop", no_argument, nullptr, 's' }, + { "stop-after-current", no_argument, nullptr, 'q' }, + { "previous", no_argument, nullptr, 'r' }, + { "next", no_argument, nullptr, 'f' }, + { "volume", required_argument, nullptr, 'v' }, + { "volume-up", no_argument, nullptr, LongOptions::VolumeUp }, + { "volume-down", no_argument, nullptr, LongOptions::VolumeDown }, + { "volume-increase-by", required_argument, nullptr, LongOptions::VolumeIncreaseBy }, + { "volume-decrease-by", required_argument, nullptr, LongOptions::VolumeDecreaseBy }, + { "seek-to", required_argument, nullptr, LongOptions::SeekTo }, + { "seek-by", required_argument, nullptr, LongOptions::SeekBy }, + { "restart-or-previous", no_argument, nullptr, LongOptions::RestartOrPrevious }, + { "create", required_argument, nullptr, 'c' }, + { "append", no_argument, nullptr, 'a' }, + { "load", no_argument, nullptr, 'l' }, + { "play-track", required_argument, nullptr, 'k' }, + { "play-playlist", required_argument, nullptr, 'i' }, + { "show-osd", no_argument, nullptr, 'o' }, + { "toggle-pretty-osd", no_argument, nullptr, 'y' }, + { "language", required_argument, nullptr, 'g' }, + { "resize-window", required_argument, nullptr, 'w' }, + { "quiet", no_argument, nullptr, LongOptions::Quiet }, + { "verbose", no_argument, nullptr, LongOptions::Verbose }, + { "log-levels", required_argument, nullptr, LongOptions::LogLevels }, + { "version", no_argument, nullptr, LongOptions::Version }, + { nullptr, 0, nullptr, 0 } +#endif +}; // Parse the arguments bool ok = false; forever { +#ifdef Q_OS_WIN32 + int c = getopt_long(argc_, argv_, L"hptusqrfv:c:alk:i:oyg:w:", kOptions, nullptr); +#else int c = getopt_long(argc_, argv_, "hptusqrfv:c:alk:i:oyg:w:", kOptions, nullptr); +#endif // End of the options if (c == -1) break; @@ -162,36 +215,36 @@ bool CommandlineOptions::Parse() { case 'h': { QString translated_help_text = QString(kHelpText) - .arg(tr("Usage"), tr("options"), tr("URL(s)"), - tr("Player options"), - tr("Start the playlist currently playing"), - tr("Play if stopped, pause if playing"), - tr("Pause playback"), tr("Stop playback"), - tr("Stop playback after current track")) - .arg(tr("Skip backwards in playlist"), - tr("Skip forwards in playlist"), - tr("Set the volume to percent"), - tr("Increase the volume by 4 percent"), - tr("Decrease the volume by 4 percent"), - tr("Increase the volume by percent"), - tr("Decrease the volume by percent")) - .arg(tr("Seek the currently playing track to an absolute position"), - tr("Seek the currently playing track by a relative amount"), - tr("Restart the track, or play the previous track if within 8 seconds of start."), - tr("Playlist options"), - tr("Create a new playlist with files"), - tr("Append files/URLs to the playlist"), - tr("Loads files/URLs, replacing current playlist"), - tr("Play the th track in the playlist"), - tr("Play given playlist")) - .arg(tr("Other options"), tr("Display the on-screen-display"), - tr("Toggle visibility for the pretty on-screen-display"), - tr("Change the language"), - tr("Resize the window"), - tr("Equivalent to --log-levels *:1"), - tr("Equivalent to --log-levels *:3"), - tr("Comma separated list of class:level, level is 0-3")) - .arg(tr("Print out version information")); + .arg(QObject::tr("Usage"), QObject::tr("options"), QObject::tr("URL(s)"), + QObject::tr("Player options"), + QObject::tr("Start the playlist currently playing"), + QObject::tr("Play if stopped, pause if playing"), + QObject::tr("Pause playback"), QObject::tr("Stop playback"), + QObject::tr("Stop playback after current track")) + .arg(QObject::tr("Skip backwards in playlist"), + QObject::tr("Skip forwards in playlist"), + QObject::tr("Set the volume to percent"), + QObject::tr("Increase the volume by 4 percent"), + QObject::tr("Decrease the volume by 4 percent"), + QObject::tr("Increase the volume by percent"), + QObject::tr("Decrease the volume by percent")) + .arg(QObject::tr("Seek the currently playing track to an absolute position"), + QObject::tr("Seek the currently playing track by a relative amount"), + QObject::tr("Restart the track, or play the previous track if within 8 seconds of start."), + QObject::tr("Playlist options"), + QObject::tr("Create a new playlist with files"), + QObject::tr("Append files/URLs to the playlist"), + QObject::tr("Loads files/URLs, replacing current playlist"), + QObject::tr("Play the th track in the playlist"), + QObject::tr("Play given playlist")) + .arg(QObject::tr("Other options"), QObject::tr("Display the on-screen-display"), + QObject::tr("Toggle visibility for the pretty on-screen-display"), + QObject::tr("Change the language"), + QObject::tr("Resize the window"), + QObject::tr("Equivalent to --log-levels *:1"), + QObject::tr("Equivalent to --log-levels *:3"), + QObject::tr("Comma separated list of class:level, level is 0-3")) + .arg(QObject::tr("Print out version information")); std::cout << translated_help_text.toLocal8Bit().constData(); return false; @@ -220,11 +273,11 @@ bool CommandlineOptions::Parse() { break; case 'i': player_action_ = PlayerAction::PlayPlaylist; - playlist_name_ = QString(optarg); + playlist_name_ = OptArgToString(optarg); break; case 'c': url_list_action_ = UrlListAction::CreateNew; - playlist_name_ = QString(optarg); + playlist_name_ = OptArgToString(optarg); break; case 'a': url_list_action_ = UrlListAction::Append; @@ -239,7 +292,7 @@ bool CommandlineOptions::Parse() { toggle_pretty_osd_ = true; break; case 'g': - language_ = QString(optarg); + language_ = OptArgToString(optarg); break; case LongOptions::VolumeUp: volume_modifier_ = +4; @@ -254,7 +307,7 @@ bool CommandlineOptions::Parse() { log_levels_ = "3"; break; case LongOptions::LogLevels: - log_levels_ = QString(optarg); + log_levels_ = OptArgToString(optarg); break; case LongOptions::Version: { QString version_text = QString(kVersionText).arg(STRAWBERRY_VERSION_DISPLAY); @@ -262,27 +315,27 @@ bool CommandlineOptions::Parse() { std::exit(0); } case 'v': - set_volume_ = QString(optarg).toInt(&ok); + set_volume_ = OptArgToString(optarg).toInt(&ok); if (!ok) set_volume_ = -1; break; case LongOptions::VolumeIncreaseBy: - volume_modifier_ = QString(optarg).toInt(&ok); + volume_modifier_ = OptArgToString(optarg).toInt(&ok); if (!ok) volume_modifier_ = 0; break; case LongOptions::VolumeDecreaseBy: - volume_modifier_ = -QString(optarg).toInt(&ok); + volume_modifier_ = -OptArgToString(optarg).toInt(&ok); if (!ok) volume_modifier_ = 0; break; case LongOptions::SeekTo: - seek_to_ = QString(optarg).toInt(&ok); + seek_to_ = OptArgToString(optarg).toInt(&ok); if (!ok) seek_to_ = -1; break; case LongOptions::SeekBy: - seek_by_ = QString(optarg).toInt(&ok); + seek_by_ = OptArgToString(optarg).toInt(&ok); if (!ok) seek_by_ = 0; break; @@ -291,12 +344,12 @@ bool CommandlineOptions::Parse() { break; case 'k': - play_track_at_ = QString(optarg).toInt(&ok); + play_track_at_ = OptArgToString(optarg).toInt(&ok); if (!ok) play_track_at_ = -1; break; case 'w': - window_size_ = QString(optarg); + window_size_ = OptArgToString(optarg); player_action_ = PlayerAction::ResizeWindow; break; @@ -308,10 +361,10 @@ bool CommandlineOptions::Parse() { // Get any filenames or URLs following the arguments for (int i = optind; i < argc_; ++i) { - QString value = QFile::decodeName(argv_[i]); - QFileInfo file_info(value); - if (file_info.exists()) { - urls_ << QUrl::fromLocalFile(file_info.canonicalFilePath()); + const QString value = DecodeName(argv_[i]); + QFileInfo fileinfo(value); + if (fileinfo.exists()) { + urls_ << QUrl::fromLocalFile(fileinfo.canonicalFilePath()); } else { urls_ << QUrl::fromUserInput(value); @@ -362,10 +415,30 @@ void CommandlineOptions::Load(const QByteArray &serialized) { } -QString CommandlineOptions::tr(const char *source_text) { - return QObject::tr(source_text); // clazy:exclude=tr-non-literal +#ifdef Q_OS_WIN32 +QString CommandlineOptions::OptArgToString(wchar_t *opt) { + + return QString::fromWCharArray(opt); + } +QString CommandlineOptions::DecodeName(wchar_t *opt) { + + return QString::fromWCharArray(opt); +} +#else +QString CommandlineOptions::OptArgToString(char *opt) { + + return QString(opt); +} + +QString CommandlineOptions::DecodeName(char *opt) { + + return QFile::decodeName(opt); + +} +#endif + QDataStream &operator<<(QDataStream &s, const CommandlineOptions &a) { s << static_cast(a.player_action_) diff --git a/src/core/commandlineoptions.h b/src/core/commandlineoptions.h index 73ad040b..c1c338eb 100644 --- a/src/core/commandlineoptions.h +++ b/src/core/commandlineoptions.h @@ -23,12 +23,17 @@ #include "config.h" +#include #include #include #include #include #include +#ifdef Q_OS_WIN32 +# include +#endif + class CommandlineOptions { friend QDataStream &operator<<(QDataStream &s, const CommandlineOptions &a); friend QDataStream &operator>>(QDataStream &s, CommandlineOptions &a); @@ -100,12 +105,23 @@ class CommandlineOptions { RestartOrPrevious }; - static QString tr(const char *source_text); void RemoveArg(const QString &starts_with, int count); +#ifdef Q_OS_WIN32 + static QString OptArgToString(wchar_t *opt); + static QString DecodeName(wchar_t *opt); +#else + static QString OptArgToString(char *opt); + static QString DecodeName(char *opt); +#endif + private: int argc_; +#ifdef Q_OS_WIN32 + LPWSTR *argv_; +#else char **argv_; +#endif UrlListAction url_list_action_; PlayerAction player_action_;