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