OSDN Git Service

am c38ffecc: Merge "Moving BTtraffic from experiment location to here" into cw-d...
[android-x86/frameworks-base.git] / tools / aidl / aidl.cpp
1
2 #include "aidl_language.h"
3 #include "options.h"
4 #include "search_path.h"
5 #include "Type.h"
6 #include "generate_java.h"
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <sys/param.h>
10 #include <sys/stat.h>
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <map>
16
17 #ifdef HAVE_MS_C_RUNTIME
18 #include <io.h>
19 #include <direct.h>
20 #include <sys/stat.h>
21 #endif
22
23 #ifndef O_BINARY
24 #  define O_BINARY  0
25 #endif
26
27 // The following are gotten as the offset from the allowable id's between
28 // android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
29 // android.os.IBinder.LAST_CALL_TRANSACTION=16777215
30 #define MIN_USER_SET_METHOD_ID                0
31 #define MAX_USER_SET_METHOD_ID                16777214
32
33 using namespace std;
34
35 static void
36 test_document(document_item_type* d)
37 {
38     while (d) {
39         if (d->item_type == INTERFACE_TYPE_BINDER) {
40             interface_type* c = (interface_type*)d;
41             printf("interface %s %s {\n", c->package, c->name.data);
42             interface_item_type *q = (interface_item_type*)c->interface_items;
43             while (q) {
44                 if (q->item_type == METHOD_TYPE) {
45                     method_type *m = (method_type*)q;
46                     printf("  %s %s(", m->type.type.data, m->name.data);
47                     arg_type *p = m->args;
48                     while (p) {
49                         printf("%s %s",p->type.type.data,p->name.data);
50                         if (p->next) printf(", ");
51                         p=p->next;
52                     }
53                     printf(")");
54                     printf(";\n");
55                 }
56                 q=q->next;
57             }
58             printf("}\n");
59         }
60         else if (d->item_type == USER_DATA_TYPE) {
61             user_data_type* b = (user_data_type*)d;
62             if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
63                 printf("parcelable %s %s;\n", b->package, b->name.data);
64             }
65             if ((b->flattening_methods & RPC_DATA) != 0) {
66                 printf("flattenable %s %s;\n", b->package, b->name.data);
67             }
68         }
69         else {
70             printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
71         }
72         d = d->next;
73     }
74 }
75
76 // ==========================================================
77 int
78 convert_direction(const char* direction)
79 {
80     if (direction == NULL) {
81         return IN_PARAMETER;
82     }
83     if (0 == strcmp(direction, "in")) {
84         return IN_PARAMETER;
85     }
86     if (0 == strcmp(direction, "out")) {
87         return OUT_PARAMETER;
88     }
89     return INOUT_PARAMETER;
90 }
91
92 // ==========================================================
93 struct import_info {
94     const char* from;
95     const char* filename;
96     buffer_type statement;
97     const char* neededClass;
98     document_item_type* doc;
99     struct import_info* next;
100 };
101
102 document_item_type* g_document = NULL;
103 import_info* g_imports = NULL;
104
105 static void
106 main_document_parsed(document_item_type* d)
107 {
108     g_document = d;
109 }
110
111 static void
112 main_import_parsed(buffer_type* statement)
113 {
114     import_info* import = (import_info*)malloc(sizeof(import_info));
115     memset(import, 0, sizeof(import_info));
116     import->from = strdup(g_currentFilename);
117     import->statement.lineno = statement->lineno;
118     import->statement.data = strdup(statement->data);
119     import->statement.extra = NULL;
120     import->next = g_imports;
121     import->neededClass = parse_import_statement(statement->data);
122     g_imports = import;
123 }
124
125 static ParserCallbacks g_mainCallbacks = {
126     &main_document_parsed,
127     &main_import_parsed
128 };
129
130 char*
131 parse_import_statement(const char* text)
132 {
133     const char* end;
134     int len;
135
136     while (isspace(*text)) {
137         text++;
138     }
139     while (!isspace(*text)) {
140         text++;
141     }
142     while (isspace(*text)) {
143         text++;
144     }
145     end = text;
146     while (!isspace(*end) && *end != ';') {
147         end++;
148     }
149     len = end-text;
150
151     char* rv = (char*)malloc(len+1);
152     memcpy(rv, text, len);
153     rv[len] = '\0';
154
155     return rv;
156 }
157
158 // ==========================================================
159 static void
160 import_import_parsed(buffer_type* statement)
161 {
162 }
163
164 static ParserCallbacks g_importCallbacks = {
165     &main_document_parsed,
166     &import_import_parsed
167 };
168
169 // ==========================================================
170 static int
171 check_filename(const char* filename, const char* package, buffer_type* name)
172 {
173     const char* p;
174     string expected;
175     string fn;
176     size_t len;
177     char cwd[MAXPATHLEN];
178     bool valid = false;
179
180 #ifdef HAVE_WINDOWS_PATHS
181     if (isalpha(filename[0]) && filename[1] == ':'
182         && filename[2] == OS_PATH_SEPARATOR) {
183 #else
184     if (filename[0] == OS_PATH_SEPARATOR) {
185 #endif
186         fn = filename;
187     } else {
188         fn = getcwd(cwd, sizeof(cwd));
189         len = fn.length();
190         if (fn[len-1] != OS_PATH_SEPARATOR) {
191             fn += OS_PATH_SEPARATOR;
192         }
193         fn += filename;
194     }
195
196     if (package) {
197         expected = package;
198         expected += '.';
199     }
200
201     len = expected.length();
202     for (size_t i=0; i<len; i++) {
203         if (expected[i] == '.') {
204             expected[i] = OS_PATH_SEPARATOR;
205         }
206     }
207
208     p = strchr(name->data, '.');
209     len = p ? p-name->data : strlen(name->data);
210     expected.append(name->data, len);
211     
212     expected += ".aidl";
213
214     len = fn.length();
215     valid = (len >= expected.length());
216
217     if (valid) {
218         p = fn.c_str() + (len - expected.length());
219
220 #ifdef HAVE_WINDOWS_PATHS
221         if (OS_PATH_SEPARATOR != '/') {
222             // Input filename under cygwin most likely has / separators
223             // whereas the expected string uses \\ separators. Adjust
224             // them accordingly.
225           for (char *c = const_cast<char *>(p); *c; ++c) {
226                 if (*c == '/') *c = OS_PATH_SEPARATOR;
227             }
228         }
229 #endif
230
231         // aidl assumes case-insensitivity on Mac Os and Windows.
232 #if defined(__linux__)
233         valid = (expected == p);
234 #else
235         valid = !strcasecmp(expected.c_str(), p);
236 #endif
237     }
238
239     if (!valid) {
240         fprintf(stderr, "%s:%d interface %s should be declared in a file"
241                 " called %s.\n",
242                 filename, name->lineno, name->data, expected.c_str());
243         return 1;
244     }
245
246     return 0;
247 }
248
249 static int
250 check_filenames(const char* filename, document_item_type* items)
251 {
252     int err = 0;
253     while (items) {
254         if (items->item_type == USER_DATA_TYPE) {
255             user_data_type* p = (user_data_type*)items;
256             err |= check_filename(filename, p->package, &p->name);
257         }
258         else if (items->item_type == INTERFACE_TYPE_BINDER
259                 || items->item_type == INTERFACE_TYPE_RPC) {
260             interface_type* c = (interface_type*)items;
261             err |= check_filename(filename, c->package, &c->name);
262         }
263         else {
264             fprintf(stderr, "aidl: internal error unkown document type %d.\n",
265                         items->item_type);
266             return 1;
267         }
268         items = items->next;
269     }
270     return err;
271 }
272
273 // ==========================================================
274 static const char*
275 kind_to_string(int kind)
276 {
277     switch (kind)
278     {
279         case Type::INTERFACE:
280             return "an interface";
281         case Type::USERDATA:
282             return "a user data";
283         default:
284             return "ERROR";
285     }
286 }
287
288 static char*
289 rfind(char* str, char c)
290 {
291     char* p = str + strlen(str) - 1;
292     while (p >= str) {
293         if (*p == c) {
294             return p;
295         }
296         p--;
297     }
298     return NULL;
299 }
300
301 static int
302 gather_types(const char* filename, document_item_type* items)
303 {
304     int err = 0;
305     while (items) {
306         Type* type;
307         if (items->item_type == USER_DATA_TYPE) {
308             user_data_type* p = (user_data_type*)items;
309             type = new UserDataType(p->package ? p->package : "", p->name.data,
310                     false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
311                     ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
312         }
313         else if (items->item_type == INTERFACE_TYPE_BINDER
314                 || items->item_type == INTERFACE_TYPE_RPC) {
315             interface_type* c = (interface_type*)items;
316             type = new InterfaceType(c->package ? c->package : "",
317                             c->name.data, false, c->oneway,
318                             filename, c->name.lineno);
319         }
320         else {
321             fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
322             return 1;
323         }
324
325         Type* old = NAMES.Find(type->QualifiedName());
326         if (old == NULL) {
327             NAMES.Add(type);
328
329             if (items->item_type == INTERFACE_TYPE_BINDER) {
330                 // for interfaces, also add the stub and proxy types, we don't
331                 // bother checking these for duplicates, because the parser
332                 // won't let us do it.
333                 interface_type* c = (interface_type*)items;
334
335                 string name = c->name.data;
336                 name += ".Stub";
337                 Type* stub = new Type(c->package ? c->package : "",
338                                         name, Type::GENERATED, false, false, false,
339                                         filename, c->name.lineno);
340                 NAMES.Add(stub);
341
342                 name = c->name.data;
343                 name += ".Stub.Proxy";
344                 Type* proxy = new Type(c->package ? c->package : "",
345                                         name, Type::GENERATED, false, false, false,
346                                         filename, c->name.lineno);
347                 NAMES.Add(proxy);
348             }
349             else if (items->item_type == INTERFACE_TYPE_RPC) {
350                 // for interfaces, also add the service base type, we don't
351                 // bother checking these for duplicates, because the parser
352                 // won't let us do it.
353                 interface_type* c = (interface_type*)items;
354
355                 string name = c->name.data;
356                 name += ".ServiceBase";
357                 Type* base = new Type(c->package ? c->package : "",
358                                         name, Type::GENERATED, false, false, false,
359                                         filename, c->name.lineno);
360                 NAMES.Add(base);
361             }
362         } else {
363             if (old->Kind() == Type::BUILT_IN) {
364                 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
365                             filename, type->DeclLine(),
366                             type->QualifiedName().c_str());
367                 err = 1;
368             }
369             else if (type->Kind() != old->Kind()) {
370                 const char* oldKind = kind_to_string(old->Kind());
371                 const char* newKind = kind_to_string(type->Kind());
372
373                 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
374                             filename, type->DeclLine(),
375                             type->QualifiedName().c_str(), newKind);
376                 fprintf(stderr, "%s:%d    previously defined here as %s.\n",
377                             old->DeclFile().c_str(), old->DeclLine(), oldKind);
378                 err = 1;
379             }
380         }
381
382         items = items->next;
383     }
384     return err;
385 }
386
387 // ==========================================================
388 static bool
389 matches_keyword(const char* str)
390 {
391     static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
392         "byte", "case", "catch", "char", "class", "const", "continue",
393         "default", "do", "double", "else", "enum", "extends", "final",
394         "finally", "float", "for", "goto", "if", "implements", "import",
395         "instanceof", "int", "interface", "long", "native", "new", "package",
396         "private", "protected", "public", "return", "short", "static",
397         "strictfp", "super", "switch", "synchronized", "this", "throw",
398         "throws", "transient", "try", "void", "volatile", "while",
399         "true", "false", "null",
400         NULL
401     };
402     const char** k = KEYWORDS;
403     while (*k) {
404         if (0 == strcmp(str, *k)) {
405             return true;
406         }
407         k++;
408     }
409     return false;
410 }
411
412 static int
413 check_method(const char* filename, int kind, method_type* m)
414 {
415     int err = 0;
416
417     // return type
418     Type* returnType = NAMES.Search(m->type.type.data);
419     if (returnType == NULL) {
420         fprintf(stderr, "%s:%d unknown return type %s\n", filename,
421                     m->type.type.lineno, m->type.type.data);
422         err = 1;
423         return err;
424     }
425
426     if (returnType == EVENT_FAKE_TYPE) {
427         if (kind != INTERFACE_TYPE_RPC) {
428             fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
429                     filename, m->type.type.lineno);
430             err = 1;
431         }
432     } else {
433         if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
434                     : returnType->CanWriteToRpcData())) {
435             fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
436                         m->type.type.lineno, m->type.type.data);
437             err = 1;
438         }
439     }
440
441     if (m->type.dimension > 0 && !returnType->CanBeArray()) {
442         fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
443                 m->type.array_token.lineno, m->type.type.data,
444                 m->type.array_token.data);
445         err = 1;
446     }
447
448     if (m->type.dimension > 1) {
449         fprintf(stderr, "%s:%d return type %s%s only one"
450                 " dimensional arrays are supported\n", filename,
451                 m->type.array_token.lineno, m->type.type.data,
452                 m->type.array_token.data);
453         err = 1;
454     }
455
456     int index = 1;
457
458     arg_type* arg = m->args;
459     while (arg) {
460         Type* t = NAMES.Search(arg->type.type.data);
461
462         // check the arg type
463         if (t == NULL) {
464             fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
465                     filename, m->type.type.lineno, arg->name.data, index,
466                     arg->type.type.data);
467             err = 1;
468             goto next;
469         }
470
471         if (t == EVENT_FAKE_TYPE) {
472             fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
473                     filename, m->type.type.lineno, arg->name.data, index,
474                     arg->type.type.data);
475             err = 1;
476             goto next;
477         }
478         
479         if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
480             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
481                         filename, m->type.type.lineno, index,
482                         arg->type.type.data, arg->name.data);
483             err = 1;
484         }
485
486         if (returnType == EVENT_FAKE_TYPE
487                 && convert_direction(arg->direction.data) != IN_PARAMETER) {
488             fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
489                     filename, m->type.type.lineno, index,
490                     arg->type.type.data, arg->name.data);
491             err = 1;
492             goto next;
493         }
494
495         if (arg->direction.data == NULL
496                 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
497             fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
498                                 " parameter, so you must declare it as in,"
499                                 " out or inout.\n",
500                         filename, m->type.type.lineno, index,
501                         arg->type.type.data, arg->name.data);
502             err = 1;
503         }
504
505         if (convert_direction(arg->direction.data) != IN_PARAMETER
506                 && !t->CanBeOutParameter()
507                 && arg->type.dimension == 0) {
508             fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
509                             " parameter.\n",
510                         filename, m->type.type.lineno, index,
511                         arg->direction.data, arg->type.type.data,
512                         arg->name.data);
513             err = 1;
514         }
515
516         if (arg->type.dimension > 0 && !t->CanBeArray()) {
517             fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
518                     " array.\n", filename,
519                     m->type.array_token.lineno, index, arg->direction.data,
520                     arg->type.type.data, arg->type.array_token.data,
521                     arg->name.data);
522             err = 1;
523         }
524
525         if (arg->type.dimension > 1) {
526             fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
527                     " dimensional arrays are supported\n", filename,
528                     m->type.array_token.lineno, index, arg->direction.data,
529                     arg->type.type.data, arg->type.array_token.data,
530                     arg->name.data);
531             err = 1;
532         }
533
534         // check that the name doesn't match a keyword
535         if (matches_keyword(arg->name.data)) {
536             fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
537                     " Java or aidl keyword\n",
538                     filename, m->name.lineno, index, arg->name.data);
539             err = 1;
540         }
541         
542 next:
543         index++;
544         arg = arg->next;
545     }
546
547     return err;
548 }
549
550 static int
551 check_types(const char* filename, document_item_type* items)
552 {
553     int err = 0;
554     while (items) {
555         // (nothing to check for USER_DATA_TYPE)
556         if (items->item_type == INTERFACE_TYPE_BINDER
557                 || items->item_type == INTERFACE_TYPE_RPC) {
558             map<string,method_type*> methodNames;
559             interface_type* c = (interface_type*)items;
560
561             interface_item_type* member = c->interface_items;
562             while (member) {
563                 if (member->item_type == METHOD_TYPE) {
564                     method_type* m = (method_type*)member;
565
566                     err |= check_method(filename, items->item_type, m);
567
568                     // prevent duplicate methods
569                     if (methodNames.find(m->name.data) == methodNames.end()) {
570                         methodNames[m->name.data] = m;
571                     } else {
572                         fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
573                                 filename, m->name.lineno, m->name.data);
574                         method_type* old = methodNames[m->name.data];
575                         fprintf(stderr, "%s:%d    previously defined here.\n",
576                                 filename, old->name.lineno);
577                         err = 1;
578                     }
579                 }
580                 member = member->next;
581             }
582         }
583
584         items = items->next;
585     }
586     return err;
587 }
588
589 // ==========================================================
590 static int
591 exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
592                       bool* onlyParcelable)
593 {
594     if (items == NULL) {
595         fprintf(stderr, "%s: file does not contain any interfaces\n",
596                             filename);
597         return 1;
598     }
599
600     const document_item_type* next = items->next;
601     // Allow parcelables to skip the "one-only" rule.
602     if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
603         int lineno = -1;
604         if (next->item_type == INTERFACE_TYPE_BINDER) {
605             lineno = ((interface_type*)next)->interface_token.lineno;
606         }
607         else if (next->item_type == INTERFACE_TYPE_RPC) {
608             lineno = ((interface_type*)next)->interface_token.lineno;
609         }
610         fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
611                             filename, lineno);
612         return 1;
613     }
614
615     if (items->item_type == USER_DATA_TYPE) {
616         *onlyParcelable = true;
617         if (options.failOnParcelable) {
618             fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
619                             " parcelables or flattenables,\n", filename,
620                             ((user_data_type*)items)->keyword_token.lineno);
621             fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
622                             "may not go in the Makefile.\n", filename,
623                             ((user_data_type*)items)->keyword_token.lineno);
624             return 1;
625         }
626     } else {
627         *onlyParcelable = false;
628     }
629
630     return 0;
631 }
632
633 // ==========================================================
634 void
635 generate_dep_file(const Options& options, const document_item_type* items)
636 {
637     /* we open the file in binary mode to ensure that the same output is
638      * generated on all platforms !!
639      */
640     FILE* to = NULL;
641     if (options.autoDepFile) {
642         string fileName = options.outputFileName + ".d";
643         to = fopen(fileName.c_str(), "wb");
644     } else {
645         to = fopen(options.depFileName.c_str(), "wb");
646     }
647
648     if (to == NULL) {
649         return;
650     }
651
652     const char* slash = "\\";
653     import_info* import = g_imports;
654     if (import == NULL) {
655         slash = "";
656     }
657
658     if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
659         fprintf(to, "%s: \\\n", options.outputFileName.c_str());
660     } else {
661         // parcelable: there's no output file.
662         fprintf(to, " : \\\n");
663     }
664     fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
665
666     while (import) {
667         if (import->next == NULL) {
668             slash = "";
669         }
670         if (import->filename) {
671             fprintf(to, "  %s %s\n", import->filename, slash);
672         }
673         import = import->next;
674     }
675
676     fprintf(to, "\n");
677
678     // Output "<imported_file>: " so make won't fail if the imported file has
679     // been deleted, moved or renamed in incremental build.
680     import = g_imports;
681     while (import) {
682         if (import->filename) {
683             fprintf(to, "%s :\n", import->filename);
684         }
685         import = import->next;
686     }
687
688     fclose(to);
689 }
690
691 // ==========================================================
692 static string
693 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
694 {
695     string result;
696
697     // create the path to the destination folder based on the
698     // interface package name
699     result = options.outputBaseFolder;
700     result += OS_PATH_SEPARATOR;
701
702     string packageStr = package;
703     size_t len = packageStr.length();
704     for (size_t i=0; i<len; i++) {
705         if (packageStr[i] == '.') {
706             packageStr[i] = OS_PATH_SEPARATOR;
707         }
708     }
709
710     result += packageStr;
711
712     // add the filename by replacing the .aidl extension to .java
713     const char* p = strchr(name.data, '.');
714     len = p ? p-name.data : strlen(name.data);
715
716     result += OS_PATH_SEPARATOR;
717     result.append(name.data, len);
718     result += ".java";
719
720     return result;
721 }
722
723 // ==========================================================
724 static string
725 generate_outputFileName(const Options& options, const document_item_type* items)
726 {
727     // items has already been checked to have only one interface.
728     if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
729         interface_type* type = (interface_type*)items;
730
731         return generate_outputFileName2(options, type->name, type->package);
732     } else if (items->item_type == USER_DATA_TYPE) {
733         user_data_type* type = (user_data_type*)items;
734         return generate_outputFileName2(options, type->name, type->package);
735     }
736
737     // I don't think we can come here, but safer than returning NULL.
738     string result;
739     return result;
740 }
741
742
743
744 // ==========================================================
745 static void
746 check_outputFilePath(const string& path) {
747     size_t len = path.length();
748     for (size_t i=0; i<len ; i++) {
749         if (path[i] == OS_PATH_SEPARATOR) {
750             string p = path.substr(0, i);
751             if (access(path.data(), F_OK) != 0) {
752 #ifdef HAVE_MS_C_RUNTIME
753                 _mkdir(p.data());
754 #else
755                 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
756 #endif
757             }
758         }
759     }
760 }
761
762
763 // ==========================================================
764 static int
765 parse_preprocessed_file(const string& filename)
766 {
767     int err;
768
769     FILE* f = fopen(filename.c_str(), "rb");
770     if (f == NULL) {
771         fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
772                 filename.c_str());
773         return 1;
774     }
775
776     int lineno = 1;
777     char line[1024];
778     char type[1024];
779     char fullname[1024];
780     while (fgets(line, sizeof(line), f)) {
781         // skip comments and empty lines
782         if (!line[0] || strncmp(line, "//", 2) == 0) {
783           continue;
784         }
785
786         sscanf(line, "%s %[^; \r\n\t];", type, fullname);
787
788         char* packagename;
789         char* classname = rfind(fullname, '.');
790         if (classname != NULL) {
791             *classname = '\0';
792             classname++;
793             packagename = fullname;
794         } else {
795             classname = fullname;
796             packagename = NULL;
797         }
798
799         //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
800         //        type, packagename, classname);
801         document_item_type* doc;
802         
803         if (0 == strcmp("parcelable", type)) {
804             user_data_type* parcl = (user_data_type*)malloc(
805                     sizeof(user_data_type));
806             memset(parcl, 0, sizeof(user_data_type));
807             parcl->document_item.item_type = USER_DATA_TYPE;
808             parcl->keyword_token.lineno = lineno;
809             parcl->keyword_token.data = strdup(type);
810             parcl->package = packagename ? strdup(packagename) : NULL;
811             parcl->name.lineno = lineno;
812             parcl->name.data = strdup(classname);
813             parcl->semicolon_token.lineno = lineno;
814             parcl->semicolon_token.data = strdup(";");
815             parcl->flattening_methods = PARCELABLE_DATA;
816             doc = (document_item_type*)parcl;
817         }
818         else if (0 == strcmp("flattenable", type)) {
819             user_data_type* parcl = (user_data_type*)malloc(
820                     sizeof(user_data_type));
821             memset(parcl, 0, sizeof(user_data_type));
822             parcl->document_item.item_type = USER_DATA_TYPE;
823             parcl->keyword_token.lineno = lineno;
824             parcl->keyword_token.data = strdup(type);
825             parcl->package = packagename ? strdup(packagename) : NULL;
826             parcl->name.lineno = lineno;
827             parcl->name.data = strdup(classname);
828             parcl->semicolon_token.lineno = lineno;
829             parcl->semicolon_token.data = strdup(";");
830             parcl->flattening_methods = RPC_DATA;
831             doc = (document_item_type*)parcl;
832         }
833         else if (0 == strcmp("interface", type)) {
834             interface_type* iface = (interface_type*)malloc(
835                     sizeof(interface_type));
836             memset(iface, 0, sizeof(interface_type));
837             iface->document_item.item_type = INTERFACE_TYPE_BINDER;
838             iface->interface_token.lineno = lineno;
839             iface->interface_token.data = strdup(type);
840             iface->package = packagename ? strdup(packagename) : NULL;
841             iface->name.lineno = lineno;
842             iface->name.data = strdup(classname);
843             iface->open_brace_token.lineno = lineno;
844             iface->open_brace_token.data = strdup("{");
845             iface->close_brace_token.lineno = lineno;
846             iface->close_brace_token.data = strdup("}");
847             doc = (document_item_type*)iface;
848         }
849         else {
850             fprintf(stderr, "%s:%d: bad type in line: %s\n",
851                     filename.c_str(), lineno, line);
852             fclose(f);
853             return 1;
854         }
855         err = gather_types(filename.c_str(), doc);
856         lineno++;
857     }
858
859     if (!feof(f)) {
860         fprintf(stderr, "%s:%d: error reading file, line to long.\n",
861                 filename.c_str(), lineno);
862         return 1;
863     }
864
865     fclose(f);
866     return 0;
867 }
868
869 static int
870 check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
871 {
872     // Check whether there are any methods with manually assigned id's and any that are not.
873     // Either all method id's must be manually assigned or all of them must not.
874     // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
875     set<int> usedIds;
876     interface_item_type* item = first_item;
877     bool hasUnassignedIds = false;
878     bool hasAssignedIds = false;
879     while (item != NULL) {
880         if (item->item_type == METHOD_TYPE) {
881             method_type* method_item = (method_type*)item;
882             if (method_item->hasId) {
883                 hasAssignedIds = true;
884                 method_item->assigned_id = atoi(method_item->id.data);
885                 // Ensure that the user set id is not duplicated.
886                 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
887                     // We found a duplicate id, so throw an error.
888                     fprintf(stderr,
889                             "%s:%d Found duplicate method id (%d) for method: %s\n",
890                             filename, method_item->id.lineno,
891                             method_item->assigned_id, method_item->name.data);
892                     return 1;
893                 }
894                 // Ensure that the user set id is within the appropriate limits
895                 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
896                         method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
897                     fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
898                             filename, method_item->id.lineno,
899                             method_item->assigned_id, method_item->name.data);
900                     fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
901                             MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
902                     return 1;
903                 }
904                 usedIds.insert(method_item->assigned_id);
905             } else {
906                 hasUnassignedIds = true;
907             }
908             if (hasAssignedIds && hasUnassignedIds) {
909                 fprintf(stderr,
910                         "%s: You must either assign id's to all methods or to none of them.\n",
911                         filename);
912                 return 1;
913             }
914         }
915         item = item->next;
916     }
917
918     // In the case that all methods have unassigned id's, set a unique id for them.
919     if (hasUnassignedIds) {
920         int newId = 0;
921         item = first_item;
922         while (item != NULL) {
923             if (item->item_type == METHOD_TYPE) {
924                 method_type* method_item = (method_type*)item;
925                 method_item->assigned_id = newId++;
926             }
927             item = item->next;
928         }
929     }
930
931     // success
932     return 0;
933 }
934
935 // ==========================================================
936 static int
937 compile_aidl(Options& options)
938 {
939     int err = 0, N;
940
941     set_import_paths(options.importPaths);
942
943     register_base_types();
944
945     // import the preprocessed file
946     N = options.preprocessedFiles.size();
947     for (int i=0; i<N; i++) {
948         const string& s = options.preprocessedFiles[i];
949         err |= parse_preprocessed_file(s);
950     }
951     if (err != 0) {
952         return err;
953     }
954
955     // parse the main file
956     g_callbacks = &g_mainCallbacks;
957     err = parse_aidl(options.inputFileName.c_str());
958     document_item_type* mainDoc = g_document;
959     g_document = NULL;
960
961     // parse the imports
962     g_callbacks = &g_mainCallbacks;
963     import_info* import = g_imports;
964     while (import) {
965         if (NAMES.Find(import->neededClass) == NULL) {
966             import->filename = find_import_file(import->neededClass);
967             if (!import->filename) {
968                 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
969                         import->from, import->statement.lineno,
970                         import->neededClass);
971                 err |= 1;
972             } else {
973                 err |= parse_aidl(import->filename);
974                 import->doc = g_document;
975                 if (import->doc == NULL) {
976                     err |= 1;
977                 }
978             }
979         }
980         import = import->next;
981     }
982     // bail out now if parsing wasn't successful
983     if (err != 0 || mainDoc == NULL) {
984         //fprintf(stderr, "aidl: parsing failed, stopping.\n");
985         return 1;
986     }
987
988     // complain about ones that aren't in the right files
989     err |= check_filenames(options.inputFileName.c_str(), mainDoc);
990     import = g_imports;
991     while (import) {
992         err |= check_filenames(import->filename, import->doc);
993         import = import->next;
994     }
995
996     // gather the types that have been declared
997     err |= gather_types(options.inputFileName.c_str(), mainDoc);
998     import = g_imports;
999     while (import) {
1000         err |= gather_types(import->filename, import->doc);
1001         import = import->next;
1002     }
1003
1004 #if 0
1005     printf("---- main doc ----\n");
1006     test_document(mainDoc);
1007
1008     import = g_imports;
1009     while (import) {
1010         printf("---- import doc ----\n");
1011         test_document(import->doc);
1012         import = import->next;
1013     }
1014     NAMES.Dump();
1015 #endif
1016
1017     // check the referenced types in mainDoc to make sure we've imported them
1018     err |= check_types(options.inputFileName.c_str(), mainDoc);
1019
1020     // finally, there really only needs to be one thing in mainDoc, and it
1021     // needs to be an interface.
1022     bool onlyParcelable = false;
1023     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
1024
1025     // If this includes an interface definition, then assign method ids and validate.
1026     if (!onlyParcelable) {
1027         err |= check_and_assign_method_ids(options.inputFileName.c_str(),
1028                 ((interface_type*)mainDoc)->interface_items);
1029     }
1030
1031     // after this, there shouldn't be any more errors because of the
1032     // input.
1033     if (err != 0 || mainDoc == NULL) {
1034         return 1;
1035     }
1036
1037     // if needed, generate the outputFileName from the outputBaseFolder
1038     if (options.outputFileName.length() == 0 &&
1039             options.outputBaseFolder.length() > 0) {
1040         options.outputFileName = generate_outputFileName(options, mainDoc);
1041     }
1042
1043     // if we were asked to, generate a make dependency file
1044     // unless it's a parcelable *and* it's supposed to fail on parcelable
1045     if ((options.autoDepFile || options.depFileName != "") &&
1046             !(onlyParcelable && options.failOnParcelable)) {
1047         // make sure the folders of the output file all exists
1048         check_outputFilePath(options.outputFileName);
1049         generate_dep_file(options, mainDoc);
1050     }
1051
1052     // they didn't ask to fail on parcelables, so just exit quietly.
1053     if (onlyParcelable && !options.failOnParcelable) {
1054         return 0;
1055     }
1056
1057     // make sure the folders of the output file all exists
1058     check_outputFilePath(options.outputFileName);
1059
1060     err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1061                         (interface_type*)mainDoc);
1062
1063     return err;
1064 }
1065
1066 static int
1067 preprocess_aidl(const Options& options)
1068 {
1069     vector<string> lines;
1070     int err;
1071
1072     // read files
1073     int N = options.filesToPreprocess.size();
1074     for (int i=0; i<N; i++) {
1075         g_callbacks = &g_mainCallbacks;
1076         err = parse_aidl(options.filesToPreprocess[i].c_str());
1077         if (err != 0) {
1078             return err;
1079         }
1080         document_item_type* doc = g_document;
1081         string line;
1082         if (doc->item_type == USER_DATA_TYPE) {
1083             user_data_type* parcelable = (user_data_type*)doc;
1084             if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
1085                 line = "parcelable ";
1086             }
1087             if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1088                 line = "flattenable ";
1089             }
1090             if (parcelable->package) {
1091                 line += parcelable->package;
1092                 line += '.';
1093             }
1094             line += parcelable->name.data;
1095         } else {
1096             line = "interface ";
1097             interface_type* iface = (interface_type*)doc;
1098             if (iface->package) {
1099                 line += iface->package;
1100                 line += '.';
1101             }
1102             line += iface->name.data;
1103         }
1104         line += ";\n";
1105         lines.push_back(line);
1106     }
1107
1108     // write preprocessed file
1109     int fd = open( options.outputFileName.c_str(), 
1110                    O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1111 #ifdef HAVE_MS_C_RUNTIME
1112                    _S_IREAD|_S_IWRITE);
1113 #else    
1114                    S_IRUSR|S_IWUSR|S_IRGRP);
1115 #endif            
1116     if (fd == -1) {
1117         fprintf(stderr, "aidl: could not open file for write: %s\n",
1118                 options.outputFileName.c_str());
1119         return 1;
1120     }
1121
1122     N = lines.size();
1123     for (int i=0; i<N; i++) {
1124         const string& s = lines[i];
1125         int len = s.length();
1126         if (len != write(fd, s.c_str(), len)) {
1127             fprintf(stderr, "aidl: error writing to file %s\n",
1128                 options.outputFileName.c_str());
1129             close(fd);
1130             unlink(options.outputFileName.c_str());
1131             return 1;
1132         }
1133     }
1134
1135     close(fd);
1136     return 0;
1137 }
1138
1139 // ==========================================================
1140 int
1141 main(int argc, const char **argv)
1142 {
1143     Options options;
1144     int result = parse_options(argc, argv, &options);
1145     if (result) {
1146         return result;
1147     }
1148
1149     switch (options.task)
1150     {
1151         case COMPILE_AIDL:
1152             return compile_aidl(options);
1153         case PREPROCESS_AIDL:
1154             return preprocess_aidl(options);
1155     }
1156     fprintf(stderr, "aidl: internal error\n");
1157     return 1;
1158 }