1 #include "android/cmdline-option.h"
2 #include "android/utils/debug.h"
3 #include "android/utils/misc.h"
4 #include "android/utils/system.h"
5 #include <stdlib.h>
6 #include <stddef.h>
7 #include <string.h>
8
9 #define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
10 static const struct { const char* name; int flag; const char* text; }
11 debug_tags[] = {
12 VERBOSE_TAG_LIST
13 { 0, 0, 0 }
14 };
15
16 static void parse_debug_tags( const char* tags );
17 void parse_env_debug_tags( void );
18
19 enum {
20 OPTION_IS_FLAG = 0,
21 OPTION_IS_PARAM,
22 OPTION_IS_LIST,
23 };
24
25 typedef struct {
26 const char* name;
27 int var_offset;
28 int var_type;
29 int var_is_config;
30 } OptionInfo;
31
32 #define OPTION(_name,_type,_config) \
33 { #_name, offsetof(AndroidOptions,_name), _type, _config },
34
35
36 static const OptionInfo option_keys[] = {
37 #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)
42 #include "android/cmdline-options.h"
43 { NULL, 0, 0, 0 }
44 };
45
46 int
android_parse_options(int * pargc,char *** pargv,AndroidOptions * opt)47 android_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
155 if (oo->var_type != OPTION_IS_FLAG) {
156 /* parameter/list option */
157 if (nargs == 0) {
158 derror( "-%s must be followed by parameter (see -help-%s)",
159 arg, arg );
160 exit(1);
161 }
162 nargs--;
163
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 }
180 } 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
208 /* 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
230 return 0;
231 }
232
233
234
235 /* special handling of -debug option and tags */
236 #define ENV_DEBUG "ANDROID_DEBUG"
237
238 static void
parse_debug_tags(const char * tags)239 parse_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
294 void
parse_env_debug_tags(void)295 parse_env_debug_tags( void )
296 {
297 const char* env = getenv( ENV_DEBUG );
298 parse_debug_tags( env );
299 }
300
301