blob: f17f66b31f8e9d95415dbac7f95ad5db3a0ae2d5 [file] [log] [blame]
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -08001
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
26using namespace std;
27
28static void
29test_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 {
Scott Turner2c3d74b2010-01-14 21:05:17 -050058 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -080059 }
60 d = d->next;
61 }
62}
63
64// ==========================================================
65int
66convert_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// ==========================================================
81struct 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
90document_item_type* g_document = NULL;
91import_info* g_imports = NULL;
92
93static void
94main_document_parsed(document_item_type* d)
95{
96 g_document = d;
97}
98
99static void
100main_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
113static ParserCallbacks g_mainCallbacks = {
114 &main_document_parsed,
115 &main_import_parsed
116};
117
118char*
119parse_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// ==========================================================
147static void
148import_import_parsed(buffer_type* statement)
149{
150}
151
152static ParserCallbacks g_importCallbacks = {
153 &main_document_parsed,
154 &import_import_parsed
155};
156
157// ==========================================================
158static int
159check_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
236static int
237check_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// ==========================================================
260static const char*
261kind_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
274static char*
275rfind(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
287static int
288gather_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// ==========================================================
359static bool
360matches_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
383static int
384check_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
487next:
488 index++;
489 arg = arg->next;
490 }
491
492 return err;
493}
494
495static int
496check_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// ==========================================================
534static int
535exactly_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// ==========================================================
577void
578generate_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// ==========================================================
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700613static string
614generate_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// ==========================================================
650static void
651check_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// ==========================================================
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800669static int
670parse_preprocessed_file(const string& filename)
671{
672 int err;
673
674 FILE* f = fopen(filename.c_str(), "rb");
675 if (f == NULL) {
The Android Open Source Projected7bd9d2009-03-05 14:34:35 -0800676 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800677 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// ==========================================================
758static int
759compile_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
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700863 // 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(),
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800874 (interface_type*)mainDoc);
875
876 return err;
877}
878
879static int
880preprocess_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// ==========================================================
948int
949main(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