Alexandre Julliard : tools: Implement a replacement for getopt_long().
Alexandre Julliard
julliard at winehq.org
Tue Oct 5 15:51:41 CDT 2021
Module: wine
Branch: master
Commit: 9c4cbde78fa6357aec1c235265d92ea2cdbb69e7
URL: https://source.winehq.org/git/wine.git/?a=commit;h=9c4cbde78fa6357aec1c235265d92ea2cdbb69e7
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Oct 5 11:51:57 2021 +0200
tools: Implement a replacement for getopt_long().
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
tools/tools.h | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/winedump/main.c | 6 +--
2 files changed, 113 insertions(+), 3 deletions(-)
diff --git a/tools/tools.h b/tools/tools.h
index 8b658079952..f013bf7a510 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -310,4 +310,114 @@ static inline int make_temp_file( const char *prefix, const char *suffix, char *
exit(1);
}
+
+/* command-line option parsing */
+/* partly based on the Glibc getopt() implementation */
+
+struct long_option
+{
+ const char *name;
+ int has_arg;
+ int val;
+};
+
+static inline struct strarray parse_options( int argc, char **argv, const char *short_opts,
+ const struct long_option *long_opts, int long_only,
+ void (*callback)( int, char* ) )
+{
+ struct strarray ret = empty_strarray;
+ const char *flag;
+ char *start, *end;
+ int i;
+
+#define OPT_ERR(fmt) { callback( '?', strmake( fmt, argv[1] )); continue; }
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] != '-' || !argv[i][1]) /* not an option */
+ {
+ strarray_add( &ret, argv[i] );
+ continue;
+ }
+ if (!strcmp( argv[i], "--" ))
+ {
+ /* add remaining args */
+ while (++i < argc) strarray_add( &ret, argv[i] );
+ break;
+ }
+ start = argv[i] + 1 + (argv[i][1] == '-');
+
+ if (argv[i][1] == '-' || (long_only && (argv[i][2] || !strchr( short_opts, argv[i][1] ))))
+ {
+ /* handle long option */
+ const struct long_option *opt, *found = NULL;
+ int count = 0;
+
+ if (!(end = strchr( start, '=' ))) end = start + strlen(start);
+ for (opt = long_opts; opt && opt->name; opt++)
+ {
+ if (strncmp( opt->name, start, end - start )) continue;
+ if (!opt->name[end - start]) /* exact match */
+ {
+ found = opt;
+ count = 1;
+ break;
+ }
+ if (!found)
+ {
+ found = opt;
+ count++;
+ }
+ else if (long_only || found->has_arg != opt->has_arg || found->val != opt->val)
+ {
+ count++;
+ }
+ }
+
+ if (count > 1) OPT_ERR( "option '%s' is ambiguous" );
+
+ if (found)
+ {
+ if (*end)
+ {
+ if (!found->has_arg) OPT_ERR( "argument not allowed in '%s'" );
+ end++; /* skip '=' */
+ }
+ else if (found->has_arg == 1)
+ {
+ if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
+ end = argv[++i];
+ }
+ else end = NULL;
+
+ callback( found->val, end );
+ continue;
+ }
+ if (argv[i][1] == '-' || !long_only || !strchr( short_opts, argv[i][1] ))
+ OPT_ERR( "unrecognized option '%s'" );
+ }
+
+ /* handle short option */
+ for ( ; *start; start++)
+ {
+ if (!(flag = strchr( short_opts, *start ))) OPT_ERR( "invalid option '%s'" );
+ if (flag[1] == ':')
+ {
+ end = start + 1;
+ if (!*end) end = NULL;
+ if (flag[2] != ':' && !end)
+ {
+ if (i == argc - 1) OPT_ERR( "option '%s' requires an argument" );
+ end = argv[++i];
+ }
+ callback( *start, end );
+ break;
+ }
+ callback( *start, NULL );
+ }
+ }
+ return ret;
+#undef OPT_ERR
+}
+
#endif /* __WINE_TOOLS_H */
diff --git a/tools/winedump/main.c b/tools/winedump/main.c
index 818180e6d8c..b60868d0d89 100644
--- a/tools/winedump/main.c
+++ b/tools/winedump/main.c
@@ -257,11 +257,11 @@ void do_usage (const char *arg)
/*******************************************************************
- * parse_options
+ * parse_cmdline
*
* Parse options from the argv array
*/
-static void parse_options (char *argv[])
+static void parse_cmdline (char *argv[])
{
const struct my_option *opt;
char *const *ptr;
@@ -388,7 +388,7 @@ int main (int argc, char *argv[])
globals.input_name = NULL;
globals.dumpsect = NULL;
- parse_options (argv);
+ parse_cmdline (argv);
memset (&symbol, 0, sizeof (parsed_symbol));
More information about the wine-cvs
mailing list