start: Fix the command line handling.
Francois Gouget
fgouget at free.fr
Wed Jun 27 02:19:58 CDT 2012
- The options don't have short or long forms and cannot be concatenated.
- Add support for specifying the title.
- Add support for setting the new process directory with the /d option.
- Add support for the options setting the new process priority.
- Implement the /b option which disables the creation of a new console.
- Recognize and ignore the /node and /affinity options.
- Update the usage message accordingly.
---
I had forgotten a previous patch that added a FIXME to that section of
the code as a reminder to myself, hence why it did not apply. Doh!
programs/cmd/cmd.rc | 23 ++++--
programs/start/start.c | 197 +++++++++++++++++++++++++++++++----------------
programs/start/start.rc | 23 ++++--
3 files changed, 166 insertions(+), 77 deletions(-)
diff --git a/programs/cmd/cmd.rc b/programs/cmd/cmd.rc
index 00d2189..4a43a83 100644
--- a/programs/cmd/cmd.rc
+++ b/programs/cmd/cmd.rc
@@ -166,12 +166,23 @@ start [options] program_filename [...]\n\
start [options] document_filename\n\
\n\
Options:\n\
-/M[inimized] Start the program minimized.\n\
-/MAX[imized] Start the program maximized.\n\
-/R[estored] Start the program normally (neither minimized nor maximized).\n\
-/W[ait] Wait for started program to finish, then exit with its exit code.\n\
-/Unix Use a Unix filename and start the file like windows explorer.\n\
-/ProgIDOpen Open a document using the following progID.\n\
+\"title\" Specifies the title of the child windows.\n\
+/d directory Start the program in the specified directory.\n\
+/b Don't create a new console for the program.\n\
+/i Start the program with fresh environment variables.\n\
+/min Start the program minimized.\n\
+/max Start the program maximized.\n\
+/low Start the program in the idle priority class.\n\
+/normal Start the program in the normal priority class.\n\
+/high Start the program in the high priority class.\n\
+/realtime Start the program in the realtime priority class.\n\
+/abovenormal Start the program in the abovenormal priority class.\n\
+/belownormal Start the program in the belownormal priority class.\n\
+/node n Start the program on the specified NUMA node.\n\
+/affinity mask Start the program with the specified affinity mask.\n\
+/wait Wait for the started program to finish, then exit with its exit code.\n\
+/unix Use a Unix filename and start the file like windows explorer.\n\
+/ProgIDOpen Open a document using the specified progID.\n\
/? Display this help and exit.\n"
WCMD_SET,
diff --git a/programs/start/start.c b/programs/start/start.c
index d65b497..8eb7148 100644
--- a/programs/start/start.c
+++ b/programs/start/start.c
@@ -169,21 +169,46 @@ static WCHAR *get_parent_dir(WCHAR* path)
return result;
}
+static BOOL is_option(const WCHAR* arg, const WCHAR* opt)
+{
+ return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
+ arg, -1, opt, -1) == CSTR_EQUAL;
+}
+
int wmain (int argc, WCHAR *argv[])
{
SHELLEXECUTEINFOW sei;
+ DWORD creation_flags;
WCHAR *args = NULL;
int i;
int unix_mode = 0;
int progid_open = 0;
+ WCHAR *title = NULL;
WCHAR *dos_filename = NULL;
WCHAR *parent_directory = NULL;
DWORD binary_type;
- static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 };
- static const WCHAR unixW[] = { 'u', 'n', 'i', 'x', 0 };
+ static const WCHAR bW[] = { '/', 'b', 0 };
+ static const WCHAR minW[] = { '/', 'm', 'i', 'n', 0 };
+ static const WCHAR maxW[] = { '/', 'm', 'a', 'x', 0 };
+ static const WCHAR lowW[] = { '/', 'l', 'o', 'w', 0 };
+ static const WCHAR normalW[] = { '/', 'n', 'o', 'r', 'm', 'a', 'l', 0 };
+ static const WCHAR highW[] = { '/', 'h', 'i', 'g', 'h', 0 };
+ static const WCHAR realtimeW[] = { '/', 'r', 'e', 'a', 'l', 't', 'i', 'm', 'e', 0 };
+ static const WCHAR abovenormalW[] = { '/', 'a', 'b', 'o', 'v', 'e', 'n', 'o', 'r', 'm', 'a', 'l', 0 };
+ static const WCHAR belownormalW[] = { '/', 'b', 'e', 'l', 'o', 'w', 'n', 'o', 'r', 'm', 'a', 'l', 0 };
+ static const WCHAR separateW[] = { '/', 's', 'e', 'p', 'a', 'r', 'a', 't', 'e', 0 };
+ static const WCHAR sharedW[] = { '/', 's', 'h', 'a', 'r', 'e', 'd', 0 };
+ static const WCHAR nodeW[] = { '/', 'n', 'o', 'd', 'e', 0 };
+ static const WCHAR affinityW[] = { '/', 'a', 'f', 'f', 'i', 'n', 'i', 't', 'y', 0 };
+ static const WCHAR wW[] = { '/', 'w', 0 };
+ static const WCHAR waitW[] = { '/', 'w', 'a', 'i', 't', 0 };
+ static const WCHAR helpW[] = { '/', '?', 0 };
+ static const WCHAR unixW[] = { '/', 'u', 'n', 'i', 'x', 0 };
static const WCHAR progIDOpenW[] =
- { 'p', 'r', 'o', 'g', 'I', 'D', 'O', 'p', 'e', 'n', 0};
+ { '/', 'p', 'r', 'o', 'g', 'I', 'D', 'O', 'p', 'e', 'n', 0};
+ static const WCHAR openW[] = { '/', 'o', 'p', 'e', 'n', 0 };
+ static const WCHAR cmdW[] = { 'c', 'm', 'd', '.', 'e', 'x', 'e', 0 };
memset(&sei, 0, sizeof(sei));
sei.cbSize = sizeof(sei);
@@ -193,87 +218,127 @@ int wmain (int argc, WCHAR *argv[])
sei.fMask = SEE_MASK_FLAG_DDEWAIT|
SEE_MASK_FLAG_NO_UI|
SEE_MASK_NO_CONSOLE;
+ sei.lpDirectory = NULL;
+ creation_flags = CREATE_NEW_CONSOLE;
/* Canonical Microsoft commandline flag processing:
- * flags start with /, are case insensitive,
- * and may be run together in same word.
+ * flags start with / and are case insensitive.
*/
for (i=1; i<argc; i++) {
- int ci;
-
+ if (argv[i][0] == '"') {
+ title = argv[i];
+ continue;
+ }
if (argv[i][0] != '/')
break;
- /* Unix paths can start with / so we have to assume anything following /U is not a flag */
+ /* Unix paths can start with / so we have to assume anything following /unix is not a flag */
if (unix_mode || progid_open)
break;
- /* Handle all options in this word */
- for (ci=0; argv[i][ci]; ) {
- /* Skip slash */
- ci++;
- switch(argv[i][ci]) {
- case 'b':
- case 'B':
- break; /* FIXME: should stop new window from being created */
- case 'i':
- case 'I':
- break; /* FIXME: should ignore any changes to current environment */
- case 'm':
- case 'M':
- if (argv[i][ci+1] == 'a' || argv[i][ci+1] == 'A')
- sei.nShow = SW_SHOWMAXIMIZED;
- else
- sei.nShow = SW_SHOWMINIMIZED;
- break;
- case 'r':
- case 'R':
- /* sei.nShow = SW_SHOWNORMAL; */
- break;
- case 'u':
- case 'U':
- if (strncmpiW(&argv[i][ci], unixW, 4) == 0)
- unix_mode = 1;
- else {
- WINE_ERR("Option '%s' not recognized\n", wine_dbgstr_w( argv[i]+ci-1));
- usage();
- }
- break;
- case 'p':
- case 'P':
- if (strncmpiW(&argv[i][ci], progIDOpenW, 17) == 0)
- progid_open = 1;
- else {
- WINE_ERR("Option '%s' not recognized\n", wine_dbgstr_w( argv[i]+ci-1));
- usage();
- }
- break;
- case 'w':
- case 'W':
- sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
- break;
- case '?':
+ if (argv[i][0] == '/' && (argv[i][1] == 'd' || argv[i][1] == 'D')) {
+ if (argv[i][2])
+ /* The start directory was concatenated to the option */
+ sei.lpDirectory = argv[i]+2;
+ else if (i+1 == argc) {
+ WINE_ERR("you must specify a directory path for the /d option\n");
usage();
- break;
- default:
- WINE_ERR("Option '%s' not recognized\n", wine_dbgstr_w( argv[i]+ci-1));
+ } else
+ sei.lpDirectory = argv[++i];
+ }
+ else if (is_option(argv[i], bW)) {
+ creation_flags &= !CREATE_NEW_CONSOLE;
+ }
+ else if (argv[i][0] == '/' && (argv[i][1] == 'i' || argv[i][1] == 'I')) {
+ TRACE("/i is ignored\n"); /* FIXME */
+ }
+ else if (is_option(argv[i], minW)) {
+ sei.nShow = SW_SHOWMINIMIZED;
+ }
+ else if (is_option(argv[i], maxW)) {
+ sei.nShow = SW_SHOWMAXIMIZED;
+ }
+ else if (is_option(argv[i], lowW)) {
+ creation_flags |= IDLE_PRIORITY_CLASS;
+ }
+ else if (is_option(argv[i], normalW)) {
+ creation_flags |= NORMAL_PRIORITY_CLASS;
+ }
+ else if (is_option(argv[i], highW)) {
+ creation_flags |= HIGH_PRIORITY_CLASS;
+ }
+ else if (is_option(argv[i], realtimeW)) {
+ creation_flags |= REALTIME_PRIORITY_CLASS;
+ }
+ else if (is_option(argv[i], abovenormalW)) {
+ creation_flags |= ABOVE_NORMAL_PRIORITY_CLASS;
+ }
+ else if (is_option(argv[i], belownormalW)) {
+ creation_flags |= BELOW_NORMAL_PRIORITY_CLASS;
+ }
+ else if (is_option(argv[i], separateW)) {
+ TRACE("/separate is ignored\n"); /* FIXME */
+ }
+ else if (is_option(argv[i], sharedW)) {
+ TRACE("/shared is ignored\n"); /* FIXME */
+ }
+ else if (is_option(argv[i], nodeW)) {
+ if (i+1 == argc) {
+ WINE_ERR("you must specify a numa node for the /node option\n");
usage();
+ } else
+ {
+ TRACE("/node is ignored\n"); /* FIXME */
+ i++;
}
- /* Skip to next slash */
- while (argv[i][ci] && (argv[i][ci] != '/'))
- ci++;
}
- }
+ else if (is_option(argv[i], affinityW))
+ {
+ if (i+1 == argc) {
+ WINE_ERR("you must specify a numa node for the /node option\n");
+ usage();
+ } else
+ {
+ TRACE("/affinity is ignored\n"); /* FIXME */
+ i++;
+ }
+ }
+ else if (is_option(argv[i], wW) || is_option(argv[i], waitW)) {
+ sei.fMask |= SEE_MASK_NOCLOSEPROCESS;
+ }
+ else if (is_option(argv[i], helpW)) {
+ usage();
+ }
- if (i == argc)
- usage();
+ /* Wine extensions */
+
+ else if (is_option(argv[i], unixW)) {
+ unix_mode = 1;
+ }
+ else if (is_option(argv[i], progIDOpenW)) {
+ progid_open = 1;
+ } else
+
+ {
+ WINE_ERR("Unknown option '%s'\n", wine_dbgstr_w(argv[i]));
+ usage();
+ }
+ }
if (progid_open) {
+ if (i == argc)
+ usage();
sei.lpClass = argv[i++];
sei.fMask |= SEE_MASK_CLASSNAME;
}
- sei.lpFile = argv[i++];
+ if (i == argc) {
+ if (progid_open || unix_mode)
+ usage();
+ sei.lpFile = cmdW;
+ }
+ else
+ sei.lpFile = argv[i++];
args = build_args( argc - i, &argv[i] );
sei.lpParameters = args;
@@ -301,7 +366,8 @@ int wmain (int argc, WCHAR *argv[])
fatal_string(STRING_UNIXFAIL);
sei.lpFile = dos_filename;
- sei.lpDirectory = parent_directory = get_parent_dir(dos_filename);
+ if (!sei.lpDirectory)
+ sei.lpDirectory = parent_directory = get_parent_dir(dos_filename);
sei.fMask &= ~SEE_MASK_FLAG_NO_UI;
if (GetBinaryTypeW(sei.lpFile, &binary_type)) {
@@ -317,6 +383,7 @@ int wmain (int argc, WCHAR *argv[])
ZeroMemory(&startup_info, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
+ startup_info.lpTitle = title;
if (!CreateProcessW(
NULL, /* lpApplicationName */
@@ -324,7 +391,7 @@ int wmain (int argc, WCHAR *argv[])
NULL, /* lpProcessAttributes */
NULL, /* lpThreadAttributes */
FALSE, /* bInheritHandles */
- CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ creation_flags, /* dwCreationFlags */
NULL, /* lpEnvironment */
sei.lpDirectory, /* lpCurrentDirectory */
&startup_info, /* lpStartupInfo */
diff --git a/programs/start/start.rc b/programs/start/start.rc
index e442e3c..a1ac57c 100644
--- a/programs/start/start.rc
+++ b/programs/start/start.rc
@@ -30,12 +30,23 @@ start [options] program_filename [...]\n\
start [options] document_filename\n\
\n\
Options:\n\
-/M[inimized] Start the program minimized.\n\
-/MAX[imized] Start the program maximized.\n\
-/R[estored] Start the program normally (neither minimized nor maximized).\n\
-/W[ait] Wait for started program to finish, then exit with its exit code.\n\
-/Unix Use a Unix filename and start the file like windows explorer.\n\
-/ProgIDOpen Open a document using the following progID.\n\
+\"title\" Specifies the title of the child windows.\n\
+/d directory Start the program in the specified directory.\n\
+/b Don't create a new console for the program.\n\
+/i Start the program with fresh environment variables.\n\
+/min Start the program minimized.\n\
+/max Start the program maximized.\n\
+/low Start the program in the idle priority class.\n\
+/normal Start the program in the normal priority class.\n\
+/high Start the program in the high priority class.\n\
+/realtime Start the program in the realtime priority class.\n\
+/abovenormal Start the program in the abovenormal priority class.\n\
+/belownormal Start the program in the belownormal priority class.\n\
+/node n Start the program on the specified NUMA node.\n\
+/affinity mask Start the program with the specified affinity mask.\n\
+/wait Wait for the started program to finish, then exit with its exit code.\n\
+/unix Use a Unix filename and start the file like windows explorer.\n\
+/ProgIDOpen Open a document using the specified progID.\n\
/? Display this help and exit.\n"
STRING_EXECFAIL, "Application could not be started, or no application associated with the specified file.\nShellExecuteEx failed"
--
1.7.10
More information about the wine-patches
mailing list