blob: fb5aa23c9e1108a9409fc17efd064039e3c4ee50 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001#include "android/cmdline-option.h"
2#include "android/utils/debug.h"
3#include "android/utils/misc.h"
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02004#include "android/utils/system.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005#include <stdlib.h>
6#include <stddef.h>
7#include <string.h>
8
9#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
10static const struct { const char* name; int flag; const char* text; }
11debug_tags[] = {
12 VERBOSE_TAG_LIST
13 { 0, 0, 0 }
14};
15
16static void parse_debug_tags( const char* tags );
17void parse_env_debug_tags( void );
18
David 'Digit' Turner318e4f22009-05-25 18:01:03 +020019enum {
20 OPTION_IS_FLAG = 0,
21 OPTION_IS_PARAM,
22 OPTION_IS_LIST,
23};
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080024
25typedef struct {
26 const char* name;
27 int var_offset;
David 'Digit' Turner318e4f22009-05-25 18:01:03 +020028 int var_type;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080029 int var_is_config;
30} OptionInfo;
31
32#define OPTION(_name,_type,_config) \
33 { #_name, offsetof(AndroidOptions,_name), _type, _config },
34
35
36static const OptionInfo option_keys[] = {
David 'Digit' Turner318e4f22009-05-25 18:01:03 +020037#define OPT_FLAG(_name,_descr) OPTION(_name,OPTION_IS_FLAG,0)
38#define OPT_PARAM(_name,_template,_descr) OPTION(_name,OPTION_IS_PARAM,0)
39#define OPT_LIST(_name,_template,_descr) OPTION(_name,OPTION_IS_LIST,0)
40#define CFG_FLAG(_name,_descr) OPTION(_name,OPTION_IS_FLAG,1)
41#define CFG_PARAM(_name,_template,_descr) OPTION(_name,OPTION_IS_PARAM,1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080042#include "android/cmdline-options.h"
43 { NULL, 0, 0, 0 }
44};
45
46int
47android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
48{
49 int nargs = *pargc-1;
50 char** aread = *pargv+1;
51 char** awrite = aread;
52
53 memset( opt, 0, sizeof *opt );
54
55 while (nargs > 0) {
56 char* arg;
57 char arg2_tab[64], *arg2 = arg2_tab;
58 int nn;
59
60 /* process @<name> as a special exception meaning
61 * '-avd <name>'
62 */
63 if (aread[0][0] == '@') {
64 opt->avd = aread[0]+1;
65 nargs--;
66 aread++;
67 continue;
68 }
69
70 /* anything that isn't an option past this points
71 * exits the loop
72 */
73 if (aread[0][0] != '-') {
74 break;
75 }
76
77 arg = aread[0]+1;
78
79 /* an option cannot contain an underscore */
80 if (strchr(arg, '_') != NULL) {
81 break;
82 }
83
84 nargs--;
85 aread++;
86
87 /* for backwards compatibility with previous versions */
88 if (!strcmp(arg, "verbose")) {
89 arg = "debug-init";
90 }
91
92 /* special handing for -debug <tags> */
93 if (!strcmp(arg, "debug")) {
94 if (nargs == 0) {
95 derror( "-debug must be followed by tags (see -help-verbose)\n");
96 exit(1);
97 }
98 nargs--;
99 parse_debug_tags(*aread++);
100 continue;
101 }
102
103 /* NOTE: variable tables map option names to values
104 * (e.g. field offsets into the AndroidOptions structure).
105 *
106 * however, the names stored in the table used underscores
107 * instead of dashes. this means that the command-line option
108 * '-foo-bar' will be associated to the name 'foo_bar' in
109 * this table, and will point to the field 'foo_bar' or
110 * AndroidOptions.
111 *
112 * as such, before comparing the current option to the
113 * content of the table, we're going to translate dashes
114 * into underscores.
115 */
116 arg2 = arg2_tab;
117 buffer_translate_char( arg2_tab, sizeof(arg2_tab),
118 arg, '-', '_');
119
120 /* special handling for -debug-<tag> and -debug-no-<tag> */
121 if (!memcmp(arg2, "debug_", 6)) {
122 int remove = 0;
123 unsigned long mask = 0;
124 arg2 += 6;
125 if (!memcmp(arg2, "no_", 3)) {
126 arg2 += 3;
127 remove = 1;
128 }
129 if (!strcmp(arg2, "all")) {
130 mask = ~0;
131 }
132 for (nn = 0; debug_tags[nn].name; nn++) {
133 if (!strcmp(arg2, debug_tags[nn].name)) {
134 mask = (1UL << debug_tags[nn].flag);
135 break;
136 }
137 }
138 if (remove)
139 android_verbose &= ~mask;
140 else
141 android_verbose |= mask;
142 continue;
143 }
144
145 /* look into our table of options
146 *
147 */
148 {
149 const OptionInfo* oo = option_keys;
150
151 for ( ; oo->name; oo++ ) {
152 if ( !strcmp( oo->name, arg2 ) ) {
153 void* field = (char*)opt + oo->var_offset;
154
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200155 if (oo->var_type != OPTION_IS_FLAG) {
156 /* parameter/list option */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800157 if (nargs == 0) {
158 derror( "-%s must be followed by parameter (see -help-%s)",
159 arg, arg );
160 exit(1);
161 }
162 nargs--;
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200163
164 if (oo->var_type == OPTION_IS_PARAM)
165 {
166 ((char**)field)[0] = *aread++;
167 }
168 else if (oo->var_type == OPTION_IS_LIST)
169 {
170 ParamList** head = (ParamList**)field;
171 ParamList* pl;
172 ANEW0(pl);
173 /* note: store list items in reverse order here
174 * the list is reversed later in this function.
175 */
176 pl->param = *aread++;
177 pl->next = *head;
178 *head = pl;
179 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800180 } else {
181 /* flag option */
182 ((int*)field)[0] = 1;
183 }
184 break;
185 }
186 }
187
188 if (oo->name == NULL) { /* unknown option ? */
189 nargs++;
190 aread--;
191 break;
192 }
193 }
194 }
195
196 /* copy remaining parameters, if any, to command line */
197 *pargc = nargs + 1;
198
199 while (nargs > 0) {
200 awrite[0] = aread[0];
201 awrite ++;
202 aread ++;
203 nargs --;
204 }
205
206 awrite[0] = NULL;
207
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200208 /* reverse any parameter list before exit.
209 */
210 {
211 const OptionInfo* oo = option_keys;
212
213 for ( ; oo->name; oo++ ) {
214 if ( oo->var_type == OPTION_IS_LIST ) {
215 ParamList** head = (ParamList**)((char*)opt + oo->var_offset);
216 ParamList* prev = NULL;
217 ParamList* cur = *head;
218
219 while (cur != NULL) {
220 ParamList* next = cur->next;
221 cur->next = prev;
222 prev = cur;
223 cur = next;
224 }
225 *head = prev;
226 }
227 }
228 }
229
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800230 return 0;
231}
232
233
234
235/* special handling of -debug option and tags */
236#define ENV_DEBUG "ANDROID_DEBUG"
237
238static void
239parse_debug_tags( const char* tags )
240{
241 char* x;
242 char* y;
243 char* x0;
244
245 if (tags == NULL)
246 return;
247
248 x = x0 = strdup(tags);
249 while (*x) {
250 y = strchr(x, ',');
251 if (y == NULL)
252 y = x + strlen(x);
253 else
254 *y++ = 0;
255
256 if (y > x+1) {
257 int nn, remove = 0;
258 unsigned mask = 0;
259
260 if (x[0] == '-') {
261 remove = 1;
262 x += 1;
263 }
264
265 if (!strcmp( "all", x ))
266 mask = ~0;
267 else {
268 char temp[32];
269 buffer_translate_char(temp, sizeof temp, x, '-', '_');
270
271 for (nn = 0; debug_tags[nn].name != NULL; nn++) {
272 if ( !strcmp( debug_tags[nn].name, temp ) ) {
273 mask |= (1 << debug_tags[nn].flag);
274 break;
275 }
276 }
277 }
278
279 if (mask == 0)
280 dprint( "ignoring unknown " ENV_DEBUG " item '%s'", x );
281 else {
282 if (remove)
283 android_verbose &= ~mask;
284 else
285 android_verbose |= mask;
286 }
287 }
288 x = y;
289 }
290
291 free(x0);
292}
293
294void
295parse_env_debug_tags( void )
296{
297 const char* env = getenv( ENV_DEBUG );
298 parse_debug_tags( env );
299}
300