• 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%08x d->item_type=%ld\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)
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 = fopen(options.depFileName.c_str(), "wb");
584     if (to == NULL) {
585         return;
586     }
587 
588     const char* slash = "\\";
589     import_info* import = g_imports;
590     if (import == NULL) {
591         slash = "";
592     }
593 
594     fprintf(to, "%s: \\\n", options.outputFileName.c_str());
595     fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
596 
597     while (import) {
598         if (import->next == NULL) {
599             slash = "";
600         }
601         if (import->filename) {
602             fprintf(to, "  %s %s\n", import->filename, slash);
603         }
604         import = import->next;
605     }
606 
607     fprintf(to, "\n");
608 
609     fclose(to);
610 }
611 
612 // ==========================================================
613 static string
614 generate_outputFileName(const Options& options, const document_item_type* items)
615 {
616     string result;
617 
618     // items has already been checked to have only one interface.
619     if (items->item_type == INTERFACE_TYPE) {
620         interface_type* type = (interface_type*)items;
621 
622         // create the path to the destination folder based on the
623         // interface package name
624         result = options.outputBaseFolder;
625         result += OS_PATH_SEPARATOR;
626 
627         string package = type->package;
628         size_t len = package.length();
629         for (size_t i=0; i<len; i++) {
630             if (package[i] == '.') {
631                 package[i] = OS_PATH_SEPARATOR;
632             }
633         }
634 
635         result += package;
636 
637         // add the filename by replacing the .aidl extension to .java
638         const char* p = strchr(type->name.data, '.');
639         len = p ? p-type->name.data : strlen(type->name.data);
640 
641         result += OS_PATH_SEPARATOR;
642         result.append(type->name.data, len);
643         result += ".java";
644     }
645 
646     return result;
647 }
648 
649 // ==========================================================
650 static void
651 check_outputFileName(const string& path) {
652     size_t len = path.length();
653     for (size_t i=0; i<len ; i++) {
654         if (path[i] == OS_PATH_SEPARATOR) {
655             string p = path.substr(0, i);
656             if (access(path.data(), F_OK) != 0) {
657 #ifdef HAVE_MS_C_RUNTIME
658                 _mkdir(p.data());
659 #else
660                 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
661 #endif
662             }
663         }
664     }
665 }
666 
667 
668 // ==========================================================
669 static int
670 parse_preprocessed_file(const string& filename)
671 {
672     int err;
673 
674     FILE* f = fopen(filename.c_str(), "rb");
675     if (f == NULL) {
676         fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
677                 filename.c_str());
678         return 1;
679     }
680 
681     int lineno = 1;
682     char line[1024];
683     char type[1024];
684     char fullname[1024];
685     while (fgets(line, sizeof(line), f)) {
686         // skip comments and empty lines
687         if (!line[0] || strncmp(line, "//", 2) == 0) {
688           continue;
689         }
690 
691         sscanf(line, "%s %[^; \r\n\t];", type, fullname);
692 
693         char* packagename;
694         char* classname = rfind(fullname, '.');
695         if (classname != NULL) {
696             *classname = '\0';
697             classname++;
698             packagename = fullname;
699         } else {
700             classname = fullname;
701             packagename = NULL;
702         }
703 
704         //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
705         //        type, packagename, classname);
706         document_item_type* doc;
707 
708         if (0 == strcmp("parcelable", type)) {
709             parcelable_type* parcl = (parcelable_type*)malloc(
710                     sizeof(parcelable_type));
711             memset(parcl, 0, sizeof(parcelable_type));
712             parcl->document_item.item_type = PARCELABLE_TYPE;
713             parcl->parcelable_token.lineno = lineno;
714             parcl->parcelable_token.data = strdup(type);
715             parcl->package = packagename ? strdup(packagename) : NULL;
716             parcl->name.lineno = lineno;
717             parcl->name.data = strdup(classname);
718             parcl->semicolon_token.lineno = lineno;
719             parcl->semicolon_token.data = strdup(";");
720             doc = (document_item_type*)parcl;
721         }
722         else if (0 == strcmp("interface", type)) {
723             interface_type* iface = (interface_type*)malloc(
724                     sizeof(interface_type));
725             memset(iface, 0, sizeof(interface_type));
726             iface->document_item.item_type = INTERFACE_TYPE;
727             iface->interface_token.lineno = lineno;
728             iface->interface_token.data = strdup(type);
729             iface->package = packagename ? strdup(packagename) : NULL;
730             iface->name.lineno = lineno;
731             iface->name.data = strdup(classname);
732             iface->open_brace_token.lineno = lineno;
733             iface->open_brace_token.data = strdup("{");
734             iface->close_brace_token.lineno = lineno;
735             iface->close_brace_token.data = strdup("}");
736             doc = (document_item_type*)iface;
737         }
738         else {
739             fprintf(stderr, "%s:%d: bad type in line: %s\n",
740                     filename.c_str(), lineno, line);
741             return 1;
742         }
743         err = gather_types(filename.c_str(), doc);
744         lineno++;
745     }
746 
747     if (!feof(f)) {
748         fprintf(stderr, "%s:%d: error reading file, line to long.\n",
749                 filename.c_str(), lineno);
750         return 1;
751     }
752 
753     fclose(f);
754     return 0;
755 }
756 
757 // ==========================================================
758 static int
759 compile_aidl(const Options& options)
760 {
761     int err = 0, N;
762 
763     set_import_paths(options.importPaths);
764 
765     register_base_types();
766 
767     // import the preprocessed file
768     N = options.preprocessedFiles.size();
769     for (int i=0; i<N; i++) {
770         const string& s = options.preprocessedFiles[i];
771         err |= parse_preprocessed_file(s);
772     }
773     if (err != 0) {
774         return err;
775     }
776 
777     // parse the main file
778     g_callbacks = &g_mainCallbacks;
779     err = parse_aidl(options.inputFileName.c_str());
780     document_item_type* mainDoc = g_document;
781     g_document = NULL;
782 
783     // parse the imports
784     g_callbacks = &g_mainCallbacks;
785     import_info* import = g_imports;
786     while (import) {
787         if (NAMES.Find(import->neededClass) == NULL) {
788             import->filename = find_import_file(import->neededClass);
789             if (!import->filename) {
790                 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
791                         import->from, import->statement.lineno,
792                         import->neededClass);
793                 err |= 1;
794             } else {
795                 err |= parse_aidl(import->filename);
796                 import->doc = g_document;
797                 if (import->doc == NULL) {
798                     err |= 1;
799                 }
800             }
801         }
802         import = import->next;
803     }
804     // bail out now if parsing wasn't successful
805     if (err != 0 || mainDoc == NULL) {
806         //fprintf(stderr, "aidl: parsing failed, stopping.\n");
807         return 1;
808     }
809 
810     // complain about ones that aren't in the right files
811     err |= check_filenames(options.inputFileName.c_str(), mainDoc);
812     import = g_imports;
813     while (import) {
814         err |= check_filenames(import->filename, import->doc);
815         import = import->next;
816     }
817 
818     // gather the types that have been declared
819     err |= gather_types(options.inputFileName.c_str(), mainDoc);
820     import = g_imports;
821     while (import) {
822         err |= gather_types(import->filename, import->doc);
823         import = import->next;
824     }
825 
826 #if 0
827     printf("---- main doc ----\n");
828     test_document(mainDoc);
829 
830     import = g_imports;
831     while (import) {
832         printf("---- import doc ----\n");
833         test_document(import->doc);
834         import = import->next;
835     }
836     NAMES.Dump();
837 #endif
838 
839     // check the referenced types in mainDoc to make sure we've imported them
840     err |= check_types(options.inputFileName.c_str(), mainDoc);
841 
842     // finally, there really only needs to be one thing in mainDoc, and it
843     // needs to be an interface.
844     bool onlyParcelable = false;
845     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
846 
847     // after this, there shouldn't be any more errors because of the
848     // input.
849     if (err != 0 || mainDoc == NULL) {
850         return 1;
851     }
852 
853     // they didn't ask to fail on parcelables, so just exit quietly.
854     if (onlyParcelable && !options.failOnParcelable) {
855         return 0;
856     }
857 
858     // if we were asked to, generate a make dependency file
859     if (options.depFileName != "") {
860         generate_dep_file(options);
861     }
862 
863     // if needed, generate the outputFileName from the outputBaseFolder
864     string outputFileName = options.outputFileName;
865     if (outputFileName.length() == 0 &&
866             options.outputBaseFolder.length() > 0) {
867         outputFileName = generate_outputFileName(options, mainDoc);
868     }
869 
870     // make sure the folders of the output file all exists
871     check_outputFileName(outputFileName);
872 
873     err = generate_java(outputFileName, options.inputFileName.c_str(),
874                         (interface_type*)mainDoc);
875 
876     return err;
877 }
878 
879 static int
880 preprocess_aidl(const Options& options)
881 {
882     vector<string> lines;
883     int err;
884 
885     // read files
886     int N = options.filesToPreprocess.size();
887     for (int i=0; i<N; i++) {
888         g_callbacks = &g_mainCallbacks;
889         err = parse_aidl(options.filesToPreprocess[i].c_str());
890         if (err != 0) {
891             return err;
892         }
893         document_item_type* doc = g_document;
894         string line;
895         if (doc->item_type == PARCELABLE_TYPE) {
896             line = "parcelable ";
897             parcelable_type* parcelable = (parcelable_type*)doc;
898             if (parcelable->package) {
899                 line += parcelable->package;
900                 line += '.';
901             }
902             line += parcelable->name.data;
903         } else {
904             line = "interface ";
905             interface_type* iface = (interface_type*)doc;
906             if (iface->package) {
907                 line += iface->package;
908                 line += '.';
909             }
910             line += iface->name.data;
911         }
912         line += ";\n";
913         lines.push_back(line);
914     }
915 
916     // write preprocessed file
917     int fd = open( options.outputFileName.c_str(),
918                    O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
919 #ifdef HAVE_MS_C_RUNTIME
920                    _S_IREAD|_S_IWRITE);
921 #else
922                    S_IRUSR|S_IWUSR|S_IRGRP);
923 #endif
924     if (fd == -1) {
925         fprintf(stderr, "aidl: could not open file for write: %s\n",
926                 options.outputFileName.c_str());
927         return 1;
928     }
929 
930     N = lines.size();
931     for (int i=0; i<N; i++) {
932         const string& s = lines[i];
933         int len = s.length();
934         if (len != write(fd, s.c_str(), len)) {
935             fprintf(stderr, "aidl: error writing to file %s\n",
936                 options.outputFileName.c_str());
937             close(fd);
938             unlink(options.outputFileName.c_str());
939             return 1;
940         }
941     }
942 
943     close(fd);
944     return 0;
945 }
946 
947 // ==========================================================
948 int
949 main(int argc, const char **argv)
950 {
951     int err = 0;
952 
953     Options options;
954     int result = parse_options(argc, argv, &options);
955     if (result) {
956         return result;
957     }
958 
959     switch (options.task)
960     {
961         case COMPILE_AIDL:
962             return compile_aidl(options);
963         case PREPROCESS_AIDL:
964             return preprocess_aidl(options);
965     }
966     fprintf(stderr, "aidl: internal error\n");
967     return 1;
968 }
969 
970 
971