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