blob: fb5aa23c9e1108a9409fc17efd064039e3c4ee50 [file] [log] [blame]
#include "android/cmdline-option.h"
#include "android/utils/debug.h"
#include "android/utils/misc.h"
#include "android/utils/system.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
static const struct { const char* name; int flag; const char* text; }
debug_tags[] = {
VERBOSE_TAG_LIST
{ 0, 0, 0 }
};
static void parse_debug_tags( const char* tags );
void parse_env_debug_tags( void );
enum {
OPTION_IS_FLAG = 0,
OPTION_IS_PARAM,
OPTION_IS_LIST,
};
typedef struct {
const char* name;
int var_offset;
int var_type;
int var_is_config;
} OptionInfo;
#define OPTION(_name,_type,_config) \
{ #_name, offsetof(AndroidOptions,_name), _type, _config },
static const OptionInfo option_keys[] = {
#define OPT_FLAG(_name,_descr) OPTION(_name,OPTION_IS_FLAG,0)
#define OPT_PARAM(_name,_template,_descr) OPTION(_name,OPTION_IS_PARAM,0)
#define OPT_LIST(_name,_template,_descr) OPTION(_name,OPTION_IS_LIST,0)
#define CFG_FLAG(_name,_descr) OPTION(_name,OPTION_IS_FLAG,1)
#define CFG_PARAM(_name,_template,_descr) OPTION(_name,OPTION_IS_PARAM,1)
#include "android/cmdline-options.h"
{ NULL, 0, 0, 0 }
};
int
android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
{
int nargs = *pargc-1;
char** aread = *pargv+1;
char** awrite = aread;
memset( opt, 0, sizeof *opt );
while (nargs > 0) {
char* arg;
char arg2_tab[64], *arg2 = arg2_tab;
int nn;
/* process @<name> as a special exception meaning
* '-avd <name>'
*/
if (aread[0][0] == '@') {
opt->avd = aread[0]+1;
nargs--;
aread++;
continue;
}
/* anything that isn't an option past this points
* exits the loop
*/
if (aread[0][0] != '-') {
break;
}
arg = aread[0]+1;
/* an option cannot contain an underscore */
if (strchr(arg, '_') != NULL) {
break;
}
nargs--;
aread++;
/* for backwards compatibility with previous versions */
if (!strcmp(arg, "verbose")) {
arg = "debug-init";
}
/* special handing for -debug <tags> */
if (!strcmp(arg, "debug")) {
if (nargs == 0) {
derror( "-debug must be followed by tags (see -help-verbose)\n");
exit(1);
}
nargs--;
parse_debug_tags(*aread++);
continue;
}
/* NOTE: variable tables map option names to values
* (e.g. field offsets into the AndroidOptions structure).
*
* however, the names stored in the table used underscores
* instead of dashes. this means that the command-line option
* '-foo-bar' will be associated to the name 'foo_bar' in
* this table, and will point to the field 'foo_bar' or
* AndroidOptions.
*
* as such, before comparing the current option to the
* content of the table, we're going to translate dashes
* into underscores.
*/
arg2 = arg2_tab;
buffer_translate_char( arg2_tab, sizeof(arg2_tab),
arg, '-', '_');
/* special handling for -debug-<tag> and -debug-no-<tag> */
if (!memcmp(arg2, "debug_", 6)) {
int remove = 0;
unsigned long mask = 0;
arg2 += 6;
if (!memcmp(arg2, "no_", 3)) {
arg2 += 3;
remove = 1;
}
if (!strcmp(arg2, "all")) {
mask = ~0;
}
for (nn = 0; debug_tags[nn].name; nn++) {
if (!strcmp(arg2, debug_tags[nn].name)) {
mask = (1UL << debug_tags[nn].flag);
break;
}
}
if (remove)
android_verbose &= ~mask;
else
android_verbose |= mask;
continue;
}
/* look into our table of options
*
*/
{
const OptionInfo* oo = option_keys;
for ( ; oo->name; oo++ ) {
if ( !strcmp( oo->name, arg2 ) ) {
void* field = (char*)opt + oo->var_offset;
if (oo->var_type != OPTION_IS_FLAG) {
/* parameter/list option */
if (nargs == 0) {
derror( "-%s must be followed by parameter (see -help-%s)",
arg, arg );
exit(1);
}
nargs--;
if (oo->var_type == OPTION_IS_PARAM)
{
((char**)field)[0] = *aread++;
}
else if (oo->var_type == OPTION_IS_LIST)
{
ParamList** head = (ParamList**)field;
ParamList* pl;
ANEW0(pl);
/* note: store list items in reverse order here
* the list is reversed later in this function.
*/
pl->param = *aread++;
pl->next = *head;
*head = pl;
}
} else {
/* flag option */
((int*)field)[0] = 1;
}
break;
}
}
if (oo->name == NULL) { /* unknown option ? */
nargs++;
aread--;
break;
}
}
}
/* copy remaining parameters, if any, to command line */
*pargc = nargs + 1;
while (nargs > 0) {
awrite[0] = aread[0];
awrite ++;
aread ++;
nargs --;
}
awrite[0] = NULL;
/* reverse any parameter list before exit.
*/
{
const OptionInfo* oo = option_keys;
for ( ; oo->name; oo++ ) {
if ( oo->var_type == OPTION_IS_LIST ) {
ParamList** head = (ParamList**)((char*)opt + oo->var_offset);
ParamList* prev = NULL;
ParamList* cur = *head;
while (cur != NULL) {
ParamList* next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
*head = prev;
}
}
}
return 0;
}
/* special handling of -debug option and tags */
#define ENV_DEBUG "ANDROID_DEBUG"
static void
parse_debug_tags( const char* tags )
{
char* x;
char* y;
char* x0;
if (tags == NULL)
return;
x = x0 = strdup(tags);
while (*x) {
y = strchr(x, ',');
if (y == NULL)
y = x + strlen(x);
else
*y++ = 0;
if (y > x+1) {
int nn, remove = 0;
unsigned mask = 0;
if (x[0] == '-') {
remove = 1;
x += 1;
}
if (!strcmp( "all", x ))
mask = ~0;
else {
char temp[32];
buffer_translate_char(temp, sizeof temp, x, '-', '_');
for (nn = 0; debug_tags[nn].name != NULL; nn++) {
if ( !strcmp( debug_tags[nn].name, temp ) ) {
mask |= (1 << debug_tags[nn].flag);
break;
}
}
}
if (mask == 0)
dprint( "ignoring unknown " ENV_DEBUG " item '%s'", x );
else {
if (remove)
android_verbose &= ~mask;
else
android_verbose |= mask;
}
}
x = y;
}
free(x0);
}
void
parse_env_debug_tags( void )
{
const char* env = getenv( ENV_DEBUG );
parse_debug_tags( env );
}