On Wed, Jul 26, 2006 at 11:18:52AM -0500, Bo Peng wrote:

> > We could arrange things such that the program looks at its name and if
> > it isn't called lyx.exe it behaves exactly as it does now, otherwise,
> > after parsing the env vars, it prefixes the remaining parameters on the
> > command line with "cmd /c lyxc.exe".
> 
> It becomes too magical then. I would prefer either
> 
> 1. we keep it as it is (maybe change /var to -var), and pass cmd /c
> lyxc.exe explicitly, this allows some flexibility for the windows
> installer, and it is not terribly difficult to use.
> 
> or
> 
> 2. completely trnasform this to a lyx.exe that can take -var=val in
> additional to what the real lyx.exe is doing now.
> 
> > Do you want me to make the change?
> 
> Yes, please.

Please, find attached a patch for hidecmd.c. It works in the following way.
After renaming the real lyx executable as lyxc.exe and hidecmd.exe as lyx.exe

lyx.exe var=val var1=val1 -dbg 4 -geometry "10x10+10-10" file1.lyx file2.lyx

results in

set var=val
set var1=val1
cmd /c ""path\to\lyxc.exe" -dbg 4 -geometry "10x10+10-10" file1.lyx file2.lyx"

The behavior with respect to environment variables is similar to the
*nix env program, i.e., everything in the form a=b is taken as a request
to set the env var "a" to the value "b". To avoid this, one can use quoting,
such that

lyx.exe var="val" "var1=val1" -dbg 4 file.lyx

results in

set var="val"
cmd /c ""path\to\lyxc.exe "var1=val1" -dbg 4 file.lyx"

I avoided any call to standard C functions in order to keep the size of
the executable small (the stripped size is 7.5 Kb with mingw).

Please test. It works for me.

-- 
Enrico
Index: development/Win32/hidecmd.c
===================================================================
--- development/Win32/hidecmd.c (revision 14498)
+++ development/Win32/hidecmd.c (working copy)
@@ -12,39 +12,34 @@
  */
 
 /**
- *  This utility function is used to start lyx under windows, but
- *  hide the console window. It is adapted from program hidec at
+ *  This is a wrapper program to start lyx under windows hiding its
+ *  console window. It is adapted from program hidec at
  *  http://www.msfn.org/board/index.php?showtopic=49184&mode=threaded
  *
+ *  This wrapper should be named lyx.exe and placed in the same directory
+ *  as the real lyx executable which _must_ be renamed as lyxc.exe
+ *
  *  Usage: 
- *     hidecmd [/w] [/VAR=val] <filename> [<params>]
- *  where: /w           wait for program termination
- *             /VAR=val        set VAR=val
- *             <filename>  executable program
- *             <params>        program parameters
+ *      hidecmd [VAR=val ...] [<params>]
+ *  where:
+ *         VAR=val    set VAR=val (multiple settings may be specified)
+ *         <params>   parameters for the real lyx executable
  *
- *  How to built this program:
+ *  How to build this program:
  *  msvc:
  *     cl.exe hidecmd.c /GA /O1 /link /subsystem:windows \
  *        kernel32.lib advapi32.lib user32.lib libcmt.lib
  *  mingw/gcc:
- *     gcc -mno-cygwin -mwindows hidecmd.c -o hidecmd
+ *     gcc -mwindows hidecmd.c -o hidecmd
  *
  */
 
 #include <process.h>
 #include <windows.h>
 
-
-char * usage = "hidecmd [/w] [/VAR=val] <filename> [<params>]\n"
-       "  where: /w             wait for program termination\n"
-       "               /VAR=val        set VAR=val\n"
-       "               <filename>  executable program\n"
-       "               <params>        program parameters\n";
-
 #ifdef _MSC_VER
 //
-// Using msvc, the following progma can reduce executable size from
+// Using msvc, the following pragmas can reduce executable size from
 // 44k to 6k. I am not sure if mingw/gcc can take advantage of them
 // though.
 //
@@ -64,19 +59,25 @@
 {
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
-       int bWait = 0;
        DWORD exitcode = 0;
        char delim = ' ';
-       char var[128];
-       char val[128];
+       char * var;
+       char * val;
+       // two " are needed here: the first one quotes the entire
+       // command, the second one the executable name
+       char cmd[1024] = "cmd /c \"\"";
+       //  i0 = strlen(cmd);
+       int i0 = 9;
+       int i;
        int err = 0;
+       int inquote;
        char * cmdLine = GetCommandLine();
-       int i;
-       // start and end of variable/value
-       char * s;
-       char * e;
+       // the name of the executable to be launched
+       // (must be in the same directory)
+       char * lyxc = "lyxc.exe";
 
-       // use GetCommandLine(), command name is included. Skip it
+       // When using GetCommandLine(), command name is included
+       // but the full path may be missing, so skip it.
        if (*cmdLine == '\"') {
                delim = '\"';
                cmdLine++;
@@ -89,95 +90,106 @@
                cmdLine++;
 
        // skip over ' ' or '\t'
-       while ((*cmdLine != 0) && ((*cmdLine == ' ') || (*cmdLine == '\t')))
+       while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t'))
                cmdLine++; 
 
-       while (*cmdLine == '/') {
-               // /w or /W option
-               if (((cmdLine[1] == 'w') || (cmdLine[1] == 'W')) &&
-                       (cmdLine[2] == ' '))
+       // Use GetModuleFileName() to get the path to lyxc.exe
+       GetModuleFileName(0, cmd + i0, sizeof(cmd) / 2);
+
+       // substitute executable name
+       for (i = i0; cmd[i] != 0; ++i);
+
+       for (--i; i >= i0 && cmd[i] != '\\' && cmd[i] != '/'; --i);
+
+       for (++i; *lyxc && i < sizeof(cmd); )
+               cmd[i++] = *lyxc++;
+
+       // check whether lyxc.exe is there
+       cmd[i] = '\0';
+       lyxc = cmd + i0;
+       if (GetFileAttributesA(lyxc) == 0xFFFFFFFF) {
+               exitcode = GetLastError();
+               MessageBox(0, lyxc, "Error: cannot find the real LyX executable 
below", 0);
+               ExitProcess(exitcode);
+       }
+
+       // it's there, so finish quoting filename
+       cmd[i++] = '\"';
+
+       // parse remainder of command line
+       while (*cmdLine != 0 && !err) {
+               if (i < sizeof(cmd))
+                       cmd[i++] = ' ';
+               else
+                       err = 1;
+
+               if ((*cmdLine >= 'A' && *cmdLine <= 'Z') ||
+                   (*cmdLine >= 'a' && *cmdLine <= 'z'))
+                       var = cmd + i;
+               else
+                       var = NULL;
+
+               val = NULL;
+               inquote = 0;
+               while (!err && ((*cmdLine != 0 && *cmdLine != ' ' &&
+                               *cmdLine != '\t') || inquote))
                {
-                       bWait = 1;
-                       cmdLine += 3;
-               // environment variable
-               } else {
-                       cmdLine++;
+                       if (*cmdLine == '\"')
+                               inquote = 1 - inquote;
 
-                       // get var
-                       s = var;
-                       e = s + sizeof(var) - 1;
-                       
-                       while (*cmdLine != 0 && *cmdLine != '=') {
-                               if (s < e) {
-                                       *s++ = *cmdLine++;
-                               } else {
-                                       cmdLine++;
-                                       err = 1;
-                               }
-                       }
+                       if (var && *cmdLine == '=' && !inquote)
+                               val = cmd + i;
 
-                       // get value
-                       *s = 0;
-                       if (*cmdLine == '=')
-                               cmdLine++;
+                       if (i < sizeof(cmd))
+                               cmd[i++] = *cmdLine;
+                       else
+                               err = 1;
 
-                       delim = ' ';
-                       
-                       if (*cmdLine == '\"') {
-                               delim = '\"';
-                               cmdLine++;
-                       }
+                       cmdLine++;
+               }
 
-                       s = val;
-                       e = s + sizeof(val) - 1;
-                       
-                       while (*cmdLine != delim && *cmdLine != 0) {
-                               if (s < e) {
-                                       *s++ = *cmdLine++;
-                               } else {
-                                       cmdLine++;
-                                       err = 1;
-                               }
+               if (var && val && !err) {
+                       *val++ = '\0';          // mark end of var
+                       if (*val == '\"') {     // account for quoted val
+                               ++val;
+                               --i;
                        }
-                       *s = 0;
-                       if (*cmdLine == delim)
-                               cmdLine++;
-
+                       cmd[i] = '\0';          // mark end of val
+                       i = var - cmd - 1;      // reset pointer
                        SetEnvironmentVariable(var, val);
                        // MessageBox(0, val, var, 0);
                }
 
                // skip spaces
-               while ((*cmdLine != 0) && ((*cmdLine == ' ') || (*cmdLine == 
'\t'))) 
+               while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t')) 
                        cmdLine++;
        }
 
-       // report error if there is no parameter 
-       if (*cmdLine == 0)
-       {
-               MessageBox(0, usage, "Error: Incorrect usage", 0);
-               ExitProcess(0);
-       }
+       if (i < sizeof(cmd) - 1) {
+               // finish quoting the entire command
+               cmd[i++] = '\"';
+               cmd[i] = '\0';
+       } else
+               err = 1;
        
        if (err) {
-               MessageBox(0, "One of the specified environment variables or 
its value is too long.", "Error: Variable name or value too long", 0);
+               MessageBox(0, "Please, use a shorter command line.",
+                               "Error: command line is too long", 0);
                ExitProcess(0);
        }
 
        // create process with new console
        // memset(&si, 0, sizeof(si));
-       s = (char *) &si;
+       val = (char *) &si;
        for (i = 0; i < sizeof(si); ++i)
-               s[i] = 0x00;
+               val[i] = 0x00;
        si.cb = sizeof(si);
        si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE;
-       if (CreateProcess(NULL, cmdLine,
+       if (CreateProcess(NULL, cmd,
                NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
                NULL, NULL, &si, &pi))
        {
-               if (bWait) 
-                       WaitForSingleObject(pi.hProcess, INFINITE);
                CloseHandle( pi.hProcess );
                CloseHandle( pi.hThread );
        }

Reply via email to