blob: c39e603a70a5b071dbb86b898ccb0711490f2364 [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 Onoratofdfe2ff2011-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 }
Joe Onorato7db766c2011-09-15 21:31:15 -070057 else if (d->item_type == FLATTENABLE_TYPE) {
58 parcelable_type* b = (parcelable_type*)d;
59 printf("flattenable %s %s;\n", b->package, b->name.data);
60 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 else {
Scott Turner066aa992010-01-14 21:05:17 -050062 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 -080063 }
64 d = d->next;
65 }
66}
67
68// ==========================================================
69int
70convert_direction(const char* direction)
71{
72 if (direction == NULL) {
73 return IN_PARAMETER;
74 }
75 if (0 == strcmp(direction, "in")) {
76 return IN_PARAMETER;
77 }
78 if (0 == strcmp(direction, "out")) {
79 return OUT_PARAMETER;
80 }
81 return INOUT_PARAMETER;
82}
83
84// ==========================================================
85struct import_info {
86 const char* from;
87 const char* filename;
88 buffer_type statement;
89 const char* neededClass;
90 document_item_type* doc;
91 struct import_info* next;
92};
93
94document_item_type* g_document = NULL;
95import_info* g_imports = NULL;
96
97static void
98main_document_parsed(document_item_type* d)
99{
100 g_document = d;
101}
102
103static void
104main_import_parsed(buffer_type* statement)
105{
106 import_info* import = (import_info*)malloc(sizeof(import_info));
107 memset(import, 0, sizeof(import_info));
108 import->from = strdup(g_currentFilename);
109 import->statement.lineno = statement->lineno;
110 import->statement.data = strdup(statement->data);
111 import->statement.extra = NULL;
112 import->next = g_imports;
113 import->neededClass = parse_import_statement(statement->data);
114 g_imports = import;
115}
116
117static ParserCallbacks g_mainCallbacks = {
118 &main_document_parsed,
119 &main_import_parsed
120};
121
122char*
123parse_import_statement(const char* text)
124{
125 const char* end;
126 int len;
127
128 while (isspace(*text)) {
129 text++;
130 }
131 while (!isspace(*text)) {
132 text++;
133 }
134 while (isspace(*text)) {
135 text++;
136 }
137 end = text;
138 while (!isspace(*end) && *end != ';') {
139 end++;
140 }
141 len = end-text;
142
143 char* rv = (char*)malloc(len+1);
144 memcpy(rv, text, len);
145 rv[len] = '\0';
146
147 return rv;
148}
149
150// ==========================================================
151static void
152import_import_parsed(buffer_type* statement)
153{
154}
155
156static ParserCallbacks g_importCallbacks = {
157 &main_document_parsed,
158 &import_import_parsed
159};
160
161// ==========================================================
162static int
163check_filename(const char* filename, const char* package, buffer_type* name)
164{
165 const char* p;
166 string expected;
167 string fn;
168 size_t len;
169 char cwd[MAXPATHLEN];
170 bool valid = false;
171
172#ifdef HAVE_WINDOWS_PATHS
173 if (isalpha(filename[0]) && filename[1] == ':'
174 && filename[2] == OS_PATH_SEPARATOR) {
175#else
176 if (filename[0] == OS_PATH_SEPARATOR) {
177#endif
178 fn = filename;
179 } else {
180 fn = getcwd(cwd, sizeof(cwd));
181 len = fn.length();
182 if (fn[len-1] != OS_PATH_SEPARATOR) {
183 fn += OS_PATH_SEPARATOR;
184 }
185 fn += filename;
186 }
187
188 if (package) {
189 expected = package;
190 expected += '.';
191 }
192
193 len = expected.length();
194 for (size_t i=0; i<len; i++) {
195 if (expected[i] == '.') {
196 expected[i] = OS_PATH_SEPARATOR;
197 }
198 }
199
200 p = strchr(name->data, '.');
201 len = p ? p-name->data : strlen(name->data);
202 expected.append(name->data, len);
203
204 expected += ".aidl";
205
206 len = fn.length();
207 valid = (len >= expected.length());
208
209 if (valid) {
210 p = fn.c_str() + (len - expected.length());
211
212#ifdef HAVE_WINDOWS_PATHS
213 if (OS_PATH_SEPARATOR != '/') {
214 // Input filename under cygwin most likely has / separators
215 // whereas the expected string uses \\ separators. Adjust
216 // them accordingly.
217 for (char *c = const_cast<char *>(p); *c; ++c) {
218 if (*c == '/') *c = OS_PATH_SEPARATOR;
219 }
220 }
221#endif
222
223#ifdef OS_CASE_SENSITIVE
224 valid = (expected == p);
225#else
226 valid = !strcasecmp(expected.c_str(), p);
227#endif
228 }
229
230 if (!valid) {
231 fprintf(stderr, "%s:%d interface %s should be declared in a file"
232 " called %s.\n",
233 filename, name->lineno, name->data, expected.c_str());
234 return 1;
235 }
236
237 return 0;
238}
239
240static int
241check_filenames(const char* filename, document_item_type* items)
242{
243 int err = 0;
244 while (items) {
Joe Onorato7db766c2011-09-15 21:31:15 -0700245 if (items->item_type == PARCELABLE_TYPE
246 || items->item_type == FLATTENABLE_TYPE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 parcelable_type* p = (parcelable_type*)items;
248 err |= check_filename(filename, p->package, &p->name);
249 }
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700250 else if (items->item_type == INTERFACE_TYPE_BINDER
251 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 interface_type* c = (interface_type*)items;
253 err |= check_filename(filename, c->package, &c->name);
254 }
255 else {
256 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
257 items->item_type);
258 return 1;
259 }
260 items = items->next;
261 }
262 return err;
263}
264
265// ==========================================================
266static const char*
267kind_to_string(int kind)
268{
269 switch (kind)
270 {
271 case Type::INTERFACE:
272 return "an interface";
273 case Type::PARCELABLE:
274 return "a parcelable";
275 default:
276 return "ERROR";
277 }
278}
279
280static char*
281rfind(char* str, char c)
282{
283 char* p = str + strlen(str) - 1;
284 while (p >= str) {
285 if (*p == c) {
286 return p;
287 }
288 p--;
289 }
290 return NULL;
291}
292
293static int
294gather_types(const char* filename, document_item_type* items)
295{
296 int err = 0;
297 while (items) {
298 Type* type;
299 if (items->item_type == PARCELABLE_TYPE) {
300 parcelable_type* p = (parcelable_type*)items;
301 type = new ParcelableType(p->package ? p->package : "",
302 p->name.data, false, filename, p->name.lineno);
303 }
Joe Onorato7db766c2011-09-15 21:31:15 -0700304 else if (items->item_type == FLATTENABLE_TYPE) {
305 parcelable_type* p = (parcelable_type*)items;
306 type = new FlattenableType(p->package ? p->package : "",
307 p->name.data, false, filename, p->name.lineno);
308 }
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700309 else if (items->item_type == INTERFACE_TYPE_BINDER
310 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 interface_type* c = (interface_type*)items;
312 type = new InterfaceType(c->package ? c->package : "",
313 c->name.data, false, c->oneway,
314 filename, c->name.lineno);
315 }
316 else {
317 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
318 return 1;
319 }
320
321 Type* old = NAMES.Find(type->QualifiedName());
322 if (old == NULL) {
323 NAMES.Add(type);
324
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700325 if (items->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 // for interfaces, also add the stub and proxy types, we don't
327 // bother checking these for duplicates, because the parser
328 // won't let us do it.
329 interface_type* c = (interface_type*)items;
330
331 string name = c->name.data;
332 name += ".Stub";
333 Type* stub = new Type(c->package ? c->package : "",
Joe Onorato7db766c2011-09-15 21:31:15 -0700334 name, Type::GENERATED, false, false, false,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 filename, c->name.lineno);
336 NAMES.Add(stub);
337
338 name = c->name.data;
339 name += ".Stub.Proxy";
340 Type* proxy = new Type(c->package ? c->package : "",
Joe Onorato7db766c2011-09-15 21:31:15 -0700341 name, Type::GENERATED, false, false, false,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 filename, c->name.lineno);
343 NAMES.Add(proxy);
344 }
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700345 else if (items->item_type == INTERFACE_TYPE_RPC) {
346 // for interfaces, also add the service base type, we don't
347 // bother checking these for duplicates, because the parser
348 // won't let us do it.
349 interface_type* c = (interface_type*)items;
350
351 string name = c->name.data;
352 name += ".ServiceBase";
353 Type* base = new Type(c->package ? c->package : "",
Joe Onorato7db766c2011-09-15 21:31:15 -0700354 name, Type::GENERATED, false, false, false,
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700355 filename, c->name.lineno);
356 NAMES.Add(base);
357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 } else {
359 if (old->Kind() == Type::BUILT_IN) {
360 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
361 filename, type->DeclLine(),
362 type->QualifiedName().c_str());
363 err = 1;
364 }
365 else if (type->Kind() != old->Kind()) {
366 const char* oldKind = kind_to_string(old->Kind());
367 const char* newKind = kind_to_string(type->Kind());
368
369 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
370 filename, type->DeclLine(),
371 type->QualifiedName().c_str(), newKind);
372 fprintf(stderr, "%s:%d previously defined here as %s.\n",
373 old->DeclFile().c_str(), old->DeclLine(), oldKind);
374 err = 1;
375 }
376 }
377
378 items = items->next;
379 }
380 return err;
381}
382
383// ==========================================================
384static bool
385matches_keyword(const char* str)
386{
387 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
388 "byte", "case", "catch", "char", "class", "const", "continue",
389 "default", "do", "double", "else", "enum", "extends", "final",
390 "finally", "float", "for", "goto", "if", "implements", "import",
391 "instanceof", "int", "interface", "long", "native", "new", "package",
392 "private", "protected", "public", "return", "short", "static",
393 "strictfp", "super", "switch", "synchronized", "this", "throw",
394 "throws", "transient", "try", "void", "volatile", "while",
395 "true", "false", "null",
396 NULL
397 };
398 const char** k = KEYWORDS;
399 while (*k) {
400 if (0 == strcmp(str, *k)) {
401 return true;
402 }
403 k++;
404 }
405 return false;
406}
407
408static int
Joe Onorato7db766c2011-09-15 21:31:15 -0700409check_method(const char* filename, int kind, method_type* m)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410{
411 int err = 0;
412
413 // return type
414 Type* returnType = NAMES.Search(m->type.type.data);
415 if (returnType == NULL) {
416 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
417 m->type.type.lineno, m->type.type.data);
418 err = 1;
419 return err;
420 }
421
Joe Onorato7db766c2011-09-15 21:31:15 -0700422 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
423 : returnType->CanWriteToRpcData())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
425 m->type.type.lineno, m->type.type.data);
426 err = 1;
427 }
428
429 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
430 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
431 m->type.array_token.lineno, m->type.type.data,
432 m->type.array_token.data);
433 err = 1;
434 }
435
436 if (m->type.dimension > 1) {
437 fprintf(stderr, "%s:%d return type %s%s only one"
438 " dimensional arrays are supported\n", filename,
439 m->type.array_token.lineno, m->type.type.data,
440 m->type.array_token.data);
441 err = 1;
442 }
443
444 int index = 1;
445
446 arg_type* arg = m->args;
447 while (arg) {
448 Type* t = NAMES.Search(arg->type.type.data);
449
450 // check the arg type
451 if (t == NULL) {
452 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
453 filename, m->type.type.lineno, arg->name.data, index,
454 arg->type.type.data);
455 err = 1;
456 goto next;
457 }
458
Joe Onorato7db766c2011-09-15 21:31:15 -0700459 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
461 filename, m->type.type.lineno, index,
462 arg->type.type.data, arg->name.data);
463 err = 1;
464 }
465
466 if (arg->direction.data == NULL
467 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
468 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
469 " parameter, so you must declare it as in,"
470 " out or inout.\n",
471 filename, m->type.type.lineno, index,
472 arg->type.type.data, arg->name.data);
473 err = 1;
474 }
475
476 if (convert_direction(arg->direction.data) != IN_PARAMETER
477 && !t->CanBeOutParameter()
478 && arg->type.dimension == 0) {
479 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
480 " parameter.\n",
481 filename, m->type.type.lineno, index,
482 arg->direction.data, arg->type.type.data,
483 arg->name.data);
484 err = 1;
485 }
486
487 if (arg->type.dimension > 0 && !t->CanBeArray()) {
488 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
489 " array.\n", filename,
490 m->type.array_token.lineno, index, arg->direction.data,
491 arg->type.type.data, arg->type.array_token.data,
492 arg->name.data);
493 err = 1;
494 }
495
496 if (arg->type.dimension > 1) {
497 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
498 " dimensional arrays are supported\n", filename,
499 m->type.array_token.lineno, index, arg->direction.data,
500 arg->type.type.data, arg->type.array_token.data,
501 arg->name.data);
502 err = 1;
503 }
504
505 // check that the name doesn't match a keyword
506 if (matches_keyword(arg->name.data)) {
507 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
508 " Java keyword\n",
509 filename, m->name.lineno, index, arg->name.data);
510 err = 1;
511 }
512
513next:
514 index++;
515 arg = arg->next;
516 }
517
518 return err;
519}
520
521static int
522check_types(const char* filename, document_item_type* items)
523{
524 int err = 0;
525 while (items) {
Joe Onorato7db766c2011-09-15 21:31:15 -0700526 // (nothing to check for PARCELABLE_TYPE or FLATTENABLE_TYPE)
527 if (items->item_type == INTERFACE_TYPE_BINDER
528 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 map<string,method_type*> methodNames;
530 interface_type* c = (interface_type*)items;
531
532 interface_item_type* member = c->interface_items;
533 while (member) {
534 if (member->item_type == METHOD_TYPE) {
535 method_type* m = (method_type*)member;
536
Joe Onorato7db766c2011-09-15 21:31:15 -0700537 err |= check_method(filename, items->item_type, m);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538
539 // prevent duplicate methods
540 if (methodNames.find(m->name.data) == methodNames.end()) {
541 methodNames[m->name.data] = m;
542 } else {
543 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
544 filename, m->name.lineno, m->name.data);
545 method_type* old = methodNames[m->name.data];
546 fprintf(stderr, "%s:%d previously defined here.\n",
547 filename, old->name.lineno);
548 err = 1;
549 }
550 }
551 member = member->next;
552 }
553 }
554
555 items = items->next;
556 }
557 return err;
558}
559
560// ==========================================================
561static int
562exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
563 bool* onlyParcelable)
564{
565 if (items == NULL) {
566 fprintf(stderr, "%s: file does not contain any interfaces\n",
567 filename);
568 return 1;
569 }
570
571 const document_item_type* next = items->next;
572 if (items->next != NULL) {
573 int lineno = -1;
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700574 if (next->item_type == INTERFACE_TYPE_BINDER) {
575 lineno = ((interface_type*)next)->interface_token.lineno;
576 }
577 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 lineno = ((interface_type*)next)->interface_token.lineno;
579 }
580 else if (next->item_type == PARCELABLE_TYPE) {
581 lineno = ((parcelable_type*)next)->parcelable_token.lineno;
582 }
Joe Onorato7db766c2011-09-15 21:31:15 -0700583 else if (next->item_type == FLATTENABLE_TYPE) {
584 lineno = ((parcelable_type*)next)->parcelable_token.lineno;
585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
587 filename, lineno);
588 return 1;
589 }
590
Joe Onorato7db766c2011-09-15 21:31:15 -0700591 if (items->item_type == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 *onlyParcelable = true;
593 if (options.failOnParcelable) {
594 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Joe Onorato7db766c2011-09-15 21:31:15 -0700595 " parcelables or flattenables,\n", filename,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 ((parcelable_type*)items)->parcelable_token.lineno);
Joe Onorato7db766c2011-09-15 21:31:15 -0700597 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
598 "may not go in the Makefile.\n", filename,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 ((parcelable_type*)items)->parcelable_token.lineno);
600 return 1;
601 }
602 } else {
603 *onlyParcelable = false;
604 }
605
606 return 0;
607}
608
609// ==========================================================
610void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700611generate_dep_file(const Options& options, const document_item_type* items)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612{
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700613 /* we open the file in binary mode to ensure that the same output is
614 * generated on all platforms !!
615 */
616 FILE* to = NULL;
617 if (options.autoDepFile) {
618 string fileName = options.outputFileName + ".d";
619 to = fopen(fileName.c_str(), "wb");
620 } else {
621 to = fopen(options.depFileName.c_str(), "wb");
622 }
623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 if (to == NULL) {
625 return;
626 }
627
628 const char* slash = "\\";
629 import_info* import = g_imports;
630 if (import == NULL) {
631 slash = "";
632 }
633
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700634 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700635 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
636 } else {
637 // parcelable: there's no output file.
638 fprintf(to, " : \\\n");
639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
641
642 while (import) {
643 if (import->next == NULL) {
644 slash = "";
645 }
646 if (import->filename) {
647 fprintf(to, " %s %s\n", import->filename, slash);
648 }
649 import = import->next;
650 }
651
652 fprintf(to, "\n");
653
654 fclose(to);
655}
656
657// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700658static string
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700659generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700660{
661 string result;
662
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700663 // create the path to the destination folder based on the
664 // interface package name
665 result = options.outputBaseFolder;
666 result += OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700667
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700668 string packageStr = package;
669 size_t len = packageStr.length();
670 for (size_t i=0; i<len; i++) {
671 if (packageStr[i] == '.') {
672 packageStr[i] = OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700673 }
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700674 }
675
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700676 result += packageStr;
677
678 // add the filename by replacing the .aidl extension to .java
679 const char* p = strchr(name.data, '.');
680 len = p ? p-name.data : strlen(name.data);
681
682 result += OS_PATH_SEPARATOR;
683 result.append(name.data, len);
684 result += ".java";
685
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700686 return result;
687}
688
689// ==========================================================
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700690static string
691generate_outputFileName(const Options& options, const document_item_type* items)
692{
693 // items has already been checked to have only one interface.
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700694 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700695 interface_type* type = (interface_type*)items;
696
697 return generate_outputFileName2(options, type->name, type->package);
Joe Onorato7db766c2011-09-15 21:31:15 -0700698 } else if (items->item_type == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700699 parcelable_type* type = (parcelable_type*)items;
700 return generate_outputFileName2(options, type->name, type->package);
701 }
702
703 // I don't think we can come here, but safer than returning NULL.
704 string result;
705 return result;
706}
707
708
709
710// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700711static void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700712check_outputFilePath(const string& path) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700713 size_t len = path.length();
714 for (size_t i=0; i<len ; i++) {
715 if (path[i] == OS_PATH_SEPARATOR) {
716 string p = path.substr(0, i);
717 if (access(path.data(), F_OK) != 0) {
718#ifdef HAVE_MS_C_RUNTIME
719 _mkdir(p.data());
720#else
721 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
722#endif
723 }
724 }
725 }
726}
727
728
729// ==========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730static int
731parse_preprocessed_file(const string& filename)
732{
733 int err;
734
735 FILE* f = fopen(filename.c_str(), "rb");
736 if (f == NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800737 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 filename.c_str());
739 return 1;
740 }
741
742 int lineno = 1;
743 char line[1024];
744 char type[1024];
745 char fullname[1024];
746 while (fgets(line, sizeof(line), f)) {
747 // skip comments and empty lines
748 if (!line[0] || strncmp(line, "//", 2) == 0) {
749 continue;
750 }
751
752 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
753
754 char* packagename;
755 char* classname = rfind(fullname, '.');
756 if (classname != NULL) {
757 *classname = '\0';
758 classname++;
759 packagename = fullname;
760 } else {
761 classname = fullname;
762 packagename = NULL;
763 }
764
765 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
766 // type, packagename, classname);
767 document_item_type* doc;
768
769 if (0 == strcmp("parcelable", type)) {
770 parcelable_type* parcl = (parcelable_type*)malloc(
771 sizeof(parcelable_type));
772 memset(parcl, 0, sizeof(parcelable_type));
773 parcl->document_item.item_type = PARCELABLE_TYPE;
774 parcl->parcelable_token.lineno = lineno;
775 parcl->parcelable_token.data = strdup(type);
776 parcl->package = packagename ? strdup(packagename) : NULL;
777 parcl->name.lineno = lineno;
778 parcl->name.data = strdup(classname);
779 parcl->semicolon_token.lineno = lineno;
780 parcl->semicolon_token.data = strdup(";");
781 doc = (document_item_type*)parcl;
782 }
Joe Onorato7db766c2011-09-15 21:31:15 -0700783 else if (0 == strcmp("flattenable", type)) {
784 parcelable_type* parcl = (parcelable_type*)malloc(
785 sizeof(parcelable_type));
786 memset(parcl, 0, sizeof(parcelable_type));
787 parcl->document_item.item_type = FLATTENABLE_TYPE;
788 parcl->parcelable_token.lineno = lineno;
789 parcl->parcelable_token.data = strdup(type);
790 parcl->package = packagename ? strdup(packagename) : NULL;
791 parcl->name.lineno = lineno;
792 parcl->name.data = strdup(classname);
793 parcl->semicolon_token.lineno = lineno;
794 parcl->semicolon_token.data = strdup(";");
795 doc = (document_item_type*)parcl;
796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 else if (0 == strcmp("interface", type)) {
798 interface_type* iface = (interface_type*)malloc(
799 sizeof(interface_type));
800 memset(iface, 0, sizeof(interface_type));
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700801 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 iface->interface_token.lineno = lineno;
803 iface->interface_token.data = strdup(type);
804 iface->package = packagename ? strdup(packagename) : NULL;
805 iface->name.lineno = lineno;
806 iface->name.data = strdup(classname);
807 iface->open_brace_token.lineno = lineno;
808 iface->open_brace_token.data = strdup("{");
809 iface->close_brace_token.lineno = lineno;
810 iface->close_brace_token.data = strdup("}");
811 doc = (document_item_type*)iface;
812 }
813 else {
814 fprintf(stderr, "%s:%d: bad type in line: %s\n",
815 filename.c_str(), lineno, line);
816 return 1;
817 }
818 err = gather_types(filename.c_str(), doc);
819 lineno++;
820 }
821
822 if (!feof(f)) {
823 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
824 filename.c_str(), lineno);
825 return 1;
826 }
827
828 fclose(f);
829 return 0;
830}
831
832// ==========================================================
833static int
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700834compile_aidl(Options& options)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835{
836 int err = 0, N;
837
838 set_import_paths(options.importPaths);
839
840 register_base_types();
841
842 // import the preprocessed file
843 N = options.preprocessedFiles.size();
844 for (int i=0; i<N; i++) {
845 const string& s = options.preprocessedFiles[i];
846 err |= parse_preprocessed_file(s);
847 }
848 if (err != 0) {
849 return err;
850 }
851
852 // parse the main file
853 g_callbacks = &g_mainCallbacks;
854 err = parse_aidl(options.inputFileName.c_str());
855 document_item_type* mainDoc = g_document;
856 g_document = NULL;
857
858 // parse the imports
859 g_callbacks = &g_mainCallbacks;
860 import_info* import = g_imports;
861 while (import) {
862 if (NAMES.Find(import->neededClass) == NULL) {
863 import->filename = find_import_file(import->neededClass);
864 if (!import->filename) {
865 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
866 import->from, import->statement.lineno,
867 import->neededClass);
868 err |= 1;
869 } else {
870 err |= parse_aidl(import->filename);
871 import->doc = g_document;
872 if (import->doc == NULL) {
873 err |= 1;
874 }
875 }
876 }
877 import = import->next;
878 }
879 // bail out now if parsing wasn't successful
880 if (err != 0 || mainDoc == NULL) {
881 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
882 return 1;
883 }
884
885 // complain about ones that aren't in the right files
886 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
887 import = g_imports;
888 while (import) {
889 err |= check_filenames(import->filename, import->doc);
890 import = import->next;
891 }
892
893 // gather the types that have been declared
894 err |= gather_types(options.inputFileName.c_str(), mainDoc);
895 import = g_imports;
896 while (import) {
897 err |= gather_types(import->filename, import->doc);
898 import = import->next;
899 }
900
901#if 0
902 printf("---- main doc ----\n");
903 test_document(mainDoc);
904
905 import = g_imports;
906 while (import) {
907 printf("---- import doc ----\n");
908 test_document(import->doc);
909 import = import->next;
910 }
911 NAMES.Dump();
912#endif
913
914 // check the referenced types in mainDoc to make sure we've imported them
915 err |= check_types(options.inputFileName.c_str(), mainDoc);
916
917 // finally, there really only needs to be one thing in mainDoc, and it
918 // needs to be an interface.
919 bool onlyParcelable = false;
920 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
921
922 // after this, there shouldn't be any more errors because of the
923 // input.
924 if (err != 0 || mainDoc == NULL) {
925 return 1;
926 }
927
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700928 // if needed, generate the outputFileName from the outputBaseFolder
929 if (options.outputFileName.length() == 0 &&
930 options.outputBaseFolder.length() > 0) {
931 options.outputFileName = generate_outputFileName(options, mainDoc);
932 }
933
934 // if we were asked to, generate a make dependency file
935 // unless it's a parcelable *and* it's supposed to fail on parcelable
936 if ((options.autoDepFile || options.depFileName != "") &&
937 !(onlyParcelable && options.failOnParcelable)) {
938 // make sure the folders of the output file all exists
939 check_outputFilePath(options.outputFileName);
940 generate_dep_file(options, mainDoc);
941 }
942
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 // they didn't ask to fail on parcelables, so just exit quietly.
944 if (onlyParcelable && !options.failOnParcelable) {
945 return 0;
946 }
947
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700948 // make sure the folders of the output file all exists
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700949 check_outputFilePath(options.outputFileName);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700950
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700951 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 (interface_type*)mainDoc);
953
954 return err;
955}
956
957static int
958preprocess_aidl(const Options& options)
959{
960 vector<string> lines;
961 int err;
962
963 // read files
964 int N = options.filesToPreprocess.size();
965 for (int i=0; i<N; i++) {
966 g_callbacks = &g_mainCallbacks;
967 err = parse_aidl(options.filesToPreprocess[i].c_str());
968 if (err != 0) {
969 return err;
970 }
971 document_item_type* doc = g_document;
972 string line;
973 if (doc->item_type == PARCELABLE_TYPE) {
974 line = "parcelable ";
975 parcelable_type* parcelable = (parcelable_type*)doc;
976 if (parcelable->package) {
977 line += parcelable->package;
978 line += '.';
979 }
980 line += parcelable->name.data;
Joe Onorato7db766c2011-09-15 21:31:15 -0700981 }
982 else if (doc->item_type == FLATTENABLE_TYPE) {
983 line = "parcelable ";
984 parcelable_type* parcelable = (parcelable_type*)doc;
985 if (parcelable->package) {
986 line += parcelable->package;
987 line += '.';
988 }
989 line += parcelable->name.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 } else {
991 line = "interface ";
992 interface_type* iface = (interface_type*)doc;
993 if (iface->package) {
994 line += iface->package;
995 line += '.';
996 }
997 line += iface->name.data;
998 }
999 line += ";\n";
1000 lines.push_back(line);
1001 }
1002
1003 // write preprocessed file
1004 int fd = open( options.outputFileName.c_str(),
1005 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1006#ifdef HAVE_MS_C_RUNTIME
1007 _S_IREAD|_S_IWRITE);
1008#else
1009 S_IRUSR|S_IWUSR|S_IRGRP);
1010#endif
1011 if (fd == -1) {
1012 fprintf(stderr, "aidl: could not open file for write: %s\n",
1013 options.outputFileName.c_str());
1014 return 1;
1015 }
1016
1017 N = lines.size();
1018 for (int i=0; i<N; i++) {
1019 const string& s = lines[i];
1020 int len = s.length();
1021 if (len != write(fd, s.c_str(), len)) {
1022 fprintf(stderr, "aidl: error writing to file %s\n",
1023 options.outputFileName.c_str());
1024 close(fd);
1025 unlink(options.outputFileName.c_str());
1026 return 1;
1027 }
1028 }
1029
1030 close(fd);
1031 return 0;
1032}
1033
1034// ==========================================================
1035int
1036main(int argc, const char **argv)
1037{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 Options options;
1039 int result = parse_options(argc, argv, &options);
1040 if (result) {
1041 return result;
1042 }
1043
1044 switch (options.task)
1045 {
1046 case COMPILE_AIDL:
1047 return compile_aidl(options);
1048 case PREPROCESS_AIDL:
1049 return preprocess_aidl(options);
1050 }
1051 fprintf(stderr, "aidl: internal error\n");
1052 return 1;
1053}