Remove the --managed option, and make wine use the managed mode by
[wine] / misc / options.c
1 /*
2  * Option parsing
3  *
4  * Copyright 2000 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 "config.h"
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "winbase.h"
26 #include "winnls.h"
27 #include "ntddk.h"
28 #include "wine/library.h"
29 #include "options.h"
30 #include "module.h"
31 #include "wine/debug.h"
32
33 struct option_descr
34 {
35     const char *longname;
36     char        shortname;
37     int         has_arg;
38     int         inherit;
39     void      (*func)( const char *arg );
40     const char *usage;
41 };
42
43 const char *argv0;       /* the original argv[0] */
44 const char *full_argv0;  /* the full path of argv[0] (if known) */
45
46 static char *inherit_str;  /* options to pass to child processes */
47
48 static void out_of_memory(void) WINE_NORETURN;
49 static void out_of_memory(void)
50 {
51     MESSAGE( "Virtual memory exhausted\n" );
52     ExitProcess(1);
53 }
54
55 static void do_debugmsg( const char *arg );
56 static void do_help( const char *arg );
57 static void do_version( const char *arg );
58
59 static const struct option_descr option_table[] =
60 {
61     { "debugmsg",     0, 1, 1, do_debugmsg,
62       "--debugmsg name  Turn debugging-messages on or off" },
63     { "dll",          0, 1, 1, MODULE_AddLoadOrderOption,
64       "--dll name       Enable or disable built-in DLLs" },
65     { "dosver",       0, 1, 1, VERSION_ParseDosVersion,
66       "--dosver x.xx    DOS version to imitate (e.g. 6.22)\n"
67       "                    Only valid with --winver win31" },
68     { "help",       'h', 0, 0, do_help,
69       "--help,-h        Show this help message" },
70     { "version",    'v', 0, 0, do_version,
71       "--version,-v     Display the Wine version" },
72     { "winver",       0, 1, 1, VERSION_ParseWinVersion,
73       "--winver         Version to imitate (win95,win98,winme,nt351,nt40,win2k,winxp,win20,win30,win31)" },
74     { NULL,           0, 0, 0, NULL, NULL }  /* terminator */
75 };
76
77
78 static void do_help( const char *arg )
79 {
80     OPTIONS_Usage();
81 }
82
83 static void do_version( const char *arg )
84 {
85     MESSAGE( "%s\n", PACKAGE_STRING );
86     ExitProcess(0);
87 }
88
89 static void do_debugmsg( const char *arg )
90 {
91     static const char * const debug_class_names[__WINE_DBCL_COUNT] = { "fixme", "err", "warn", "trace" };
92
93     char *opt, *options = strdup(arg);
94     int i;
95     /* defined in relay32/relay386.c */
96     extern char **debug_relay_includelist;
97     extern char **debug_relay_excludelist;
98     /* defined in relay32/snoop.c */
99     extern char **debug_snoop_includelist;
100     extern char **debug_snoop_excludelist;
101
102     if (!(opt = strtok( options, "," ))) goto error;
103     do
104     {
105         unsigned char set = 0, clear = 0;
106         char *p = strchr( opt, '+' );
107         if (!p) p = strchr( opt, '-' );
108         if (!p || !p[1]) goto error;
109         if (p > opt)
110         {
111             for (i = 0; i < __WINE_DBCL_COUNT; i++)
112             {
113                 int len = strlen(debug_class_names[i]);
114                 if (len != (p - opt)) continue;
115                 if (!memcmp( opt, debug_class_names[i], len ))  /* found it */
116                 {
117                     if (*p == '+') set |= 1 << i;
118                     else clear |= 1 << i;
119                     break;
120                 }
121             }
122             if (i == __WINE_DBCL_COUNT) goto error;  /* class name not found */
123         }
124         else
125         {
126             if (*p == '+') set = ~0;
127             else clear = ~0;
128             if (!strncasecmp(p+1, "relay=", 6) ||
129                 !strncasecmp(p+1, "snoop=", 6))
130                 {
131                     int i, l;
132                     char *s, *s2, ***output, c;
133
134                     if (strchr(p,','))
135                         l=strchr(p,',')-p;
136                     else
137                         l=strlen(p);
138                     set = ~0;
139                     clear = 0;
140                     output = (*p == '+') ?
141                         ((*(p+1) == 'r') ?
142                          &debug_relay_includelist :
143                          &debug_snoop_includelist) :
144                         ((*(p+1) == 'r') ?
145                          &debug_relay_excludelist :
146                          &debug_snoop_excludelist);
147                     s = p + 7;
148                     /* if there are n ':', there are n+1 modules, and we need
149                        n+2 slots, last one being for the sentinel (NULL) */
150                     i = 2;      
151                     while((s = strchr(s, ':'))) i++, s++;
152                     *output = malloc(sizeof(char **) * i);
153                     i = 0;
154                     s = p + 7;
155                     while((s2 = strchr(s, ':'))) {
156                         c = *s2;
157                         *s2 = '\0';
158                         *((*output)+i) = _strupr(strdup(s));
159                         *s2 = c;
160                         s = s2 + 1;
161                         i++;
162                     }
163                     c = *(p + l);
164                     *(p + l) = '\0';
165                     *((*output)+i) = _strupr(strdup(s));
166                     *(p + l) = c;
167                     *((*output)+i+1) = NULL;
168                     *(p + 6) = '\0';
169                 }
170         }
171         p++;
172         if (!strcmp( p, "all" )) p = "";  /* empty string means all */
173         wine_dbg_add_option( p, set, clear );
174         opt = strtok( NULL, "," );
175     } while(opt);
176
177     free( options );
178     return;
179
180  error:
181     MESSAGE("wine: Syntax: --debugmsg [class]+xxx,...  or "
182             "-debugmsg [class]-xxx,...\n");
183     MESSAGE("Example: --debugmsg +all,warn-heap\n"
184             "  turn on all messages except warning heap messages\n");
185     MESSAGE("Available message classes:\n");
186     for( i = 0; i < __WINE_DBCL_COUNT; i++) MESSAGE( "%-9s", debug_class_names[i] );
187     MESSAGE("\n\n");
188     ExitProcess(1);
189 }
190
191
192 static void remove_options( char *argv[], int pos, int count, int inherit )
193 {
194     if (inherit)
195     {
196         int i, len = 0;
197         for (i = 0; i < count; i++) len += strlen(argv[pos+i]) + 1;
198         if (inherit_str)
199         {
200             if (!(inherit_str = realloc( inherit_str, strlen(inherit_str) + 1 + len )))
201                 out_of_memory();
202             strcat( inherit_str, " " );
203         }
204         else
205         {
206             if (!(inherit_str = malloc( len ))) out_of_memory();
207             inherit_str[0] = 0;
208         }
209         for (i = 0; i < count; i++)
210         {
211             strcat( inherit_str, argv[pos+i] );
212             if (i < count-1) strcat( inherit_str, " " );
213         }
214     }
215     while ((argv[pos] = argv[pos+count])) pos++;
216 }
217
218 /* parse options from the argv array and remove all the recognized ones */
219 static void parse_options( char *argv[] )
220 {
221     const struct option_descr *opt;
222     int i;
223
224     for (i = 0; argv[i]; i++)
225     {
226         const char *equalarg = NULL;
227         char *p = argv[i];
228         if (*p++ != '-') continue;  /* not an option */
229         if (*p && !p[1]) /* short name */
230         {
231             if (*p == '-') break; /* "--" option */
232             for (opt = option_table; opt->longname; opt++) if (opt->shortname == *p) break;
233         }
234         else  /* long name */
235         {
236             const char *equal = strchr  (p, '=');
237             if (*p == '-') p++;
238             /* check for the long name */
239             for (opt = option_table; opt->longname; opt++) {
240                 /* Plain --option */
241                 if (!strcmp( p, opt->longname )) break;
242
243                 /* --option=value */
244                 if (opt->has_arg &&
245                     equal &&
246                     strlen (opt->longname) == equal - p &&
247                     !strncmp (p, opt->longname, equal - p)) {
248                         equalarg = equal + 1;
249                         break;
250                     }
251             }
252         }
253         if (!opt->longname) continue;
254
255         if (equalarg)
256         {
257             opt->func( equalarg );
258             remove_options( argv, i, 1, opt->inherit );
259         }
260         else if (opt->has_arg && argv[i+1])
261         {
262             opt->func( argv[i+1] );
263             remove_options( argv, i, 2, opt->inherit );
264         }
265         else
266         {
267             opt->func( "" );
268             remove_options( argv, i, 1, opt->inherit );
269         }
270         i--;
271     }
272 }
273
274 /* inherit options from WINEOPTIONS variable */
275 static void inherit_options( char *buffer )
276 {
277     char *argv[256];
278     unsigned int n;
279
280     char *p = strtok( buffer, " \t" );
281     for (n = 0; n < sizeof(argv)/sizeof(argv[0])-1 && p; n++)
282     {
283         argv[n] = p;
284         p = strtok( NULL, " \t" );
285     }
286     argv[n] = NULL;
287     parse_options( argv );
288     if (argv[0])  /* an option remains */
289     {
290         MESSAGE( "Unknown option '%s' in WINEOPTIONS variable\n\n", argv[0] );
291         OPTIONS_Usage();
292     }
293 }
294
295 /***********************************************************************
296  *              OPTIONS_Usage
297  */
298 void OPTIONS_Usage(void)
299 {
300     const struct option_descr *opt;
301     MESSAGE( "%s\n\n", PACKAGE_STRING );
302     MESSAGE( "Usage: %s [options] [--] program_name [arguments]\n", argv0 );
303     MESSAGE("The -- has to be used if you specify arguments (of the program)\n\n");
304     MESSAGE( "Options:\n" );
305     for (opt = option_table; opt->longname; opt++) MESSAGE( "   %s\n", opt->usage );
306     ExitProcess(0);
307 }
308
309 /***********************************************************************
310  *              OPTIONS_ParseOptions
311  */
312 void OPTIONS_ParseOptions( char *argv[] )
313 {
314     char buffer[1024];
315     int i;
316
317     if (GetEnvironmentVariableA( "WINEOPTIONS", buffer, sizeof(buffer) ) && buffer[0])
318         inherit_options( buffer );
319     if (!argv) return;
320
321     parse_options( argv + 1 );
322
323     SetEnvironmentVariableA( "WINEOPTIONS", inherit_str );
324
325     /* check if any option remains */
326     for (i = 1; argv[i]; i++)
327     {
328         if (!strcmp( argv[i], "--" ))
329         {
330             remove_options( argv, i, 1, 0 );
331             break;
332         }
333         if (argv[i][0] == '-')
334         {
335             MESSAGE( "Unknown option '%s'\n\n", argv[i] );
336             OPTIONS_Usage();
337         }
338     }
339 }