[PATCH 1/3] cmd: Add CHOICE builtin with DOS6 to XP commandline parameter

Detlef Riekenberg wine.dev at web.de
Tue Dec 14 16:59:35 CST 2010


This fixes http://bugs.winehq.org/show_bug.cgi?id=21173

The example script in the bug need another patch.

--
By by ... Detlef
---
 programs/cmd/En.rc      |    5 ++
 programs/cmd/builtins.c |  172 +++++++++++++++++++++++++++++++++++++++++++++++
 programs/cmd/wcmd.h     |    4 +-
 programs/cmd/wcmdmain.c |    4 +
 4 files changed, 184 insertions(+), 1 deletions(-)

diff --git a/programs/cmd/En.rc b/programs/cmd/En.rc
index 2e32c1c..87b0780 100644
--- a/programs/cmd/En.rc
+++ b/programs/cmd/En.rc
@@ -211,6 +211,10 @@ PUSHD.\n"
 
   WCMD_MORE,   "MORE displays output of files or piped input in pages.\n"
 
+  WCMD_CHOICE, "CHOICE displays a text and waits, until the User\n\
+press an allowed Key from a selectable list.\n\
+CHOICE is mainly used to build a menu selection in a batch file.\n"
+
   WCMD_EXIT,
 "EXIT terminates the current command session and returns\n\
 to the operating system or shell from which you invoked cmd.\n"
@@ -219,6 +223,7 @@ to the operating system or shell from which you invoked cmd.\n"
 ATTRIB\t\tShow or change DOS file attributes\n\
 CALL\t\tInvoke a batch file from inside another\n\
 CD (CHDIR)\tChange current default directory\n\
+CHOICE\t\tWait for an keypress from a selectable list\n\
 CLS\t\tClear the console screen\n\
 COPY\t\tCopy file\n\
 CTTY\t\tChange input/output device\n\
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 8c3f727..e18d328 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -160,6 +160,178 @@ void WCMD_change_tty (void) {
 }
 
 /****************************************************************************
+ * WCMD_choice
+ *
+ */
+
+void WCMD_choice (WCHAR * command) {
+
+    static const WCHAR bellW[] = {7,0};
+    static const WCHAR commaW[] = {',',0};
+    static const WCHAR bracket_open[] = {'[',0};
+    static const WCHAR bracket_close[] = {']','?',0};
+    WCHAR answer[16];
+    WCHAR buffer[16];
+    WCHAR *ptr = NULL;
+    WCHAR *opt_c = NULL;
+    WCHAR *my_command = NULL;
+    WCHAR opt_default = 0;
+    DWORD opt_timeout = 0;
+    DWORD count;
+    DWORD oldmode;
+    DWORD have_console;
+    BOOL opt_n = FALSE;
+    BOOL opt_s = FALSE;
+
+    have_console = GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &oldmode);
+    errorlevel = 0;
+    answer[1] = 0;
+
+    my_command = WCMD_strdupW(WCMD_strtrim_leading_spaces(command));
+    ptr = my_command;
+    while (*ptr == '/') {
+        switch (toupperW(ptr[1])) {
+            case 'C':
+                ptr += 2;
+                /* The colomn is optional */
+                if (*ptr == ':')
+                    ptr++;
+
+                if (!*ptr || isspaceW(*ptr)) {
+                    WINE_FIXME("bad parameter %s for /C\n", wine_dbgstr_w(ptr));
+                    return;
+                }
+
+                /* remember the allowed keys */
+                opt_c = ptr;
+                while (*ptr && (!isspaceW(*ptr)))
+                    ptr++;
+
+                if (*ptr) {
+                    /* terminate allowed chars */
+                    *ptr = 0;
+                    ptr = WCMD_strtrim_leading_spaces(&ptr[1]);
+                }
+                WINE_TRACE("answer-list: %s\n", wine_dbgstr_w(opt_c));
+                break;
+
+            case 'N':
+                opt_n = TRUE;
+                ptr = WCMD_strtrim_leading_spaces(&ptr[2]);
+                break;
+
+            case 'S':
+                opt_s = TRUE;
+                ptr = WCMD_strtrim_leading_spaces(&ptr[2]);
+                break;
+
+            case 'T':
+                ptr = &ptr[2];
+                /* The colomn is optional */
+                if (*ptr == ':')
+                    ptr++;
+
+                opt_default = *ptr++;
+
+                if (!opt_default || (*ptr != ',')) {
+                    WINE_FIXME("bad parameter %s for /T\n", wine_dbgstr_w(ptr));
+                    HeapFree(GetProcessHeap(), 0, my_command);
+                    return;
+                }
+                ptr++;
+
+                count = 0;
+                while (((answer[count] = *ptr)) && isdigitW(*ptr) && (count < 16)) {
+                    count++;
+                    ptr++;
+                }
+
+                answer[count] = 0;
+                opt_timeout = atoiW(answer);
+
+                ptr = WCMD_strtrim_leading_spaces(ptr);
+                break;
+
+        }
+    }
+
+    if (opt_timeout)
+        WINE_FIXME("timeout not supported: %c,%d\n", opt_default, opt_timeout);
+
+
+    if (have_console)
+        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), 0);
+
+    /* use default keys, when needed: localized versions of "Y"es and "No" */
+    if (!opt_c) {
+        LoadStringW(hinst, WCMD_YES, buffer, sizeof(buffer)/sizeof(WCHAR));
+        LoadStringW(hinst, WCMD_NO, buffer + 1, sizeof(buffer)/sizeof(WCHAR) - 1);
+        opt_c = buffer;
+        buffer[2] = 0;
+    }
+
+    /* print the question, when needed */
+    if (ptr && *ptr)
+        WCMD_output_asis(ptr);
+
+    if (!opt_s) {
+        struprW(opt_c);
+        WINE_TRACE("case insensitive answer-list: %s\n", wine_dbgstr_w(opt_c));
+    }
+
+    if (!opt_n) {
+        /* print a list of all allowed answers inside brackets */
+        WCMD_output_asis(bracket_open);
+        ptr = opt_c;
+        answer[1] = 0;
+        while ((answer[0] = *ptr++)) {
+            WCMD_output_asis(answer);
+            if (*ptr)
+                WCMD_output_asis(commaW);
+        }
+        WCMD_output_asis(bracket_close);
+    }
+
+    while (!errorlevel) {
+        count = 0;
+        while (!count){
+            /* FIXME: Add support for option /T */
+            WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, 1, &count, NULL);
+            if (!count) {
+                WINE_TRACE("no more data from stdin\n");
+                if (have_console)
+                    SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldmode);
+
+                HeapFree(GetProcessHeap(), 0, my_command);
+                return;
+            }
+        }
+        if (!opt_s)
+            answer[0] = toupperW(answer[0]);
+
+        ptr = strchrW(opt_c, answer[0]);
+        if (ptr) {
+            WCMD_output_asis(answer);
+            WCMD_output(newline);
+            if (have_console)
+                SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldmode);
+
+            errorlevel = (ptr - opt_c) + 1;
+            WINE_TRACE("answer: %d\n", errorlevel);
+            HeapFree(GetProcessHeap(), 0, my_command);
+            return;
+        }
+        else
+        {
+            /* key not allowed: play a bell */
+            WINE_TRACE("key not allowed: %s\n", wine_dbgstr_w(answer));
+            WCMD_output_asis(bellW);
+        }
+    }
+    /* This location is never reached */
+}
+
+/****************************************************************************
  * WCMD_copy
  *
  * Copy a file or wildcarded set.
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 2fde678..ce4c2da 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -52,6 +52,7 @@ void WCMD_assoc (WCHAR *, BOOL);
 void WCMD_batch (WCHAR *, WCHAR *, int, WCHAR *, HANDLE);
 void WCMD_call (WCHAR *command);
 void WCMD_change_tty (void);
+void WCMD_choice (WCHAR *);
 void WCMD_clear_screen (void);
 void WCMD_color (void);
 void WCMD_copy (void);
@@ -202,9 +203,10 @@ typedef struct _DIRECTORY_STACK
 #define WCMD_COLOR  41
 #define WCMD_FTYPE  42
 #define WCMD_MORE   43
+#define WCMD_CHOICE 44
 
 /* Must be last in list */
-#define WCMD_EXIT   44
+#define WCMD_EXIT   45
 
 /* Some standard messages */
 extern const WCHAR newline[];
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 85f78b8..7b7ce8f 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -76,6 +76,7 @@ const WCHAR inbuilt[][10] = {
         {'C','O','L','O','R','\0'},
         {'F','T','Y','P','E','\0'},
         {'M','O','R','E','\0'},
+        {'C','H','O','I','C','E','\0'},
         {'E','X','I','T','\0'}
 };
 
@@ -1543,6 +1544,9 @@ void WCMD_execute (WCHAR *command, WCHAR *redirects,
       case WCMD_MORE:
         WCMD_more(p);
         break;
+      case WCMD_CHOICE:
+        WCMD_choice(p);
+        break;
       case WCMD_EXIT:
         WCMD_exit (cmdList);
         break;
-- 
1.7.1




More information about the wine-patches mailing list