Grab the thread object in case the thread terminates with pending
[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 "winternl.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 DECLSPEC_NORETURN out_of_memory(void);
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     { "help",       'h', 0, 0, do_help,
66       "--help,-h        Show this help message" },
67     { "version",    'v', 0, 0, do_version,
68       "--version,-v     Display the Wine version" },
69     { NULL,           0, 0, 0, NULL, NULL }  /* terminator */
70 };
71
72
73 static void do_help( const char *arg )
74 {
75     OPTIONS_Usage();
76 }
77
78 static void do_version( const char *arg )
79 {
80     MESSAGE( "%s\n", PACKAGE_STRING );
81     ExitProcess(0);
82 }
83
84 static void do_debugmsg( const char *arg )
85 {
86     if (wine_dbg_parse_options( arg ))
87     {
88         MESSAGE("%s: Syntax: --debugmsg [class]+xxx,...  or -debugmsg [class]-xxx,...\n", argv0);
89         MESSAGE("Example: --debugmsg +all,warn-heap\n"
90                 "  turn on all messages except warning heap messages\n");
91         MESSAGE("Available message classes: err, warn, fixme, trace\n\n");
92         ExitProcess(1);
93     }
94 }
95
96
97 static void remove_options( char *argv[], int pos, int count, int inherit )
98 {
99     if (inherit)
100     {
101         int i, len = 0;
102         for (i = 0; i < count; i++) len += strlen(argv[pos+i]) + 1;
103         if (inherit_str)
104         {
105             if (!(inherit_str = realloc( inherit_str, strlen(inherit_str) + 1 + len )))
106                 out_of_memory();
107             strcat( inherit_str, " " );
108         }
109         else
110         {
111             if (!(inherit_str = malloc( len ))) out_of_memory();
112             inherit_str[0] = 0;
113         }
114         for (i = 0; i < count; i++)
115         {
116             strcat( inherit_str, argv[pos+i] );
117             if (i < count-1) strcat( inherit_str, " " );
118         }
119     }
120     while ((argv[pos] = argv[pos+count])) pos++;
121 }
122
123 /* parse options from the argv array and remove all the recognized ones */
124 static void parse_options( char *argv[] )
125 {
126     const struct option_descr *opt;
127     int i;
128
129     for (i = 0; argv[i]; i++)
130     {
131         const char *equalarg = NULL;
132         char *p = argv[i];
133         if (*p++ != '-') continue;  /* not an option */
134         if (*p && !p[1]) /* short name */
135         {
136             if (*p == '-') break; /* "--" option */
137             for (opt = option_table; opt->longname; opt++) if (opt->shortname == *p) break;
138         }
139         else  /* long name */
140         {
141             const char *equal = strchr  (p, '=');
142             if (*p == '-') p++;
143             /* check for the long name */
144             for (opt = option_table; opt->longname; opt++) {
145                 /* Plain --option */
146                 if (!strcmp( p, opt->longname )) break;
147
148                 /* --option=value */
149                 if (opt->has_arg &&
150                     equal &&
151                     strlen (opt->longname) == equal - p &&
152                     !strncmp (p, opt->longname, equal - p)) {
153                         equalarg = equal + 1;
154                         break;
155                     }
156             }
157         }
158         if (!opt->longname) continue;
159
160         if (equalarg)
161         {
162             opt->func( equalarg );
163             remove_options( argv, i, 1, opt->inherit );
164         }
165         else if (opt->has_arg && argv[i+1])
166         {
167             opt->func( argv[i+1] );
168             remove_options( argv, i, 2, opt->inherit );
169         }
170         else
171         {
172             opt->func( "" );
173             remove_options( argv, i, 1, opt->inherit );
174         }
175         i--;
176     }
177 }
178
179 /* inherit options from WINEOPTIONS variable */
180 static void inherit_options( char *buffer )
181 {
182     char *argv[256];
183     unsigned int n;
184
185     char *p = strtok( buffer, " \t" );
186     for (n = 0; n < sizeof(argv)/sizeof(argv[0])-1 && p; n++)
187     {
188         argv[n] = p;
189         p = strtok( NULL, " \t" );
190     }
191     argv[n] = NULL;
192     parse_options( argv );
193     if (argv[0])  /* an option remains */
194     {
195         MESSAGE( "Unknown option '%s' in WINEOPTIONS variable\n\n", argv[0] );
196         OPTIONS_Usage();
197     }
198 }
199
200 /***********************************************************************
201  *              OPTIONS_Usage
202  */
203 void OPTIONS_Usage(void)
204 {
205     const struct option_descr *opt;
206     MESSAGE( "%s\n\n", PACKAGE_STRING );
207     MESSAGE( "Usage: %s [options] [--] program_name [arguments]\n", argv0 );
208     MESSAGE("The -- has to be used if you specify arguments (of the program)\n\n");
209     MESSAGE( "Options:\n" );
210     for (opt = option_table; opt->longname; opt++) MESSAGE( "   %s\n", opt->usage );
211     ExitProcess(0);
212 }
213
214 /***********************************************************************
215  *              OPTIONS_ParseOptions
216  */
217 void OPTIONS_ParseOptions( char *argv[] )
218 {
219     char buffer[1024];
220     int i;
221
222     if (GetEnvironmentVariableA( "WINEOPTIONS", buffer, sizeof(buffer) ) && buffer[0])
223         inherit_options( buffer );
224     if (!argv) return;
225
226     parse_options( argv + 1 );
227
228     SetEnvironmentVariableA( "WINEOPTIONS", inherit_str );
229
230     /* check if any option remains */
231     for (i = 1; argv[i]; i++)
232     {
233         if (!strcmp( argv[i], "--" ))
234         {
235             remove_options( argv, i, 1, 0 );
236             break;
237         }
238         if (argv[i][0] == '-')
239         {
240             MESSAGE( "Unknown option '%s'\n\n", argv[i] );
241             OPTIONS_Usage();
242         }
243     }
244 }