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