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