Andrew Nguyen : dxdiag: Improve the command-line parsing.

Alexandre Julliard julliard at winehq.org
Mon Jun 13 11:49:18 CDT 2011


Module: wine
Branch: master
Commit: 1cd007fa99278a97cec5c05f06b6914a4ed407ad
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=1cd007fa99278a97cec5c05f06b6914a4ed407ad

Author: Andrew Nguyen <anguyen at codeweavers.com>
Date:   Mon Jun 13 07:13:12 2011 -0500

dxdiag: Improve the command-line parsing.

---

 programs/dxdiag/main.c |  151 +++++++++++++++++++++++++++++++++---------------
 1 files changed, 104 insertions(+), 47 deletions(-)

diff --git a/programs/dxdiag/main.c b/programs/dxdiag/main.c
index 4e73b4b..3b89b19 100644
--- a/programs/dxdiag/main.c
+++ b/programs/dxdiag/main.c
@@ -25,71 +25,128 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
 
+struct command_line_info
+{
+    WCHAR outfile[MAX_PATH];
+    BOOL whql_check;
+};
+
+static void usage(void)
+{
+    WINE_FIXME("Usage message box is not implemented\n");
+    ExitProcess(0);
+}
+
+static BOOL process_file_name(const WCHAR *cmdline, WCHAR *filename, size_t filename_len)
+{
+    const WCHAR *endptr;
+    size_t len;
+
+    /* Skip any intervening spaces. */
+    while (*cmdline == ' ')
+        cmdline++;
+
+    /* Ignore filename quoting, if any. */
+    if (*cmdline == '"' && (endptr = strrchrW(cmdline, '"')))
+    {
+        /* Reject a string with only one quote. */
+        if (cmdline == endptr)
+            return FALSE;
+
+        cmdline++;
+    }
+    else
+        endptr = cmdline + strlenW(cmdline);
+
+    len = endptr - cmdline;
+    if (len == 0 || len >= filename_len)
+        return FALSE;
+
+    memcpy(filename, cmdline, len * sizeof(WCHAR));
+    filename[len] = '\0';
+
+    return TRUE;
+}
+
 /*
-    Process options [/WHQL:ON|OFF][/X outfile][/T outfile]
+    Process options [/WHQL:ON|OFF][/X outfile|/T outfile]
     Returns TRUE if options were present, FALSE otherwise
-    FIXME: Native behavior seems to be:
     Only one of /X and /T is allowed, /WHQL must come before /X and /T,
-    quotes are optional around the filename, even if it contains spaces.
+    and the rest of the command line after /X or /T is interpreted as a
+    filename. If a non-option portion of the command line is encountered,
+    dxdiag assumes that the string is a filename for the /T option.
+
+    Native does not interpret quotes, but quotes are parsed here because of how
+    Wine handles the command line.
 */
 
-static BOOL ProcessCommandLine(const WCHAR *s)
+static BOOL process_command_line(const WCHAR *cmdline, struct command_line_info *info)
 {
-    WCHAR outfile[MAX_PATH+1];
-    int opt_t = FALSE;
-    int opt_x = FALSE;
-    int opt_help = FALSE;
-    int opt_given = FALSE;
-    int want_arg = FALSE;
-
-    outfile[0] = 0;
-    while (*s) {
+    static const WCHAR whql_colonW[] = {'w','h','q','l',':',0};
+    static const WCHAR offW[] = {'o','f','f',0};
+    static const WCHAR onW[] = {'o','n',0};
+
+    info->whql_check = FALSE;
+
+    while (*cmdline)
+    {
         /* Skip whitespace before arg */
-        while (*s == ' ')
-            s++;
-        /* Check for option */
-        if (*s != '-' && *s != '/')
-            return FALSE;
-        s++;
-        switch (*s++) {
+        while (*cmdline == ' ')
+            cmdline++;
+
+        /* If no option is specified, treat the command line as a filename. */
+        if (*cmdline != '-' && *cmdline != '/')
+            return process_file_name(cmdline, info->outfile, sizeof(info->outfile)/sizeof(WCHAR));
+
+        cmdline++;
+
+        switch (*cmdline)
+        {
         case 'T':
-        case 't': opt_t = TRUE; want_arg = TRUE; opt_given = TRUE; break;
+        case 't':
+            return process_file_name(cmdline + 1, info->outfile, sizeof(info->outfile)/sizeof(WCHAR));
         case 'X':
-        case 'x': opt_x = TRUE; want_arg = TRUE; opt_given = TRUE; break;
+        case 'x':
+            return process_file_name(cmdline + 1, info->outfile, sizeof(info->outfile)/sizeof(WCHAR));
         case 'W':
         case 'w':
-            opt_given = TRUE;
-            while (isalphaW(*s) || *s == ':')
-                s++;
-            break;
-        default: opt_help = TRUE; opt_given = TRUE; break;
-        }
-        /* Skip any spaces before next option or filename */
-        while (*s == ' ')
-            s++;
-        if (want_arg) {
-            int i;
-            if (*s == '"')
-                s++;
-            for (i=0; i < MAX_PATH && *s && *s != '"'; i++, s++)
-                outfile[i] = *s;
-            outfile[i] = 0;
+            if (strncmpiW(cmdline, whql_colonW, 5))
+                return FALSE;
+
+            cmdline += 5;
+
+            if (!strncmpiW(cmdline, offW, 3))
+            {
+                info->whql_check = FALSE;
+                cmdline += 2;
+            }
+            else if (!strncmpiW(cmdline, onW, 2))
+            {
+                info->whql_check = TRUE;
+                cmdline++;
+            }
+            else
+                return FALSE;
+
             break;
+        default:
+            return FALSE;
         }
+
+        cmdline++;
     }
-    if (opt_help)
-        WINE_FIXME("help unimplemented\n");
-    if (opt_t)
-        WINE_FIXME("/t unimplemented\n");
-    if (opt_x)
-        WINE_FIXME("/x unimplemented\n");
-    return opt_given;
+
+    return TRUE;
 }
 
 int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow)
 {
-    if (ProcessCommandLine(cmdline))
-        return 0;
+    struct command_line_info info;
+
+    if (!process_command_line(cmdline, &info))
+        usage();
+
+    WINE_TRACE("WHQL check: %s\n", info.whql_check ? "TRUE" : "FALSE");
 
     return 0;
 }




More information about the wine-cvs mailing list