Added support for a WINELOADER environment variable which allows the
[wine] / misc / options.c
1 /*
2  * Option parsing
3  *
4  * Copyright 2000 Alexandre Julliard
5  */
6
7 #include "config.h"
8 #include <string.h>
9 #include <stdlib.h>
10
11 #include "winbase.h"
12 #include "main.h"
13 #include "options.h"
14 #include "version.h"
15 #include "debugtools.h"
16
17 struct option
18 {
19     const char *longname;
20     char        shortname;
21     int         has_arg;
22     int         inherit;
23     void      (*func)( const char *arg );
24     const char *usage;
25 };
26
27 /* Most Windows C/C++ compilers use something like this to */
28 /* access argc and argv globally: */
29 int _ARGC;
30 char **_ARGV;
31
32 /* default options */
33 struct options Options =
34 {
35     NULL,           /* desktopGeometry */
36     NULL,           /* display */
37     NULL,           /* dllFlags */
38     FALSE,          /* synchronous */
39     FALSE,          /* Managed windows */
40     NULL            /* Alternate config file name */
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 char *xstrdup( const char *str )
56 {
57     char *ret = strdup( str );
58     if (!ret) out_of_memory();
59     return ret;
60 }
61
62 static void do_config( const char *arg );
63 static void do_desktop( const char *arg );
64 static void do_display( const char *arg );
65 static void do_dll( const char *arg );
66 static void do_help( const char *arg );
67 static void do_language( const char *arg );
68 static void do_managed( const char *arg );
69 static void do_synchronous( const char *arg );
70 static void do_version( const char *arg );
71
72 static const struct option option_table[] =
73 {
74     { "config",       0, 1, 0, do_config,
75       "--config name    Specify config file to use" },
76     { "debugmsg",     0, 1, 1, MAIN_ParseDebugOptions,
77       "--debugmsg name  Turn debugging-messages on or off" },
78     { "desktop",      0, 1, 1, do_desktop,
79       "--desktop geom   Use a desktop window of the given geometry" },
80     { "display",      0, 1, 0, do_display,
81       "--display name   Use the specified display" },
82     { "dll",          0, 1, 1, do_dll,
83       "--dll name       Enable or disable built-in DLLs" },
84     { "dosver",       0, 1, 1, VERSION_ParseDosVersion,
85       "--dosver x.xx    DOS version to imitate (e.g. 6.22). Only valid with --winver win31" },
86     { "help",       'h', 0, 0, do_help,
87       "--help,-h        Show this help message" },
88     { "language",     0, 1, 1, do_language,
89       "--language xx    Set the language (one of Br,Ca,Cs,Cy,Da,De,En,Eo,Es,Fi,Fr,Ga,Gd,Gv,\n"
90       "                    Hr,Hu,It,Ja,Ko,Kw,Nl,No,Pl,Pt,Sk,Sv,Ru,Wa)" },
91     { "managed",      0, 0, 0, do_managed,
92       "--managed        Allow the window manager to manage created windows" },
93     { "synchronous",  0, 0, 1, do_synchronous,
94       "--synchronous    Turn on synchronous display mode" },
95     { "version",    'v', 0, 0, do_version,
96       "--version,-v     Display the Wine version" },
97     { "winver",       0, 1, 1, VERSION_ParseWinVersion,
98       "--winver         Version to imitate (one of win31,win95,nt351,nt40)" },
99     { NULL,           0, 0, 0, NULL, NULL }  /* terminator */
100 };
101
102
103 static void do_help( const char *arg )
104 {
105     OPTIONS_Usage();
106 }
107
108 static void do_version( const char *arg )
109 {
110     MESSAGE( "%s\n", WINE_RELEASE_INFO );
111     ExitProcess(0);
112 }
113
114 static void do_synchronous( const char *arg )
115 {
116     Options.synchronous = TRUE;
117 }
118
119 static void do_desktop( const char *arg )
120 {
121     Options.desktopGeometry = xstrdup( arg );
122 }
123
124 static void do_display( const char *arg )
125 {
126     Options.display = xstrdup( arg );
127 }
128
129 static void do_dll( const char *arg )
130 {
131     if (Options.dllFlags)
132     {
133         Options.dllFlags = (char *) realloc ( Options.dllFlags, 
134                                             strlen ( Options.dllFlags ) + strlen ( arg ) + 2 );
135         if ( !Options.dllFlags ) out_of_memory(); 
136         strcat ( Options.dllFlags, "+" );
137         strcat ( Options.dllFlags, arg );
138     }
139     else 
140     {
141         Options.dllFlags = xstrdup( arg );
142     }
143 }
144
145 static void do_language( const char *arg )
146 {
147     SetEnvironmentVariableA( "LANGUAGE", arg );
148 }
149
150 static void do_managed( const char *arg )
151 {
152     Options.managed = TRUE;
153 }
154
155 static void do_config( const char *arg )
156 {
157     Options.configFileName = xstrdup( arg );
158 }
159
160 static void remove_options( char *argv[], int pos, int count, int inherit )
161 {
162     if (inherit)
163     {
164         int i, len = 0;
165         for (i = 0; i < count; i++) len += strlen(argv[pos+i]) + 1;
166         if (inherit_str)
167         {
168             if (!(inherit_str = realloc( inherit_str, strlen(inherit_str) + 1 + len )))
169                 out_of_memory();
170             strcat( inherit_str, " " );
171         }
172         else
173         {
174             if (!(inherit_str = malloc( len ))) out_of_memory();
175             inherit_str[0] = 0;
176         }
177         for (i = 0; i < count; i++)
178         {
179             strcat( inherit_str, argv[pos+i] );
180             if (i < count-1) strcat( inherit_str, " " );
181         }
182     }
183     while ((argv[pos] = argv[pos+count])) pos++;
184 }
185
186 /* parse options from the argv array and remove all the recognized ones */
187 static void parse_options( char *argv[] )
188 {
189     const struct option *opt;
190     int i;
191
192     for (i = 0; argv[i]; i++)
193     {
194         char *p = argv[i];
195         if (*p++ != '-') continue;  /* not an option */
196         if (*p && !p[1]) /* short name */
197         {
198             if (*p == '-') break; /* "--" option */
199             for (opt = option_table; opt->longname; opt++) if (opt->shortname == *p) break;
200         }
201         else  /* long name */
202         {
203             if (*p == '-') p++;
204             /* check for the long name */
205             for (opt = option_table; opt->longname; opt++)
206                 if (!strcmp( p, opt->longname )) break;
207         }
208         if (!opt->longname) continue;
209
210         if (opt->has_arg && argv[i+1])
211         {
212             opt->func( argv[i+1] );
213             remove_options( argv, i, 2, opt->inherit );
214         }
215         else
216         {
217             opt->func( "" );
218             remove_options( argv, i, 1, opt->inherit );
219         }
220         i--;
221     }
222 }
223
224 /* inherit options from WINEOPTIONS variable */
225 static void inherit_options( char *buffer )
226 {
227     char *argv[256];
228     int i;
229
230     char *p = strtok( buffer, " \t" );
231     for (i = 0; i < sizeof(argv)/sizeof(argv[0])-1 && p; i++)
232     {
233         argv[i] = p;
234         p = strtok( NULL, " \t" );
235     }
236     argv[i] = NULL;
237     parse_options( argv );
238     if (argv[0])  /* an option remains */
239     {
240         MESSAGE( "Unknown option '%s' in WINEOPTIONS variable\n\n", argv[0] );
241         OPTIONS_Usage();
242     }
243 }
244
245 /***********************************************************************
246  *              OPTIONS_Usage
247  */
248 void OPTIONS_Usage(void)
249 {
250     const struct option *opt;
251     MESSAGE( "Usage: %s [options] program_name [arguments]\n\n", argv0 );
252     MESSAGE( "Options:\n" );
253     for (opt = option_table; opt->longname; opt++) MESSAGE( "   %s\n", opt->usage );
254     ExitProcess(0);
255 }
256
257 /***********************************************************************
258  *              OPTIONS_ParseOptions
259  */
260 void OPTIONS_ParseOptions( char *argv[] )
261 {
262     char buffer[1024];
263     int i;
264
265     if (GetEnvironmentVariableA( "WINEOPTIONS", buffer, sizeof(buffer) ) && buffer[0])
266         inherit_options( buffer );
267
268     parse_options( argv + 1 );
269
270     SetEnvironmentVariableA( "WINEOPTIONS", inherit_str );
271
272     /* check if any option remains */
273     for (i = 1; argv[i]; i++)
274     {
275         if (!strcmp( argv[i], "--" ))
276         {
277             remove_options( argv, i, 1, 0 );
278             break;
279         }
280         if (argv[i][0] == '-')
281         {
282             MESSAGE( "Unknown option '%s'\n\n", argv[i] );
283             OPTIONS_Usage();
284         }
285     }
286
287     /* count the resulting arguments */
288     _ARGV = argv;
289     _ARGC = 0;
290     while (argv[_ARGC]) _ARGC++;
291 }