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 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 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 301