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