blob: 3d314dba3e7c796a08497c7480bc027cffded77b [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
Joe Onorato2037c252011-11-08 17:35:09 -0800479 if (returnType == EVENT_FAKE_TYPE
480 && convert_direction(arg->direction.data) != IN_PARAMETER) {
481 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
482 filename, m->type.type.lineno, index,
483 arg->type.type.data, arg->name.data);
484 err = 1;
485 goto next;
486 }
487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 if (arg->direction.data == NULL
489 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
490 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
491 " parameter, so you must declare it as in,"
492 " out or inout.\n",
493 filename, m->type.type.lineno, index,
494 arg->type.type.data, arg->name.data);
495 err = 1;
496 }
497
498 if (convert_direction(arg->direction.data) != IN_PARAMETER
499 && !t->CanBeOutParameter()
500 && arg->type.dimension == 0) {
501 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
502 " parameter.\n",
503 filename, m->type.type.lineno, index,
504 arg->direction.data, arg->type.type.data,
505 arg->name.data);
506 err = 1;
507 }
508
509 if (arg->type.dimension > 0 && !t->CanBeArray()) {
510 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
511 " array.\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 if (arg->type.dimension > 1) {
519 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
520 " dimensional arrays are supported\n", filename,
521 m->type.array_token.lineno, index, arg->direction.data,
522 arg->type.type.data, arg->type.array_token.data,
523 arg->name.data);
524 err = 1;
525 }
526
527 // check that the name doesn't match a keyword
528 if (matches_keyword(arg->name.data)) {
529 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
Joe Onorato827af242011-09-23 15:17:52 -0700530 " Java or aidl keyword\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 filename, m->name.lineno, index, arg->name.data);
532 err = 1;
533 }
534
535next:
536 index++;
537 arg = arg->next;
538 }
539
540 return err;
541}
542
543static int
544check_types(const char* filename, document_item_type* items)
545{
546 int err = 0;
547 while (items) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700548 // (nothing to check for USER_DATA_TYPE)
Joe Onoratoacff0822011-09-15 21:31:15 -0700549 if (items->item_type == INTERFACE_TYPE_BINDER
550 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 map<string,method_type*> methodNames;
552 interface_type* c = (interface_type*)items;
553
554 interface_item_type* member = c->interface_items;
555 while (member) {
556 if (member->item_type == METHOD_TYPE) {
557 method_type* m = (method_type*)member;
558
Joe Onoratoacff0822011-09-15 21:31:15 -0700559 err |= check_method(filename, items->item_type, m);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560
561 // prevent duplicate methods
562 if (methodNames.find(m->name.data) == methodNames.end()) {
563 methodNames[m->name.data] = m;
564 } else {
565 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
566 filename, m->name.lineno, m->name.data);
567 method_type* old = methodNames[m->name.data];
568 fprintf(stderr, "%s:%d previously defined here.\n",
569 filename, old->name.lineno);
570 err = 1;
571 }
572 }
573 member = member->next;
574 }
575 }
576
577 items = items->next;
578 }
579 return err;
580}
581
582// ==========================================================
583static int
584exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
585 bool* onlyParcelable)
586{
587 if (items == NULL) {
588 fprintf(stderr, "%s: file does not contain any interfaces\n",
589 filename);
590 return 1;
591 }
592
593 const document_item_type* next = items->next;
594 if (items->next != NULL) {
595 int lineno = -1;
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700596 if (next->item_type == INTERFACE_TYPE_BINDER) {
597 lineno = ((interface_type*)next)->interface_token.lineno;
598 }
599 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 lineno = ((interface_type*)next)->interface_token.lineno;
601 }
Joe Onorato94ca1b92011-10-09 22:31:16 -0700602 else if (next->item_type == USER_DATA_TYPE) {
603 lineno = ((user_data_type*)next)->keyword_token.lineno;
Joe Onoratoacff0822011-09-15 21:31:15 -0700604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
606 filename, lineno);
607 return 1;
608 }
609
Joe Onorato94ca1b92011-10-09 22:31:16 -0700610 if (items->item_type == USER_DATA_TYPE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 *onlyParcelable = true;
612 if (options.failOnParcelable) {
613 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Joe Onoratoacff0822011-09-15 21:31:15 -0700614 " parcelables or flattenables,\n", filename,
Joe Onorato94ca1b92011-10-09 22:31:16 -0700615 ((user_data_type*)items)->keyword_token.lineno);
Joe Onoratoacff0822011-09-15 21:31:15 -0700616 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
617 "may not go in the Makefile.\n", filename,
Joe Onorato94ca1b92011-10-09 22:31:16 -0700618 ((user_data_type*)items)->keyword_token.lineno);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 return 1;
620 }
621 } else {
622 *onlyParcelable = false;
623 }
624
625 return 0;
626}
627
628// ==========================================================
629void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700630generate_dep_file(const Options& options, const document_item_type* items)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631{
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700632 /* we open the file in binary mode to ensure that the same output is
633 * generated on all platforms !!
634 */
635 FILE* to = NULL;
636 if (options.autoDepFile) {
637 string fileName = options.outputFileName + ".d";
638 to = fopen(fileName.c_str(), "wb");
639 } else {
640 to = fopen(options.depFileName.c_str(), "wb");
641 }
642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 if (to == NULL) {
644 return;
645 }
646
647 const char* slash = "\\";
648 import_info* import = g_imports;
649 if (import == NULL) {
650 slash = "";
651 }
652
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700653 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700654 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
655 } else {
656 // parcelable: there's no output file.
657 fprintf(to, " : \\\n");
658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
660
661 while (import) {
662 if (import->next == NULL) {
663 slash = "";
664 }
665 if (import->filename) {
666 fprintf(to, " %s %s\n", import->filename, slash);
667 }
668 import = import->next;
669 }
670
671 fprintf(to, "\n");
672
673 fclose(to);
674}
675
676// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700677static string
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700678generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700679{
680 string result;
681
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700682 // create the path to the destination folder based on the
683 // interface package name
684 result = options.outputBaseFolder;
685 result += OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700686
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700687 string packageStr = package;
688 size_t len = packageStr.length();
689 for (size_t i=0; i<len; i++) {
690 if (packageStr[i] == '.') {
691 packageStr[i] = OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700692 }
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700693 }
694
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700695 result += packageStr;
696
697 // add the filename by replacing the .aidl extension to .java
698 const char* p = strchr(name.data, '.');
699 len = p ? p-name.data : strlen(name.data);
700
701 result += OS_PATH_SEPARATOR;
702 result.append(name.data, len);
703 result += ".java";
704
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700705 return result;
706}
707
708// ==========================================================
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700709static string
710generate_outputFileName(const Options& options, const document_item_type* items)
711{
712 // items has already been checked to have only one interface.
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700713 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700714 interface_type* type = (interface_type*)items;
715
716 return generate_outputFileName2(options, type->name, type->package);
Joe Onorato94ca1b92011-10-09 22:31:16 -0700717 } else if (items->item_type == USER_DATA_TYPE) {
718 user_data_type* type = (user_data_type*)items;
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700719 return generate_outputFileName2(options, type->name, type->package);
720 }
721
722 // I don't think we can come here, but safer than returning NULL.
723 string result;
724 return result;
725}
726
727
728
729// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700730static void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700731check_outputFilePath(const string& path) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700732 size_t len = path.length();
733 for (size_t i=0; i<len ; i++) {
734 if (path[i] == OS_PATH_SEPARATOR) {
735 string p = path.substr(0, i);
736 if (access(path.data(), F_OK) != 0) {
737#ifdef HAVE_MS_C_RUNTIME
738 _mkdir(p.data());
739#else
740 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
741#endif
742 }
743 }
744 }
745}
746
747
748// ==========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749static int
750parse_preprocessed_file(const string& filename)
751{
752 int err;
753
754 FILE* f = fopen(filename.c_str(), "rb");
755 if (f == NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800756 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 filename.c_str());
758 return 1;
759 }
760
761 int lineno = 1;
762 char line[1024];
763 char type[1024];
764 char fullname[1024];
765 while (fgets(line, sizeof(line), f)) {
766 // skip comments and empty lines
767 if (!line[0] || strncmp(line, "//", 2) == 0) {
768 continue;
769 }
770
771 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
772
773 char* packagename;
774 char* classname = rfind(fullname, '.');
775 if (classname != NULL) {
776 *classname = '\0';
777 classname++;
778 packagename = fullname;
779 } else {
780 classname = fullname;
781 packagename = NULL;
782 }
783
784 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
785 // type, packagename, classname);
786 document_item_type* doc;
787
788 if (0 == strcmp("parcelable", type)) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700789 user_data_type* parcl = (user_data_type*)malloc(
790 sizeof(user_data_type));
791 memset(parcl, 0, sizeof(user_data_type));
792 parcl->document_item.item_type = USER_DATA_TYPE;
793 parcl->keyword_token.lineno = lineno;
794 parcl->keyword_token.data = strdup(type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 parcl->package = packagename ? strdup(packagename) : NULL;
796 parcl->name.lineno = lineno;
797 parcl->name.data = strdup(classname);
798 parcl->semicolon_token.lineno = lineno;
799 parcl->semicolon_token.data = strdup(";");
Joe Onorato94ca1b92011-10-09 22:31:16 -0700800 parcl->flattening_methods = PARCELABLE_DATA;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 doc = (document_item_type*)parcl;
802 }
Joe Onoratoacff0822011-09-15 21:31:15 -0700803 else if (0 == strcmp("flattenable", type)) {
Joe Onorato94ca1b92011-10-09 22:31:16 -0700804 user_data_type* parcl = (user_data_type*)malloc(
805 sizeof(user_data_type));
806 memset(parcl, 0, sizeof(user_data_type));
807 parcl->document_item.item_type = USER_DATA_TYPE;
808 parcl->keyword_token.lineno = lineno;
809 parcl->keyword_token.data = strdup(type);
Joe Onoratoacff0822011-09-15 21:31:15 -0700810 parcl->package = packagename ? strdup(packagename) : NULL;
811 parcl->name.lineno = lineno;
812 parcl->name.data = strdup(classname);
813 parcl->semicolon_token.lineno = lineno;
814 parcl->semicolon_token.data = strdup(";");
Joe Onorato94ca1b92011-10-09 22:31:16 -0700815 parcl->flattening_methods = RPC_DATA;
Joe Onoratoacff0822011-09-15 21:31:15 -0700816 doc = (document_item_type*)parcl;
817 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 else if (0 == strcmp("interface", type)) {
819 interface_type* iface = (interface_type*)malloc(
820 sizeof(interface_type));
821 memset(iface, 0, sizeof(interface_type));
Joe Onoratoae7f32e2011-08-30 17:24:17 -0700822 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 iface->interface_token.lineno = lineno;
824 iface->interface_token.data = strdup(type);
825 iface->package = packagename ? strdup(packagename) : NULL;
826 iface->name.lineno = lineno;
827 iface->name.data = strdup(classname);
828 iface->open_brace_token.lineno = lineno;
829 iface->open_brace_token.data = strdup("{");
830 iface->close_brace_token.lineno = lineno;
831 iface->close_brace_token.data = strdup("}");
832 doc = (document_item_type*)iface;
833 }
834 else {
835 fprintf(stderr, "%s:%d: bad type in line: %s\n",
836 filename.c_str(), lineno, line);
837 return 1;
838 }
839 err = gather_types(filename.c_str(), doc);
840 lineno++;
841 }
842
843 if (!feof(f)) {
844 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
845 filename.c_str(), lineno);
846 return 1;
847 }
848
849 fclose(f);
850 return 0;
851}
852
853// ==========================================================
854static int
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700855compile_aidl(Options& options)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856{
857 int err = 0, N;
858
859 set_import_paths(options.importPaths);
860
861 register_base_types();
862
863 // import the preprocessed file
864 N = options.preprocessedFiles.size();
865 for (int i=0; i<N; i++) {
866 const string& s = options.preprocessedFiles[i];
867 err |= parse_preprocessed_file(s);
868 }
869 if (err != 0) {
870 return err;
871 }
872
873 // parse the main file
874 g_callbacks = &g_mainCallbacks;
875 err = parse_aidl(options.inputFileName.c_str());
876 document_item_type* mainDoc = g_document;
877 g_document = NULL;
878
879 // parse the imports
880 g_callbacks = &g_mainCallbacks;
881 import_info* import = g_imports;
882 while (import) {
883 if (NAMES.Find(import->neededClass) == NULL) {
884 import->filename = find_import_file(import->neededClass);
885 if (!import->filename) {
886 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
887 import->from, import->statement.lineno,
888 import->neededClass);
889 err |= 1;
890 } else {
891 err |= parse_aidl(import->filename);
892 import->doc = g_document;
893 if (import->doc == NULL) {
894 err |= 1;
895 }
896 }
897 }
898 import = import->next;
899 }
900 // bail out now if parsing wasn't successful
901 if (err != 0 || mainDoc == NULL) {
902 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
903 return 1;
904 }
905
906 // complain about ones that aren't in the right files
907 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
908 import = g_imports;
909 while (import) {
910 err |= check_filenames(import->filename, import->doc);
911 import = import->next;
912 }
913
914 // gather the types that have been declared
915 err |= gather_types(options.inputFileName.c_str(), mainDoc);
916 import = g_imports;
917 while (import) {
918 err |= gather_types(import->filename, import->doc);
919 import = import->next;
920 }
921
922#if 0
923 printf("---- main doc ----\n");
924 test_document(mainDoc);
925
926 import = g_imports;
927 while (import) {
928 printf("---- import doc ----\n");
929 test_document(import->doc);
930 import = import->next;
931 }
932 NAMES.Dump();
933#endif
934
935 // check the referenced types in mainDoc to make sure we've imported them
936 err |= check_types(options.inputFileName.c_str(), mainDoc);
937
938 // finally, there really only needs to be one thing in mainDoc, and it
939 // needs to be an interface.
940 bool onlyParcelable = false;
941 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
942
943 // after this, there shouldn't be any more errors because of the
944 // input.
945 if (err != 0 || mainDoc == NULL) {
946 return 1;
947 }
948
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700949 // if needed, generate the outputFileName from the outputBaseFolder
950 if (options.outputFileName.length() == 0 &&
951 options.outputBaseFolder.length() > 0) {
952 options.outputFileName = generate_outputFileName(options, mainDoc);
953 }
954
955 // if we were asked to, generate a make dependency file
956 // unless it's a parcelable *and* it's supposed to fail on parcelable
957 if ((options.autoDepFile || options.depFileName != "") &&
958 !(onlyParcelable && options.failOnParcelable)) {
959 // make sure the folders of the output file all exists
960 check_outputFilePath(options.outputFileName);
961 generate_dep_file(options, mainDoc);
962 }
963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 // they didn't ask to fail on parcelables, so just exit quietly.
965 if (onlyParcelable && !options.failOnParcelable) {
966 return 0;
967 }
968
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700969 // make sure the folders of the output file all exists
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700970 check_outputFilePath(options.outputFileName);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700971
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700972 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 (interface_type*)mainDoc);
974
975 return err;
976}
977
978static int
979preprocess_aidl(const Options& options)
980{
981 vector<string> lines;
982 int err;
983
984 // read files
985 int N = options.filesToPreprocess.size();
986 for (int i=0; i<N; i++) {
987 g_callbacks = &g_mainCallbacks;
988 err = parse_aidl(options.filesToPreprocess[i].c_str());
989 if (err != 0) {
990 return err;
991 }
992 document_item_type* doc = g_document;
993 string line;
Joe Onorato94ca1b92011-10-09 22:31:16 -0700994 if (doc->item_type == USER_DATA_TYPE) {
995 user_data_type* parcelable = (user_data_type*)doc;
996 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
997 line = "parcelable ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
Joe Onorato94ca1b92011-10-09 22:31:16 -0700999 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1000 line = "flattenable ";
1001 }
Joe Onoratoacff0822011-09-15 21:31:15 -07001002 if (parcelable->package) {
1003 line += parcelable->package;
1004 line += '.';
1005 }
1006 line += parcelable->name.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 } else {
1008 line = "interface ";
1009 interface_type* iface = (interface_type*)doc;
1010 if (iface->package) {
1011 line += iface->package;
1012 line += '.';
1013 }
1014 line += iface->name.data;
1015 }
1016 line += ";\n";
1017 lines.push_back(line);
1018 }
1019
1020 // write preprocessed file
1021 int fd = open( options.outputFileName.c_str(),
1022 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1023#ifdef HAVE_MS_C_RUNTIME
1024 _S_IREAD|_S_IWRITE);
1025#else
1026 S_IRUSR|S_IWUSR|S_IRGRP);
1027#endif
1028 if (fd == -1) {
1029 fprintf(stderr, "aidl: could not open file for write: %s\n",
1030 options.outputFileName.c_str());
1031 return 1;
1032 }
1033
1034 N = lines.size();
1035 for (int i=0; i<N; i++) {
1036 const string& s = lines[i];
1037 int len = s.length();
1038 if (len != write(fd, s.c_str(), len)) {
1039 fprintf(stderr, "aidl: error writing to file %s\n",
1040 options.outputFileName.c_str());
1041 close(fd);
1042 unlink(options.outputFileName.c_str());
1043 return 1;
1044 }
1045 }
1046
1047 close(fd);
1048 return 0;
1049}
1050
1051// ==========================================================
1052int
1053main(int argc, const char **argv)
1054{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 Options options;
1056 int result = parse_options(argc, argv, &options);
1057 if (result) {
1058 return result;
1059 }
1060
1061 switch (options.task)
1062 {
1063 case COMPILE_AIDL:
1064 return compile_aidl(options);
1065 case PREPROCESS_AIDL:
1066 return preprocess_aidl(options);
1067 }
1068 fprintf(stderr, "aidl: internal error\n");
1069 return 1;
1070}