blob: 50a0ba488327e765fe48eaaf7fed05e10dd1006f [file] [log] [blame]
The Android Open Source Project9066cfe2009-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) {
Joe Onorato7add83b2011-08-30 17:24:17 -070032 if (d->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033 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 Turner066aa992010-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 Project9066cfe2009-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 }
Joe Onorato7add83b2011-08-30 17:24:17 -0700245 else if (items->item_type == INTERFACE_TYPE_BINDER
246 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 interface_type* c = (interface_type*)items;
248 err |= check_filename(filename, c->package, &c->name);
249 }
250 else {
251 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
252 items->item_type);
253 return 1;
254 }
255 items = items->next;
256 }
257 return err;
258}
259
260// ==========================================================
261static const char*
262kind_to_string(int kind)
263{
264 switch (kind)
265 {
266 case Type::INTERFACE:
267 return "an interface";
268 case Type::PARCELABLE:
269 return "a parcelable";
270 default:
271 return "ERROR";
272 }
273}
274
275static char*
276rfind(char* str, char c)
277{
278 char* p = str + strlen(str) - 1;
279 while (p >= str) {
280 if (*p == c) {
281 return p;
282 }
283 p--;
284 }
285 return NULL;
286}
287
288static int
289gather_types(const char* filename, document_item_type* items)
290{
291 int err = 0;
292 while (items) {
293 Type* type;
294 if (items->item_type == PARCELABLE_TYPE) {
295 parcelable_type* p = (parcelable_type*)items;
296 type = new ParcelableType(p->package ? p->package : "",
297 p->name.data, false, filename, p->name.lineno);
298 }
Joe Onorato7add83b2011-08-30 17:24:17 -0700299 else if (items->item_type == INTERFACE_TYPE_BINDER
300 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 interface_type* c = (interface_type*)items;
302 type = new InterfaceType(c->package ? c->package : "",
303 c->name.data, false, c->oneway,
304 filename, c->name.lineno);
305 }
306 else {
307 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
308 return 1;
309 }
310
311 Type* old = NAMES.Find(type->QualifiedName());
312 if (old == NULL) {
313 NAMES.Add(type);
314
Joe Onorato7add83b2011-08-30 17:24:17 -0700315 if (items->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 // for interfaces, also add the stub and proxy types, we don't
317 // bother checking these for duplicates, because the parser
318 // won't let us do it.
319 interface_type* c = (interface_type*)items;
320
321 string name = c->name.data;
322 name += ".Stub";
323 Type* stub = new Type(c->package ? c->package : "",
324 name, Type::GENERATED, false, false,
325 filename, c->name.lineno);
326 NAMES.Add(stub);
327
328 name = c->name.data;
329 name += ".Stub.Proxy";
330 Type* proxy = new Type(c->package ? c->package : "",
331 name, Type::GENERATED, false, false,
332 filename, c->name.lineno);
333 NAMES.Add(proxy);
334 }
Joe Onorato7add83b2011-08-30 17:24:17 -0700335 else if (items->item_type == INTERFACE_TYPE_RPC) {
336 // for interfaces, also add the service base type, we don't
337 // bother checking these for duplicates, because the parser
338 // won't let us do it.
339 interface_type* c = (interface_type*)items;
340
341 string name = c->name.data;
342 name += ".ServiceBase";
343 Type* base = new Type(c->package ? c->package : "",
344 name, Type::GENERATED, false, false,
345 filename, c->name.lineno);
346 NAMES.Add(base);
347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 } else {
349 if (old->Kind() == Type::BUILT_IN) {
350 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
351 filename, type->DeclLine(),
352 type->QualifiedName().c_str());
353 err = 1;
354 }
355 else if (type->Kind() != old->Kind()) {
356 const char* oldKind = kind_to_string(old->Kind());
357 const char* newKind = kind_to_string(type->Kind());
358
359 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
360 filename, type->DeclLine(),
361 type->QualifiedName().c_str(), newKind);
362 fprintf(stderr, "%s:%d previously defined here as %s.\n",
363 old->DeclFile().c_str(), old->DeclLine(), oldKind);
364 err = 1;
365 }
366 }
367
368 items = items->next;
369 }
370 return err;
371}
372
373// ==========================================================
374static bool
375matches_keyword(const char* str)
376{
377 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
378 "byte", "case", "catch", "char", "class", "const", "continue",
379 "default", "do", "double", "else", "enum", "extends", "final",
380 "finally", "float", "for", "goto", "if", "implements", "import",
381 "instanceof", "int", "interface", "long", "native", "new", "package",
382 "private", "protected", "public", "return", "short", "static",
383 "strictfp", "super", "switch", "synchronized", "this", "throw",
384 "throws", "transient", "try", "void", "volatile", "while",
385 "true", "false", "null",
386 NULL
387 };
388 const char** k = KEYWORDS;
389 while (*k) {
390 if (0 == strcmp(str, *k)) {
391 return true;
392 }
393 k++;
394 }
395 return false;
396}
397
398static int
399check_method(const char* filename, method_type* m)
400{
401 int err = 0;
402
403 // return type
404 Type* returnType = NAMES.Search(m->type.type.data);
405 if (returnType == NULL) {
406 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
407 m->type.type.lineno, m->type.type.data);
408 err = 1;
409 return err;
410 }
411
412 if (!returnType->CanBeMarshalled()) {
413 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
414 m->type.type.lineno, m->type.type.data);
415 err = 1;
416 }
417
418 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
419 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
420 m->type.array_token.lineno, m->type.type.data,
421 m->type.array_token.data);
422 err = 1;
423 }
424
425 if (m->type.dimension > 1) {
426 fprintf(stderr, "%s:%d return type %s%s only one"
427 " dimensional arrays are supported\n", filename,
428 m->type.array_token.lineno, m->type.type.data,
429 m->type.array_token.data);
430 err = 1;
431 }
432
433 int index = 1;
434
435 arg_type* arg = m->args;
436 while (arg) {
437 Type* t = NAMES.Search(arg->type.type.data);
438
439 // check the arg type
440 if (t == NULL) {
441 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
442 filename, m->type.type.lineno, arg->name.data, index,
443 arg->type.type.data);
444 err = 1;
445 goto next;
446 }
447
448 if (!t->CanBeMarshalled()) {
449 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
450 filename, m->type.type.lineno, index,
451 arg->type.type.data, arg->name.data);
452 err = 1;
453 }
454
455 if (arg->direction.data == NULL
456 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
457 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
458 " parameter, so you must declare it as in,"
459 " out or inout.\n",
460 filename, m->type.type.lineno, index,
461 arg->type.type.data, arg->name.data);
462 err = 1;
463 }
464
465 if (convert_direction(arg->direction.data) != IN_PARAMETER
466 && !t->CanBeOutParameter()
467 && arg->type.dimension == 0) {
468 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
469 " parameter.\n",
470 filename, m->type.type.lineno, index,
471 arg->direction.data, arg->type.type.data,
472 arg->name.data);
473 err = 1;
474 }
475
476 if (arg->type.dimension > 0 && !t->CanBeArray()) {
477 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
478 " array.\n", filename,
479 m->type.array_token.lineno, index, arg->direction.data,
480 arg->type.type.data, arg->type.array_token.data,
481 arg->name.data);
482 err = 1;
483 }
484
485 if (arg->type.dimension > 1) {
486 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
487 " dimensional arrays are supported\n", filename,
488 m->type.array_token.lineno, index, arg->direction.data,
489 arg->type.type.data, arg->type.array_token.data,
490 arg->name.data);
491 err = 1;
492 }
493
494 // check that the name doesn't match a keyword
495 if (matches_keyword(arg->name.data)) {
496 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
497 " Java keyword\n",
498 filename, m->name.lineno, index, arg->name.data);
499 err = 1;
500 }
501
502next:
503 index++;
504 arg = arg->next;
505 }
506
507 return err;
508}
509
510static int
511check_types(const char* filename, document_item_type* items)
512{
513 int err = 0;
514 while (items) {
515 // (nothing to check for PARCELABLE_TYPE)
Joe Onorato7add83b2011-08-30 17:24:17 -0700516 if (items->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 map<string,method_type*> methodNames;
518 interface_type* c = (interface_type*)items;
519
520 interface_item_type* member = c->interface_items;
521 while (member) {
522 if (member->item_type == METHOD_TYPE) {
523 method_type* m = (method_type*)member;
524
525 err |= check_method(filename, m);
526
527 // prevent duplicate methods
528 if (methodNames.find(m->name.data) == methodNames.end()) {
529 methodNames[m->name.data] = m;
530 } else {
531 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
532 filename, m->name.lineno, m->name.data);
533 method_type* old = methodNames[m->name.data];
534 fprintf(stderr, "%s:%d previously defined here.\n",
535 filename, old->name.lineno);
536 err = 1;
537 }
538 }
539 member = member->next;
540 }
541 }
542
543 items = items->next;
544 }
545 return err;
546}
547
548// ==========================================================
549static int
550exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
551 bool* onlyParcelable)
552{
553 if (items == NULL) {
554 fprintf(stderr, "%s: file does not contain any interfaces\n",
555 filename);
556 return 1;
557 }
558
559 const document_item_type* next = items->next;
560 if (items->next != NULL) {
561 int lineno = -1;
Joe Onorato7add83b2011-08-30 17:24:17 -0700562 if (next->item_type == INTERFACE_TYPE_BINDER) {
563 lineno = ((interface_type*)next)->interface_token.lineno;
564 }
565 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 lineno = ((interface_type*)next)->interface_token.lineno;
567 }
568 else if (next->item_type == PARCELABLE_TYPE) {
569 lineno = ((parcelable_type*)next)->parcelable_token.lineno;
570 }
571 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
572 filename, lineno);
573 return 1;
574 }
575
576 if (items->item_type == PARCELABLE_TYPE) {
577 *onlyParcelable = true;
578 if (options.failOnParcelable) {
579 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
580 " parcelables,\n", filename,
581 ((parcelable_type*)items)->parcelable_token.lineno);
582 fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
583 "don't need to go in the Makefile.\n", filename,
584 ((parcelable_type*)items)->parcelable_token.lineno);
585 return 1;
586 }
587 } else {
588 *onlyParcelable = false;
589 }
590
591 return 0;
592}
593
594// ==========================================================
595void
596generate_dep_file(const Options& options)
597{
598 /* we open the file in binary mode to ensure that the same output is
599 * generated on all platforms !!
600 */
601 FILE* to = fopen(options.depFileName.c_str(), "wb");
602 if (to == NULL) {
603 return;
604 }
605
606 const char* slash = "\\";
607 import_info* import = g_imports;
608 if (import == NULL) {
609 slash = "";
610 }
611
612 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
613 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
614
615 while (import) {
616 if (import->next == NULL) {
617 slash = "";
618 }
619 if (import->filename) {
620 fprintf(to, " %s %s\n", import->filename, slash);
621 }
622 import = import->next;
623 }
624
625 fprintf(to, "\n");
626
627 fclose(to);
628}
629
630// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700631static string
632generate_outputFileName(const Options& options, const document_item_type* items)
633{
634 string result;
635
636 // items has already been checked to have only one interface.
Joe Onorato7add83b2011-08-30 17:24:17 -0700637 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700638 interface_type* type = (interface_type*)items;
639
640 // create the path to the destination folder based on the
641 // interface package name
642 result = options.outputBaseFolder;
643 result += OS_PATH_SEPARATOR;
644
645 string package = type->package;
646 size_t len = package.length();
647 for (size_t i=0; i<len; i++) {
648 if (package[i] == '.') {
649 package[i] = OS_PATH_SEPARATOR;
650 }
651 }
652
653 result += package;
654
655 // add the filename by replacing the .aidl extension to .java
656 const char* p = strchr(type->name.data, '.');
657 len = p ? p-type->name.data : strlen(type->name.data);
658
659 result += OS_PATH_SEPARATOR;
660 result.append(type->name.data, len);
661 result += ".java";
662 }
663
664 return result;
665}
666
667// ==========================================================
668static void
669check_outputFileName(const string& path) {
670 size_t len = path.length();
671 for (size_t i=0; i<len ; i++) {
672 if (path[i] == OS_PATH_SEPARATOR) {
673 string p = path.substr(0, i);
674 if (access(path.data(), F_OK) != 0) {
675#ifdef HAVE_MS_C_RUNTIME
676 _mkdir(p.data());
677#else
678 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
679#endif
680 }
681 }
682 }
683}
684
685
686// ==========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687static int
688parse_preprocessed_file(const string& filename)
689{
690 int err;
691
692 FILE* f = fopen(filename.c_str(), "rb");
693 if (f == NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800694 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 filename.c_str());
696 return 1;
697 }
698
699 int lineno = 1;
700 char line[1024];
701 char type[1024];
702 char fullname[1024];
703 while (fgets(line, sizeof(line), f)) {
704 // skip comments and empty lines
705 if (!line[0] || strncmp(line, "//", 2) == 0) {
706 continue;
707 }
708
709 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
710
711 char* packagename;
712 char* classname = rfind(fullname, '.');
713 if (classname != NULL) {
714 *classname = '\0';
715 classname++;
716 packagename = fullname;
717 } else {
718 classname = fullname;
719 packagename = NULL;
720 }
721
722 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
723 // type, packagename, classname);
724 document_item_type* doc;
725
726 if (0 == strcmp("parcelable", type)) {
727 parcelable_type* parcl = (parcelable_type*)malloc(
728 sizeof(parcelable_type));
729 memset(parcl, 0, sizeof(parcelable_type));
730 parcl->document_item.item_type = PARCELABLE_TYPE;
731 parcl->parcelable_token.lineno = lineno;
732 parcl->parcelable_token.data = strdup(type);
733 parcl->package = packagename ? strdup(packagename) : NULL;
734 parcl->name.lineno = lineno;
735 parcl->name.data = strdup(classname);
736 parcl->semicolon_token.lineno = lineno;
737 parcl->semicolon_token.data = strdup(";");
738 doc = (document_item_type*)parcl;
739 }
740 else if (0 == strcmp("interface", type)) {
741 interface_type* iface = (interface_type*)malloc(
742 sizeof(interface_type));
743 memset(iface, 0, sizeof(interface_type));
Joe Onorato7add83b2011-08-30 17:24:17 -0700744 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 iface->interface_token.lineno = lineno;
746 iface->interface_token.data = strdup(type);
747 iface->package = packagename ? strdup(packagename) : NULL;
748 iface->name.lineno = lineno;
749 iface->name.data = strdup(classname);
750 iface->open_brace_token.lineno = lineno;
751 iface->open_brace_token.data = strdup("{");
752 iface->close_brace_token.lineno = lineno;
753 iface->close_brace_token.data = strdup("}");
754 doc = (document_item_type*)iface;
755 }
756 else {
757 fprintf(stderr, "%s:%d: bad type in line: %s\n",
758 filename.c_str(), lineno, line);
759 return 1;
760 }
761 err = gather_types(filename.c_str(), doc);
762 lineno++;
763 }
764
765 if (!feof(f)) {
766 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
767 filename.c_str(), lineno);
768 return 1;
769 }
770
771 fclose(f);
772 return 0;
773}
774
775// ==========================================================
776static int
777compile_aidl(const Options& options)
778{
779 int err = 0, N;
780
781 set_import_paths(options.importPaths);
782
783 register_base_types();
784
785 // import the preprocessed file
786 N = options.preprocessedFiles.size();
787 for (int i=0; i<N; i++) {
788 const string& s = options.preprocessedFiles[i];
789 err |= parse_preprocessed_file(s);
790 }
791 if (err != 0) {
792 return err;
793 }
794
795 // parse the main file
796 g_callbacks = &g_mainCallbacks;
797 err = parse_aidl(options.inputFileName.c_str());
798 document_item_type* mainDoc = g_document;
799 g_document = NULL;
800
801 // parse the imports
802 g_callbacks = &g_mainCallbacks;
803 import_info* import = g_imports;
804 while (import) {
805 if (NAMES.Find(import->neededClass) == NULL) {
806 import->filename = find_import_file(import->neededClass);
807 if (!import->filename) {
808 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
809 import->from, import->statement.lineno,
810 import->neededClass);
811 err |= 1;
812 } else {
813 err |= parse_aidl(import->filename);
814 import->doc = g_document;
815 if (import->doc == NULL) {
816 err |= 1;
817 }
818 }
819 }
820 import = import->next;
821 }
822 // bail out now if parsing wasn't successful
823 if (err != 0 || mainDoc == NULL) {
824 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
825 return 1;
826 }
827
828 // complain about ones that aren't in the right files
829 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
830 import = g_imports;
831 while (import) {
832 err |= check_filenames(import->filename, import->doc);
833 import = import->next;
834 }
835
836 // gather the types that have been declared
837 err |= gather_types(options.inputFileName.c_str(), mainDoc);
838 import = g_imports;
839 while (import) {
840 err |= gather_types(import->filename, import->doc);
841 import = import->next;
842 }
843
844#if 0
845 printf("---- main doc ----\n");
846 test_document(mainDoc);
847
848 import = g_imports;
849 while (import) {
850 printf("---- import doc ----\n");
851 test_document(import->doc);
852 import = import->next;
853 }
854 NAMES.Dump();
855#endif
856
857 // check the referenced types in mainDoc to make sure we've imported them
858 err |= check_types(options.inputFileName.c_str(), mainDoc);
859
860 // finally, there really only needs to be one thing in mainDoc, and it
861 // needs to be an interface.
862 bool onlyParcelable = false;
863 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
864
865 // after this, there shouldn't be any more errors because of the
866 // input.
867 if (err != 0 || mainDoc == NULL) {
868 return 1;
869 }
870
871 // they didn't ask to fail on parcelables, so just exit quietly.
872 if (onlyParcelable && !options.failOnParcelable) {
873 return 0;
874 }
875
876 // if we were asked to, generate a make dependency file
877 if (options.depFileName != "") {
878 generate_dep_file(options);
879 }
880
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700881 // if needed, generate the outputFileName from the outputBaseFolder
882 string outputFileName = options.outputFileName;
883 if (outputFileName.length() == 0 &&
884 options.outputBaseFolder.length() > 0) {
885 outputFileName = generate_outputFileName(options, mainDoc);
886 }
887
888 // make sure the folders of the output file all exists
889 check_outputFileName(outputFileName);
890
891 err = generate_java(outputFileName, options.inputFileName.c_str(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 (interface_type*)mainDoc);
893
894 return err;
895}
896
897static int
898preprocess_aidl(const Options& options)
899{
900 vector<string> lines;
901 int err;
902
903 // read files
904 int N = options.filesToPreprocess.size();
905 for (int i=0; i<N; i++) {
906 g_callbacks = &g_mainCallbacks;
907 err = parse_aidl(options.filesToPreprocess[i].c_str());
908 if (err != 0) {
909 return err;
910 }
911 document_item_type* doc = g_document;
912 string line;
913 if (doc->item_type == PARCELABLE_TYPE) {
914 line = "parcelable ";
915 parcelable_type* parcelable = (parcelable_type*)doc;
916 if (parcelable->package) {
917 line += parcelable->package;
918 line += '.';
919 }
920 line += parcelable->name.data;
921 } else {
922 line = "interface ";
923 interface_type* iface = (interface_type*)doc;
924 if (iface->package) {
925 line += iface->package;
926 line += '.';
927 }
928 line += iface->name.data;
929 }
930 line += ";\n";
931 lines.push_back(line);
932 }
933
934 // write preprocessed file
935 int fd = open( options.outputFileName.c_str(),
936 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
937#ifdef HAVE_MS_C_RUNTIME
938 _S_IREAD|_S_IWRITE);
939#else
940 S_IRUSR|S_IWUSR|S_IRGRP);
941#endif
942 if (fd == -1) {
943 fprintf(stderr, "aidl: could not open file for write: %s\n",
944 options.outputFileName.c_str());
945 return 1;
946 }
947
948 N = lines.size();
949 for (int i=0; i<N; i++) {
950 const string& s = lines[i];
951 int len = s.length();
952 if (len != write(fd, s.c_str(), len)) {
953 fprintf(stderr, "aidl: error writing to file %s\n",
954 options.outputFileName.c_str());
955 close(fd);
956 unlink(options.outputFileName.c_str());
957 return 1;
958 }
959 }
960
961 close(fd);
962 return 0;
963}
964
965// ==========================================================
966int
967main(int argc, const char **argv)
968{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 Options options;
970 int result = parse_options(argc, argv, &options);
971 if (result) {
972 return result;
973 }
974
975 switch (options.task)
976 {
977 case COMPILE_AIDL:
978 return compile_aidl(options);
979 case PREPROCESS_AIDL:
980 return preprocess_aidl(options);
981 }
982 fprintf(stderr, "aidl: internal error\n");
983 return 1;
984}
985
986