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