• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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