blob: cd23b65cf791a3941f32f0ee6cc96ac482cafaa1 [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 Onoratoae7f32e2011-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 }
Joe Onorato94ca1b92011-10-09 22:31:16 -070053 else if (d->item_type == USER_DATA_TYPE) {
54 user_data_type* b = (user_data_type*)d;
55 if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
56 printf("parcelable %s %s;\n", b->package, b->name.data);
57 }
58 if ((b->flattening_methods & RPC_DATA) != 0) {
59 printf("flattenable %s %s;\n", b->package, b->name.data);
60 }
Joe Onoratoacff0822011-09-15 21:31:15 -070061 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 else {
Scott Turner066aa992010-01-14 21:05:17 -050063 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 -080064 }
65 d = d->next;
66 }
67}
68
69// ==========================================================
70int
71convert_direction(const char* direction)
72{
73 if (direction == NULL) {
74 return IN_PARAMETER;
75 }
76 if (0 == strcmp(direction, "in")) {
77 return IN_PARAMETER;
78 }
79 if (0 == strcmp(direction, "out")) {
80 return OUT_PARAMETER;
81 }
82 return INOUT_PARAMETER;
83}
84
85// ==========================================================
86struct import_info {
87 const char* from;
88 const char* filename;
89 buffer_type statement;
90 const char* neededClass;
91 document_item_type* doc;
92 struct import_info* next;
93};
94
95document_item_type* g_document = NULL;
96import_info* g_imports = NULL;
97
98static void
99main_document_parsed(document_item_type* d)
100{
101 g_document = d;
102}
103
104static void
105main_import_parsed(buffer_type* statement)
106{
107 import_info* import = (import_info*)malloc(sizeof(import_info));
108 memset(import, 0, sizeof(import_info));
109 import->from = strdup(g_currentFilename);
110 import->statement.lineno = statement->lineno;
111 import->statement.data = strdup(statement->data);
112 import->statement.extra = NULL;
113 import->next = g_imports;
114 import->neededClass = parse_import_statement(statement->data);
115 g_imports = import;
116}
117
118static ParserCallbacks g_mainCallbacks = {
119 &main_document_parsed,
120 &main_import_parsed
121};
122
123char*
124parse_import_statement(const char* text)
125{
126 const char* end;
127 int len;
128
129 while (isspace(*text)) {
130 text++;
131 }
132 while (!isspace(*text)) {
133 text++;
134 }
135 while (isspace(*text)) {
136 text++;
137 }
138 end = text;
139 while (!isspace(*end) && *end != ';') {
140 end++;
141 }
142 len = end-text;
143
144 char* rv = (char*)malloc(len+1);
145 memcpy(rv, text, len);
146 rv[len] = '\0';
147
148 return rv;
149}
150
151// ==========================================================
152static void
153import_import_parsed(buffer_type* statement)
154{
155}
156
157static ParserCallbacks g_importCallbacks = {
158 &main_document_parsed,
159 &import_import_parsed
160};
161
162// ==========================================================
163static int
164check_filename(const char* filename, const char* package, buffer_type* name)
165{
166 const char* p;
167 string expected;
168 string fn;
169 size_t len;
170 char cwd[MAXPATHLEN];
171 bool valid = false;
172
173#ifdef HAVE_WINDOWS_PATHS
174 if (isalpha(filename[0]) && filename[1] == ':'
175 && filename[2] == OS_PATH_SEPARATOR) {
176#else
177 if (filename[0] == OS_PATH_SEPARATOR) {
178#endif
179 fn = filename;
180 } else {
181 fn = getcwd(cwd, sizeof(cwd));
182 len = fn.length();
183 if (fn[len-1] != OS_PATH_SEPARATOR) {
184 fn += OS_PATH_SEPARATOR;
185 }
186 fn += filename;
187 }
188
189 if (package) {
190 expected = package;
191 expected += '.';
192 }
193
194 len = expected.length();
195 for (size_t i=0; i<len; i++) {
196 if (expected[i] == '.') {
197 expected[i] = OS_PATH_SEPARATOR;
198 }
199 }
200
201 p = strchr(name->data, '.');
202 len = p ? p-name->data : strlen(name->data);
203 expected.append(name->data, len);
204
205 expected += ".aidl";
206
207 len = fn.length();
208 valid = (len >= expected.length());
209
210 if (valid) {
211 p = fn.c_str() + (len - expected.length());
212
213#ifdef HAVE_WINDOWS_PATHS
214 if (OS_PATH_SEPARATOR != '/') {
215 // Input filename under cygwin most likely has / separators
216 // whereas the expected string uses \\ separators. Adjust
217 // them accordingly.
218 for (char *c = const_cast<char *>(p); *c; ++c) {
219 if (*c == '/') *c = OS_PATH_SEPARATOR;
220 }
221 }
222#endif
223
224#ifdef OS_CASE_SENSITIVE
225 valid = (expected == p);
226#else
227 valid = !strcasecmp(expected.c_str(), p);
228#endif
229 }
230
231 if (!valid) {
232 fprintf(stderr, "%s:%d interface %s should be declared in a file"
233 " called %s.\n",
234 filename, name->lineno, name->data, expected.c_str());
235 return 1;
236 }
237
238 return 0;
239}
240
241static int
242check_filenames(const char* filename, document_item_type* items)
243{
244 int err = 0;
245 while (items) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700246 if (items->item_type == USER_DATA_TYPE) {
247 user_data_type* p = (user_data_type*)items;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 err |= check_filename(filename, p->package, &p->name);
249 }
Joe Onoratoae7f32e2011-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";
Joe Onorato94ca1b92011-10-09 22:31:16 -0700273 case Type::USERDATA:
274 return "a user data";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 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;
Joe Onorato94ca1b92011-10-09 22:31:16 -0700299 if (items->item_type == USER_DATA_TYPE) {
300 user_data_type* p = (user_data_type*)items;
301 type = new UserDataType(p->package ? p->package : "", p->name.data,
302 false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
303 ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
Joe Onoratoacff0822011-09-15 21:31:15 -0700304 }
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700305 else if (items->item_type == INTERFACE_TYPE_BINDER
306 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 interface_type* c = (interface_type*)items;
308 type = new InterfaceType(c->package ? c->package : "",
309 c->name.data, false, c->oneway,
310 filename, c->name.lineno);
311 }
312 else {
313 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
314 return 1;
315 }
316
317 Type* old = NAMES.Find(type->QualifiedName());
318 if (old == NULL) {
319 NAMES.Add(type);
320
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700321 if (items->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 // for interfaces, also add the stub and proxy types, we don't
323 // bother checking these for duplicates, because the parser
324 // won't let us do it.
325 interface_type* c = (interface_type*)items;
326
327 string name = c->name.data;
328 name += ".Stub";
329 Type* stub = new Type(c->package ? c->package : "",
Joe Onoratoacff0822011-09-15 21:31:15 -0700330 name, Type::GENERATED, false, false, false,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 filename, c->name.lineno);
332 NAMES.Add(stub);
333
334 name = c->name.data;
335 name += ".Stub.Proxy";
336 Type* proxy = new Type(c->package ? c->package : "",
Joe Onoratoacff0822011-09-15 21:31:15 -0700337 name, Type::GENERATED, false, false, false,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 filename, c->name.lineno);
339 NAMES.Add(proxy);
340 }
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700341 else if (items->item_type == INTERFACE_TYPE_RPC) {
342 // for interfaces, also add the service base type, we don't
343 // bother checking these for duplicates, because the parser
344 // won't let us do it.
345 interface_type* c = (interface_type*)items;
346
347 string name = c->name.data;
348 name += ".ServiceBase";
349 Type* base = new Type(c->package ? c->package : "",
Joe Onoratoacff0822011-09-15 21:31:15 -0700350 name, Type::GENERATED, false, false, false,
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700351 filename, c->name.lineno);
352 NAMES.Add(base);
353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 } else {
355 if (old->Kind() == Type::BUILT_IN) {
356 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
357 filename, type->DeclLine(),
358 type->QualifiedName().c_str());
359 err = 1;
360 }
361 else if (type->Kind() != old->Kind()) {
362 const char* oldKind = kind_to_string(old->Kind());
363 const char* newKind = kind_to_string(type->Kind());
364
365 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
366 filename, type->DeclLine(),
367 type->QualifiedName().c_str(), newKind);
368 fprintf(stderr, "%s:%d previously defined here as %s.\n",
369 old->DeclFile().c_str(), old->DeclLine(), oldKind);
370 err = 1;
371 }
372 }
373
374 items = items->next;
375 }
376 return err;
377}
378
379// ==========================================================
380static bool
381matches_keyword(const char* str)
382{
383 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
384 "byte", "case", "catch", "char", "class", "const", "continue",
385 "default", "do", "double", "else", "enum", "extends", "final",
386 "finally", "float", "for", "goto", "if", "implements", "import",
387 "instanceof", "int", "interface", "long", "native", "new", "package",
388 "private", "protected", "public", "return", "short", "static",
389 "strictfp", "super", "switch", "synchronized", "this", "throw",
390 "throws", "transient", "try", "void", "volatile", "while",
391 "true", "false", "null",
392 NULL
393 };
394 const char** k = KEYWORDS;
395 while (*k) {
396 if (0 == strcmp(str, *k)) {
397 return true;
398 }
399 k++;
400 }
401 return false;
402}
403
404static int
Joe Onoratoacff0822011-09-15 21:31:15 -0700405check_method(const char* filename, int kind, method_type* m)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406{
407 int err = 0;
408
409 // return type
410 Type* returnType = NAMES.Search(m->type.type.data);
411 if (returnType == NULL) {
412 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
413 m->type.type.lineno, m->type.type.data);
414 err = 1;
415 return err;
416 }
417
Joe Onorato827af242011-09-23 15:17:52 -0700418 if (returnType == EVENT_FAKE_TYPE) {
419 if (kind != INTERFACE_TYPE_RPC) {
420 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
421 filename, m->type.type.lineno);
422 err = 1;
423 }
424 } else {
425 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
426 : returnType->CanWriteToRpcData())) {
Joe Onorato0ee24312011-11-03 14:44:13 -0700427 fprintf(stderr, "%s:%d return type %s can't be marshalled. kind=%d p=%d m=%d\n", filename,
428 m->type.type.lineno, m->type.type.data, kind,
429 returnType->CanWriteToParcel(), returnType->CanWriteToRpcData());
Joe Onorato827af242011-09-23 15:17:52 -0700430 err = 1;
431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 }
433
434 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
435 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
436 m->type.array_token.lineno, m->type.type.data,
437 m->type.array_token.data);
438 err = 1;
439 }
440
441 if (m->type.dimension > 1) {
442 fprintf(stderr, "%s:%d return type %s%s only one"
443 " dimensional arrays are supported\n", filename,
444 m->type.array_token.lineno, m->type.type.data,
445 m->type.array_token.data);
446 err = 1;
447 }
448
449 int index = 1;
450
451 arg_type* arg = m->args;
452 while (arg) {
453 Type* t = NAMES.Search(arg->type.type.data);
454
455 // check the arg type
456 if (t == NULL) {
457 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
458 filename, m->type.type.lineno, arg->name.data, index,
459 arg->type.type.data);
460 err = 1;
461 goto next;
462 }
Joe Onorato827af242011-09-23 15:17:52 -0700463
464 if (t == EVENT_FAKE_TYPE) {
465 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
466 filename, m->type.type.lineno, arg->name.data, index,
467 arg->type.type.data);
468 err = 1;
469 goto next;
470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471
Joe Onoratoacff0822011-09-15 21:31:15 -0700472 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
474 filename, m->type.type.lineno, index,
475 arg->type.type.data, arg->name.data);
476 err = 1;
477 }
478
479 if (arg->direction.data == NULL
480 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
481 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
482 " parameter, so you must declare it as in,"
483 " out or inout.\n",
484 filename, m->type.type.lineno, index,
485 arg->type.type.data, arg->name.data);
486 err = 1;
487 }
488
489 if (convert_direction(arg->direction.data) != IN_PARAMETER
490 && !t->CanBeOutParameter()
491 && arg->type.dimension == 0) {
492 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
493 " parameter.\n",
494 filename, m->type.type.lineno, index,
495 arg->direction.data, arg->type.type.data,
496 arg->name.data);
497 err = 1;
498 }
499
500 if (arg->type.dimension > 0 && !t->CanBeArray()) {
501 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
502 " array.\n", filename,
503 m->type.array_token.lineno, index, arg->direction.data,
504 arg->type.type.data, arg->type.array_token.data,
505 arg->name.data);
506 err = 1;
507 }
508
509 if (arg->type.dimension > 1) {
510 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
511 " dimensional arrays are supported\n", filename,
512 m->type.array_token.lineno, index, arg->direction.data,
513 arg->type.type.data, arg->type.array_token.data,
514 arg->name.data);
515 err = 1;
516 }
517
518 // check that the name doesn't match a keyword
519 if (matches_keyword(arg->name.data)) {
520 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
Joe Onorato827af242011-09-23 15:17:52 -0700521 " Java or aidl keyword\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 filename, m->name.lineno, index, arg->name.data);
523 err = 1;
524 }
525
526next:
527 index++;
528 arg = arg->next;
529 }
530
531 return err;
532}
533
534static int
535check_types(const char* filename, document_item_type* items)
536{
537 int err = 0;
538 while (items) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700539 // (nothing to check for USER_DATA_TYPE)
Joe Onoratoacff0822011-09-15 21:31:15 -0700540 if (items->item_type == INTERFACE_TYPE_BINDER
541 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 map<string,method_type*> methodNames;
543 interface_type* c = (interface_type*)items;
544
545 interface_item_type* member = c->interface_items;
546 while (member) {
547 if (member->item_type == METHOD_TYPE) {
548 method_type* m = (method_type*)member;
549
Joe Onoratoacff0822011-09-15 21:31:15 -0700550 err |= check_method(filename, items->item_type, m);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551
552 // prevent duplicate methods
553 if (methodNames.find(m->name.data) == methodNames.end()) {
554 methodNames[m->name.data] = m;
555 } else {
556 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
557 filename, m->name.lineno, m->name.data);
558 method_type* old = methodNames[m->name.data];
559 fprintf(stderr, "%s:%d previously defined here.\n",
560 filename, old->name.lineno);
561 err = 1;
562 }
563 }
564 member = member->next;
565 }
566 }
567
568 items = items->next;
569 }
570 return err;
571}
572
573// ==========================================================
574static int
575exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
576 bool* onlyParcelable)
577{
578 if (items == NULL) {
579 fprintf(stderr, "%s: file does not contain any interfaces\n",
580 filename);
581 return 1;
582 }
583
584 const document_item_type* next = items->next;
585 if (items->next != NULL) {
586 int lineno = -1;
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700587 if (next->item_type == INTERFACE_TYPE_BINDER) {
588 lineno = ((interface_type*)next)->interface_token.lineno;
589 }
590 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 lineno = ((interface_type*)next)->interface_token.lineno;
592 }
Joe Onorato94ca1b92011-10-09 22:31:16 -0700593 else if (next->item_type == USER_DATA_TYPE) {
594 lineno = ((user_data_type*)next)->keyword_token.lineno;
Joe Onoratoacff0822011-09-15 21:31:15 -0700595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
597 filename, lineno);
598 return 1;
599 }
600
Joe Onorato94ca1b92011-10-09 22:31:16 -0700601 if (items->item_type == USER_DATA_TYPE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 *onlyParcelable = true;
603 if (options.failOnParcelable) {
604 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Joe Onoratoacff0822011-09-15 21:31:15 -0700605 " parcelables or flattenables,\n", filename,
Joe Onorato94ca1b92011-10-09 22:31:16 -0700606 ((user_data_type*)items)->keyword_token.lineno);
Joe Onoratoacff0822011-09-15 21:31:15 -0700607 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
608 "may not go in the Makefile.\n", filename,
Joe Onorato94ca1b92011-10-09 22:31:16 -0700609 ((user_data_type*)items)->keyword_token.lineno);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 return 1;
611 }
612 } else {
613 *onlyParcelable = false;
614 }
615
616 return 0;
617}
618
619// ==========================================================
620void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700621generate_dep_file(const Options& options, const document_item_type* items)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622{
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700623 /* we open the file in binary mode to ensure that the same output is
624 * generated on all platforms !!
625 */
626 FILE* to = NULL;
627 if (options.autoDepFile) {
628 string fileName = options.outputFileName + ".d";
629 to = fopen(fileName.c_str(), "wb");
630 } else {
631 to = fopen(options.depFileName.c_str(), "wb");
632 }
633
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 if (to == NULL) {
635 return;
636 }
637
638 const char* slash = "\\";
639 import_info* import = g_imports;
640 if (import == NULL) {
641 slash = "";
642 }
643
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700644 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700645 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
646 } else {
647 // parcelable: there's no output file.
648 fprintf(to, " : \\\n");
649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
651
652 while (import) {
653 if (import->next == NULL) {
654 slash = "";
655 }
656 if (import->filename) {
657 fprintf(to, " %s %s\n", import->filename, slash);
658 }
659 import = import->next;
660 }
661
662 fprintf(to, "\n");
663
664 fclose(to);
665}
666
667// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700668static string
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700669generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700670{
671 string result;
672
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700673 // create the path to the destination folder based on the
674 // interface package name
675 result = options.outputBaseFolder;
676 result += OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700677
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700678 string packageStr = package;
679 size_t len = packageStr.length();
680 for (size_t i=0; i<len; i++) {
681 if (packageStr[i] == '.') {
682 packageStr[i] = OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700683 }
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700684 }
685
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700686 result += packageStr;
687
688 // add the filename by replacing the .aidl extension to .java
689 const char* p = strchr(name.data, '.');
690 len = p ? p-name.data : strlen(name.data);
691
692 result += OS_PATH_SEPARATOR;
693 result.append(name.data, len);
694 result += ".java";
695
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700696 return result;
697}
698
699// ==========================================================
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700700static string
701generate_outputFileName(const Options& options, const document_item_type* items)
702{
703 // items has already been checked to have only one interface.
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700704 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700705 interface_type* type = (interface_type*)items;
706
707 return generate_outputFileName2(options, type->name, type->package);
Joe Onorato94ca1b92011-10-09 22:31:16 -0700708 } else if (items->item_type == USER_DATA_TYPE) {
709 user_data_type* type = (user_data_type*)items;
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700710 return generate_outputFileName2(options, type->name, type->package);
711 }
712
713 // I don't think we can come here, but safer than returning NULL.
714 string result;
715 return result;
716}
717
718
719
720// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700721static void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700722check_outputFilePath(const string& path) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700723 size_t len = path.length();
724 for (size_t i=0; i<len ; i++) {
725 if (path[i] == OS_PATH_SEPARATOR) {
726 string p = path.substr(0, i);
727 if (access(path.data(), F_OK) != 0) {
728#ifdef HAVE_MS_C_RUNTIME
729 _mkdir(p.data());
730#else
731 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
732#endif
733 }
734 }
735 }
736}
737
738
739// ==========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740static int
741parse_preprocessed_file(const string& filename)
742{
743 int err;
744
745 FILE* f = fopen(filename.c_str(), "rb");
746 if (f == NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800747 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 filename.c_str());
749 return 1;
750 }
751
752 int lineno = 1;
753 char line[1024];
754 char type[1024];
755 char fullname[1024];
756 while (fgets(line, sizeof(line), f)) {
757 // skip comments and empty lines
758 if (!line[0] || strncmp(line, "//", 2) == 0) {
759 continue;
760 }
761
762 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
763
764 char* packagename;
765 char* classname = rfind(fullname, '.');
766 if (classname != NULL) {
767 *classname = '\0';
768 classname++;
769 packagename = fullname;
770 } else {
771 classname = fullname;
772 packagename = NULL;
773 }
774
775 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
776 // type, packagename, classname);
777 document_item_type* doc;
778
779 if (0 == strcmp("parcelable", type)) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700780 user_data_type* parcl = (user_data_type*)malloc(
781 sizeof(user_data_type));
782 memset(parcl, 0, sizeof(user_data_type));
783 parcl->document_item.item_type = USER_DATA_TYPE;
784 parcl->keyword_token.lineno = lineno;
785 parcl->keyword_token.data = strdup(type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 parcl->package = packagename ? strdup(packagename) : NULL;
787 parcl->name.lineno = lineno;
788 parcl->name.data = strdup(classname);
789 parcl->semicolon_token.lineno = lineno;
790 parcl->semicolon_token.data = strdup(";");
Joe Onorato94ca1b92011-10-09 22:31:16 -0700791 parcl->flattening_methods = PARCELABLE_DATA;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 doc = (document_item_type*)parcl;
793 }
Joe Onoratoacff0822011-09-15 21:31:15 -0700794 else if (0 == strcmp("flattenable", type)) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700795 user_data_type* parcl = (user_data_type*)malloc(
796 sizeof(user_data_type));
797 memset(parcl, 0, sizeof(user_data_type));
798 parcl->document_item.item_type = USER_DATA_TYPE;
799 parcl->keyword_token.lineno = lineno;
800 parcl->keyword_token.data = strdup(type);
Joe Onoratoacff0822011-09-15 21:31:15 -0700801 parcl->package = packagename ? strdup(packagename) : NULL;
802 parcl->name.lineno = lineno;
803 parcl->name.data = strdup(classname);
804 parcl->semicolon_token.lineno = lineno;
805 parcl->semicolon_token.data = strdup(";");
Joe Onorato94ca1b92011-10-09 22:31:16 -0700806 parcl->flattening_methods = RPC_DATA;
Joe Onoratoacff0822011-09-15 21:31:15 -0700807 doc = (document_item_type*)parcl;
808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 else if (0 == strcmp("interface", type)) {
810 interface_type* iface = (interface_type*)malloc(
811 sizeof(interface_type));
812 memset(iface, 0, sizeof(interface_type));
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700813 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 iface->interface_token.lineno = lineno;
815 iface->interface_token.data = strdup(type);
816 iface->package = packagename ? strdup(packagename) : NULL;
817 iface->name.lineno = lineno;
818 iface->name.data = strdup(classname);
819 iface->open_brace_token.lineno = lineno;
820 iface->open_brace_token.data = strdup("{");
821 iface->close_brace_token.lineno = lineno;
822 iface->close_brace_token.data = strdup("}");
823 doc = (document_item_type*)iface;
824 }
825 else {
826 fprintf(stderr, "%s:%d: bad type in line: %s\n",
827 filename.c_str(), lineno, line);
828 return 1;
829 }
830 err = gather_types(filename.c_str(), doc);
831 lineno++;
832 }
833
834 if (!feof(f)) {
835 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
836 filename.c_str(), lineno);
837 return 1;
838 }
839
840 fclose(f);
841 return 0;
842}
843
844// ==========================================================
845static int
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700846compile_aidl(Options& options)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847{
848 int err = 0, N;
849
850 set_import_paths(options.importPaths);
851
852 register_base_types();
853
854 // import the preprocessed file
855 N = options.preprocessedFiles.size();
856 for (int i=0; i<N; i++) {
857 const string& s = options.preprocessedFiles[i];
858 err |= parse_preprocessed_file(s);
859 }
860 if (err != 0) {
861 return err;
862 }
863
864 // parse the main file
865 g_callbacks = &g_mainCallbacks;
866 err = parse_aidl(options.inputFileName.c_str());
867 document_item_type* mainDoc = g_document;
868 g_document = NULL;
869
870 // parse the imports
871 g_callbacks = &g_mainCallbacks;
872 import_info* import = g_imports;
873 while (import) {
874 if (NAMES.Find(import->neededClass) == NULL) {
875 import->filename = find_import_file(import->neededClass);
876 if (!import->filename) {
877 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
878 import->from, import->statement.lineno,
879 import->neededClass);
880 err |= 1;
881 } else {
882 err |= parse_aidl(import->filename);
883 import->doc = g_document;
884 if (import->doc == NULL) {
885 err |= 1;
886 }
887 }
888 }
889 import = import->next;
890 }
891 // bail out now if parsing wasn't successful
892 if (err != 0 || mainDoc == NULL) {
893 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
894 return 1;
895 }
896
897 // complain about ones that aren't in the right files
898 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
899 import = g_imports;
900 while (import) {
901 err |= check_filenames(import->filename, import->doc);
902 import = import->next;
903 }
904
905 // gather the types that have been declared
906 err |= gather_types(options.inputFileName.c_str(), mainDoc);
907 import = g_imports;
908 while (import) {
909 err |= gather_types(import->filename, import->doc);
910 import = import->next;
911 }
912
913#if 0
914 printf("---- main doc ----\n");
915 test_document(mainDoc);
916
917 import = g_imports;
918 while (import) {
919 printf("---- import doc ----\n");
920 test_document(import->doc);
921 import = import->next;
922 }
923 NAMES.Dump();
924#endif
925
926 // check the referenced types in mainDoc to make sure we've imported them
927 err |= check_types(options.inputFileName.c_str(), mainDoc);
928
929 // finally, there really only needs to be one thing in mainDoc, and it
930 // needs to be an interface.
931 bool onlyParcelable = false;
932 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
933
934 // after this, there shouldn't be any more errors because of the
935 // input.
936 if (err != 0 || mainDoc == NULL) {
937 return 1;
938 }
939
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700940 // if needed, generate the outputFileName from the outputBaseFolder
941 if (options.outputFileName.length() == 0 &&
942 options.outputBaseFolder.length() > 0) {
943 options.outputFileName = generate_outputFileName(options, mainDoc);
944 }
945
946 // if we were asked to, generate a make dependency file
947 // unless it's a parcelable *and* it's supposed to fail on parcelable
948 if ((options.autoDepFile || options.depFileName != "") &&
949 !(onlyParcelable && options.failOnParcelable)) {
950 // make sure the folders of the output file all exists
951 check_outputFilePath(options.outputFileName);
952 generate_dep_file(options, mainDoc);
953 }
954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 // they didn't ask to fail on parcelables, so just exit quietly.
956 if (onlyParcelable && !options.failOnParcelable) {
957 return 0;
958 }
959
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700960 // make sure the folders of the output file all exists
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700961 check_outputFilePath(options.outputFileName);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700962
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700963 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 (interface_type*)mainDoc);
965
966 return err;
967}
968
969static int
970preprocess_aidl(const Options& options)
971{
972 vector<string> lines;
973 int err;
974
975 // read files
976 int N = options.filesToPreprocess.size();
977 for (int i=0; i<N; i++) {
978 g_callbacks = &g_mainCallbacks;
979 err = parse_aidl(options.filesToPreprocess[i].c_str());
980 if (err != 0) {
981 return err;
982 }
983 document_item_type* doc = g_document;
984 string line;
Joe Onorato94ca1b92011-10-09 22:31:16 -0700985 if (doc->item_type == USER_DATA_TYPE) {
986 user_data_type* parcelable = (user_data_type*)doc;
987 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
988 line = "parcelable ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
Joe Onorato94ca1b92011-10-09 22:31:16 -0700990 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
991 line = "flattenable ";
992 }
Joe Onoratoacff0822011-09-15 21:31:15 -0700993 if (parcelable->package) {
994 line += parcelable->package;
995 line += '.';
996 }
997 line += parcelable->name.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } else {
999 line = "interface ";
1000 interface_type* iface = (interface_type*)doc;
1001 if (iface->package) {
1002 line += iface->package;
1003 line += '.';
1004 }
1005 line += iface->name.data;
1006 }
1007 line += ";\n";
1008 lines.push_back(line);
1009 }
1010
1011 // write preprocessed file
1012 int fd = open( options.outputFileName.c_str(),
1013 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1014#ifdef HAVE_MS_C_RUNTIME
1015 _S_IREAD|_S_IWRITE);
1016#else
1017 S_IRUSR|S_IWUSR|S_IRGRP);
1018#endif
1019 if (fd == -1) {
1020 fprintf(stderr, "aidl: could not open file for write: %s\n",
1021 options.outputFileName.c_str());
1022 return 1;
1023 }
1024
1025 N = lines.size();
1026 for (int i=0; i<N; i++) {
1027 const string& s = lines[i];
1028 int len = s.length();
1029 if (len != write(fd, s.c_str(), len)) {
1030 fprintf(stderr, "aidl: error writing to file %s\n",
1031 options.outputFileName.c_str());
1032 close(fd);
1033 unlink(options.outputFileName.c_str());
1034 return 1;
1035 }
1036 }
1037
1038 close(fd);
1039 return 0;
1040}
1041
1042// ==========================================================
1043int
1044main(int argc, const char **argv)
1045{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 Options options;
1047 int result = parse_options(argc, argv, &options);
1048 if (result) {
1049 return result;
1050 }
1051
1052 switch (options.task)
1053 {
1054 case COMPILE_AIDL:
1055 return compile_aidl(options);
1056 case PREPROCESS_AIDL:
1057 return preprocess_aidl(options);
1058 }
1059 fprintf(stderr, "aidl: internal error\n");
1060 return 1;
1061}