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 },
10static const struct { const char*  name; int  flag; const char*  text; }
11debug_tags[] = {
12    VERBOSE_TAG_LIST
13    { 0, 0, 0 }
14};
15
16static void  parse_debug_tags( const char*  tags );
17void  parse_env_debug_tags( void );
18
19enum {
20    OPTION_IS_FLAG = 0,
21    OPTION_IS_PARAM,
22    OPTION_IS_LIST,
23};
24
25typedef 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
36static 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
46int
47android_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
238static void
239parse_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
294void
295parse_env_debug_tags( void )
296{
297    const char*  env = getenv( ENV_DEBUG );
298    parse_debug_tags( env );
299}
300
301