Home | History | Annotate | Download | only in android
      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