DEBUG_cmp_sym: micro optimization/cleanup.
[wine] / programs / winevdm / winevdm.c
1 /*
2  * Wine virtual DOS machine
3  *
4  * Copyright 2003 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wine/winbase16.h"
26 #include "winuser.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(winevdm);
30
31 extern void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline );
32
33
34 /***********************************************************************
35  *           build_command_line
36  *
37  * Build the command line of a process from the argv array.
38  * Copied from ENV_BuildCommandLine.
39  */
40 static char *build_command_line( char **argv )
41 {
42     int len;
43     char *p, **arg, *cmd_line;
44
45     len = 0;
46     for (arg = argv; *arg; arg++)
47     {
48         int has_space,bcount;
49         char* a;
50
51         has_space=0;
52         bcount=0;
53         a=*arg;
54         if( !*a ) has_space=1;
55         while (*a!='\0') {
56             if (*a=='\\') {
57                 bcount++;
58             } else {
59                 if (*a==' ' || *a=='\t') {
60                     has_space=1;
61                 } else if (*a=='"') {
62                     /* doubling of '\' preceeding a '"',
63                      * plus escaping of said '"'
64                      */
65                     len+=2*bcount+1;
66                 }
67                 bcount=0;
68             }
69             a++;
70         }
71         len+=(a-*arg)+1 /* for the separating space */;
72         if (has_space)
73             len+=2; /* for the quotes */
74     }
75
76     if (!(cmd_line = HeapAlloc( GetProcessHeap(), 0, len ? len + 1 : 2 ))) 
77         return NULL;
78
79     p = cmd_line;
80     *p++ = (len < 256) ? len : 255;
81     for (arg = argv; *arg; arg++)
82     {
83         int has_space,has_quote;
84         char* a;
85
86         /* Check for quotes and spaces in this argument */
87         has_space=has_quote=0;
88         a=*arg;
89         if( !*a ) has_space=1;
90         while (*a!='\0') {
91             if (*a==' ' || *a=='\t') {
92                 has_space=1;
93                 if (has_quote)
94                     break;
95             } else if (*a=='"') {
96                 has_quote=1;
97                 if (has_space)
98                     break;
99             }
100             a++;
101         }
102
103         /* Now transfer it to the command line */
104         if (has_space)
105             *p++='"';
106         if (has_quote) {
107             int bcount;
108             char* a;
109
110             bcount=0;
111             a=*arg;
112             while (*a!='\0') {
113                 if (*a=='\\') {
114                     *p++=*a;
115                     bcount++;
116                 } else {
117                     if (*a=='"') {
118                         int i;
119
120                         /* Double all the '\\' preceeding this '"', plus one */
121                         for (i=0;i<=bcount;i++)
122                             *p++='\\';
123                         *p++='"';
124                     } else {
125                         *p++=*a;
126                     }
127                     bcount=0;
128                 }
129                 a++;
130             }
131         } else {
132             strcpy(p,*arg);
133             p+=strlen(*arg);
134         }
135         if (has_space)
136             *p++='"';
137         *p++=' ';
138     }
139     if (len) p--;  /* remove last space */
140     *p = '\0';
141     return cmd_line;
142 }
143
144
145 /***********************************************************************
146  *           usage
147  */
148 static void usage(void)
149 {
150     WINE_MESSAGE( "Usage: winevdm.exe [--app-name app.exe] command line\n\n" );
151     ExitProcess(1);
152 }
153
154
155 /***********************************************************************
156  *           main
157  */
158 int main( int argc, char *argv[] )
159 {
160     DWORD count;
161     HINSTANCE16 instance;
162     LOADPARAMS16 params;
163     WORD showCmd[2];
164     char buffer[MAX_PATH];
165     STARTUPINFOA info;
166     char *cmdline, *appname, **first_arg;
167
168     if (!argv[1]) usage();
169
170     if (!strcmp( argv[1], "--app-name" ))
171     {
172         if (!(appname = argv[2])) usage();
173         first_arg = argv + 3;
174     }
175     else
176     {
177         if (!SearchPathA( NULL, argv[1], ".exe", sizeof(buffer), buffer, NULL ))
178         {
179             WINE_MESSAGE( "winevdm: can't exec '%s': file not found\n", argv[1] );
180             ExitProcess(1);
181         }
182         appname = buffer;
183         first_arg = argv + 1;
184     }
185
186     if (*first_arg) first_arg++;  /* skip program name */
187     cmdline = build_command_line( first_arg );
188
189     if (WINE_TRACE_ON(winevdm))
190     {
191         int i;
192         WINE_TRACE( "GetCommandLine = '%s'\n", GetCommandLineA() );
193         WINE_TRACE( "appname = '%s'\n", appname );
194         WINE_TRACE( "cmdline = '%.*s'\n", cmdline[0], cmdline+1 );
195         for (i = 0; argv[i]; i++) WINE_TRACE( "argv[%d]: '%s'\n", i, argv[i] );
196     }
197
198     GetStartupInfoA( &info );
199     showCmd[0] = 2;
200     showCmd[1] = (info.dwFlags & STARTF_USESHOWWINDOW) ? info.wShowWindow : SW_SHOWNORMAL;
201
202     params.hEnvironment = 0;
203     params.cmdLine = MapLS( cmdline );
204     params.showCmd = MapLS( showCmd );
205     params.reserved = 0;
206
207     RestoreThunkLock(1);  /* grab the Win16 lock */
208
209     /* some programs assume mmsystem is always present */
210     LoadLibrary16( "mmsystem.dll" );
211
212     if ((instance = LoadModule16( appname, &params )) < 32)
213     {
214         if (instance == 11)  /* try DOS format */
215         {
216             /* loader expects arguments to be regular C strings */
217             wine_load_dos_exe( appname, cmdline + 1 );
218             /* if we get back here it failed */
219             instance = GetLastError();
220         }
221
222         WINE_MESSAGE( "winevdm: can't exec '%s': ", appname );
223         switch (instance)
224         {
225         case  2: WINE_MESSAGE("file not found\n" ); break;
226         case 11: WINE_MESSAGE("invalid exe file\n" ); break;
227         default: WINE_MESSAGE("error=%d\n", instance ); break;
228         }
229         ExitProcess(instance);
230     }
231
232     /* wait forever; the process will be killed when the last task exits */
233     ReleaseThunkLock( &count );
234     Sleep( INFINITE );
235     return 0;
236 }