The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 1 | #include "android/cmdline-option.h" |
| 2 | #include "android/utils/debug.h" |
| 3 | #include "android/utils/misc.h" |
David 'Digit' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 4 | #include "android/utils/system.h" |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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 | |
David 'Digit' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 19 | enum { |
| 20 | OPTION_IS_FLAG = 0, |
| 21 | OPTION_IS_PARAM, |
| 22 | OPTION_IS_LIST, |
| 23 | }; |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 24 | |
| 25 | typedef struct { |
| 26 | const char* name; |
| 27 | int var_offset; |
David 'Digit' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 28 | int var_type; |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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[] = { |
David 'Digit' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 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) |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 42 | #include "android/cmdline-options.h" |
| 43 | { NULL, 0, 0, 0 } |
| 44 | }; |
| 45 | |
| 46 | int |
| 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 | |
David 'Digit' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 155 | if (oo->var_type != OPTION_IS_FLAG) { |
| 156 | /* parameter/list option */ |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 157 | 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' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 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 | } |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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 | |
David 'Digit' Turner | 318e4f2 | 2009-05-25 18:01:03 +0200 | [diff] [blame^] | 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 | |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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 |
| 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 |
| 295 | parse_env_debug_tags( void ) |
| 296 | { |
| 297 | const char* env = getenv( ENV_DEBUG ); |
| 298 | parse_debug_tags( env ); |
| 299 | } |
| 300 | |