Added UTF-8 conversion support.
[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, }  /* 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         /* don't overwrite previous value. Should we
134          * automatically add the ',' between multiple DLLs ?
135          */
136         MESSAGE("Only one -dll flag is allowed. Use ',' between multiple DLLs\n");
137         ExitProcess(1);
138     }
139     Options.dllFlags = xstrdup( arg );
140 }
141
142 static void do_language( const char *arg )
143 {
144     SetEnvironmentVariableA( "LANGUAGE", arg );
145 }
146
147 static void do_managed( const char *arg )
148 {
149     Options.managed = TRUE;
150 }
151
152 static void do_config( const char *arg )
153 {
154     Options.configFileName = xstrdup( arg );
155 }
156
157 static void remove_options( char *argv[], int pos, int count, int inherit )
158 {
159     if (inherit)
160     {
161         int i, len = 0;
162         for (i = 0; i < count; i++) len += strlen(argv[pos+i]) + 1;
163         if (inherit_str)
164         {
165             if (!(inherit_str = realloc( inherit_str, strlen(inherit_str) + 1 + len )))
166                 out_of_memory();
167             strcat( inherit_str, " " );
168         }
169         else
170         {
171             if (!(inherit_str = malloc( len ))) out_of_memory();
172             inherit_str[0] = 0;
173         }
174         for (i = 0; i < count; i++)
175         {
176             strcat( inherit_str, argv[pos+i] );
177             if (i < count-1) strcat( inherit_str, " " );
178         }
179     }
180     while ((argv[pos] = argv[pos+count])) pos++;
181 }
182
183 /* parse options from the argv array and remove all the recognized ones */
184 static void parse_options( char *argv[] )
185 {
186     const struct option *opt;
187     int i;
188
189     for (i = 0; argv[i]; i++)
190     {
191         char *p = argv[i];
192         if (*p++ != '-') continue;  /* not an option */
193         if (*p && !p[1]) /* short name */
194         {
195             if (*p == '-') break; /* "--" option */
196             for (opt = option_table; opt->longname; opt++) if (opt->shortname == *p) break;
197         }
198         else  /* long name */
199         {
200             if (*p == '-') p++;
201             /* check for the long name */
202             for (opt = option_table; opt->longname; opt++)
203                 if (!strcmp( p, opt->longname )) break;
204         }
205         if (!opt->longname) continue;
206
207         if (opt->has_arg && argv[i+1])
208         {
209             opt->func( argv[i+1] );
210             remove_options( argv, i, 2, opt->inherit );
211         }
212         else
213         {
214             opt->func( "" );
215             remove_options( argv, i, 1, opt->inherit );
216         }
217         i--;
218     }
219 }
220
221 /* inherit options from WINEOPTIONS variable */
222 static void inherit_options( char *buffer )
223 {
224     char *argv[256];
225     int i;
226
227     char *p = strtok( buffer, " \t" );
228     for (i = 0; i < sizeof(argv)/sizeof(argv[0])-1 && p; i++)
229     {
230         argv[i] = p;
231         p = strtok( NULL, " \t" );
232     }
233     argv[i] = NULL;
234     parse_options( argv );
235     if (argv[0])  /* an option remains */
236     {
237         MESSAGE( "Unknown option '%s' in WINEOPTIONS variable\n\n", argv[0] );
238         OPTIONS_Usage();
239     }
240 }
241
242 /***********************************************************************
243  *              OPTIONS_Usage
244  */
245 void OPTIONS_Usage(void)
246 {
247     const struct option *opt;
248     MESSAGE( "Usage: %s [options] program_name [arguments]\n\n", argv0 );
249     MESSAGE( "Options:\n" );
250     for (opt = option_table; opt->longname; opt++) MESSAGE( "   %s\n", opt->usage );
251     ExitProcess(0);
252 }
253
254 /***********************************************************************
255  *              OPTIONS_ParseOptions
256  */
257 void OPTIONS_ParseOptions( char *argv[] )
258 {
259     char buffer[1024];
260     int i;
261
262     if (GetEnvironmentVariableA( "WINEOPTIONS", buffer, sizeof(buffer) ) && buffer[0])
263         inherit_options( buffer );
264
265     parse_options( argv + 1 );
266
267     SetEnvironmentVariableA( "WINEOPTIONS", inherit_str );
268
269     /* check if any option remains */
270     for (i = 1; argv[i]; i++)
271     {
272         if (!strcmp( argv[i], "--" ))
273         {
274             remove_options( argv, i, 1, 0 );
275             break;
276         }
277         if (argv[i][0] == '-')
278         {
279             MESSAGE( "Unknown option '%s'\n\n", argv[i] );
280             OPTIONS_Usage();
281         }
282     }
283
284     /* count the resulting arguments */
285     _ARGV = argv;
286     _ARGC = 0;
287     while (argv[_ARGC]) _ARGC++;
288 }