cmd: Detect and handle start console title.
Bas Weelinck
bas.weelinck at gmail.com
Sun Mar 19 15:00:02 CDT 2017
Fixes: https://bugs.winehq.org/show_bug.cgi?id=42508
Implements proper start built-in console title detection
and handling in a way that will not break anything relying
on the separate 'start.exe' binary behaviour that is present in
wine but not in modern day Windows.
This code will break if WCMD_parameter_with_delims ever starts
handling quote escapes, which I for now assume it is designed not to.
Patch tested on Gentoo Linux.
Original start behaviour tested on Windows XP and Windows 7.
Signed-off-by: Bas Weelinck <bas.weelinck at gmail.com>
---
programs/cmd/builtins.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++--
programs/cmd/wcmd.h | 2 +-
2 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 7301f54..1da1f67 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -4311,10 +4311,15 @@ void WCMD_shift (const WCHAR *args) {
/****************************************************************************
* WCMD_start
*/
-void WCMD_start(const WCHAR *args)
+void WCMD_start(WCHAR *args)
{
static const WCHAR exeW[] = {'\\','c','o','m','m','a','n','d',
'\\','s','t','a','r','t','.','e','x','e',0};
+ static const WCHAR startDelims[] = { ' ', '\t', '/', '\0' };
+ static const WCHAR prefixQuote[] = {'"','\\','"','\0'};
+ static const WCHAR postfixQuote[] = {'\\','"','"','\0'};
+ int argno;
+ int have_title;
WCHAR file[MAX_PATH];
WCHAR *cmdline;
STARTUPINFOW st;
@@ -4322,10 +4327,90 @@ void WCMD_start(const WCHAR *args)
GetWindowsDirectoryW( file, MAX_PATH );
strcatW( file, exeW );
- cmdline = heap_alloc( (strlenW(file) + strlenW(args) + 2) * sizeof(WCHAR) );
+ cmdline = heap_alloc( (strlenW(file) + strlenW(args) + 8) * sizeof(WCHAR) );
strcpyW( cmdline, file );
strcatW( cmdline, spaceW );
- strcatW( cmdline, args );
+
+ /* The start built-in has some special command-line parsing properties
+ * which will be outlined here.
+ *
+ * both '\t' and ' ' are argument separators
+ * '/' has a special double role as both separator and switch prefix, e.g.
+ *
+ * > start /low/i
+ * or
+ * > start "title"/i
+ *
+ * are valid ways to pass multiple options to start. In the latter case
+ * '/i' is not a part of the title but parsed as a switch.
+ *
+ * However, '=', ';' and ',' are not separators:
+ * > start "deus"=ex,machina
+ *
+ * will in fact open a console titled 'deus=ex,machina'
+ *
+ * The title argument parsing code is only interested in quotes themselves,
+ * it does not respect escaping of any kind and all quotes are dropped
+ * from the resulting title, therefore:
+ *
+ * > start "\"" hello"/low
+ *
+ * actually opens a console titled '\ hello' with low priorities.
+ *
+ * To not break compatibility with wine programs relying on
+ * wine's separate 'start.exe', this program's peculiar console
+ * title parsing is actually implemented in 'cmd.exe' which is the
+ * application native Windows programs will use to invoke 'start'.
+ *
+ * WCMD_parameter_with_delims will take care of everything for us.
+ */
+ have_title = FALSE;
+ for (argno=0; ; argno++) {
+ WCHAR *thisArg, *argN;
+
+ argN = NULL;
+ thisArg = WCMD_parameter_with_delims(args, argno, &argN, FALSE, FALSE, startDelims);
+
+ /* No more parameters */
+ if (!argN)
+ break;
+
+ /* Found the title */
+ if (argN[0] == '"') {
+ TRACE("detected console title: %s\n", wine_dbgstr_w(thisArg));
+ have_title = TRUE;
+
+ /* Copy all of the cmdline processed */
+ memcpy(cmdline, args, sizeof(WCHAR) * (argN - args));
+ cmdline[argN - args] = '\0';
+
+ /* Add quoted title */
+ strcatW(cmdline, prefixQuote);
+ strcatW(cmdline, thisArg);
+ strcatW(cmdline, postfixQuote);
+
+ /* Concatenate remaining command-line */
+ thisArg = WCMD_parameter_with_delims(args, argno, &argN, TRUE, FALSE, startDelims);
+ strcatW(cmdline, argN + strlenW(thisArg));
+
+ break;
+ }
+
+ /* Skipping a regular argument? */
+ else if (argN != args && argN[-1] == '/') {
+ continue;
+
+ /* Not an argument nor the title, start of program arguments,
+ * stop looking for title.
+ */
+ } else
+ break;
+ }
+
+ /* build command-line if not built yet */
+ if (!have_title) {
+ strcatW( cmdline, args );
+ }
memset( &st, 0, sizeof(STARTUPINFOW) );
st.cb = sizeof(STARTUPINFOW);
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index c135621..1180251 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -95,7 +95,7 @@ void WCMD_setshow_path (const WCHAR *args);
void WCMD_setshow_prompt (void);
void WCMD_setshow_time (void);
void WCMD_shift (const WCHAR *args);
-void WCMD_start (const WCHAR *args);
+void WCMD_start (WCHAR *args);
void WCMD_title (const WCHAR *);
void WCMD_type (WCHAR *);
void WCMD_verify (const WCHAR *args);
--
2.10.2
More information about the wine-patches
mailing list