blob: 8dbbf502a007cebbd8a5c6f65a971deb3e5de98a [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 }
Joe Onoratoa1c6d902011-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 Onorato7db766c2011-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 Onoratoa1c6d902011-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 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";
Joe Onoratoa1c6d902011-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 Onoratoa1c6d902011-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 Onorato7db766c2011-09-15 21:31:15 -0700304 }
Joe Onoratofdfe2ff2011-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 Onoratofdfe2ff2011-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 Onorato7db766c2011-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 Onorato7db766c2011-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 Onoratofdfe2ff2011-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 Onorato7db766c2011-09-15 21:31:15 -0700350 name, Type::GENERATED, false, false, false,
Joe Onoratofdfe2ff2011-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 Onorato7db766c2011-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 Onoratoe24dbea2011-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())) {
427 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
428 m->type.type.lineno, m->type.type.data);
429 err = 1;
430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
432
433 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
434 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
435 m->type.array_token.lineno, m->type.type.data,
436 m->type.array_token.data);
437 err = 1;
438 }
439
440 if (m->type.dimension > 1) {
441 fprintf(stderr, "%s:%d return type %s%s only one"
442 " dimensional arrays are supported\n", filename,
443 m->type.array_token.lineno, m->type.type.data,
444 m->type.array_token.data);
445 err = 1;
446 }
447
448 int index = 1;
449
450 arg_type* arg = m->args;
451 while (arg) {
452 Type* t = NAMES.Search(arg->type.type.data);
453
454 // check the arg type
455 if (t == NULL) {
456 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
457 filename, m->type.type.lineno, arg->name.data, index,
458 arg->type.type.data);
459 err = 1;
460 goto next;
461 }
Joe Onoratoe24dbea2011-09-23 15:17:52 -0700462
463 if (t == EVENT_FAKE_TYPE) {
464 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
465 filename, m->type.type.lineno, arg->name.data, index,
466 arg->type.type.data);
467 err = 1;
468 goto next;
469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470
Joe Onorato7db766c2011-09-15 21:31:15 -0700471 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
473 filename, m->type.type.lineno, index,
474 arg->type.type.data, arg->name.data);
475 err = 1;
476 }
477
Joe Onoratofcb310f2011-11-08 17:35:09 -0800478 if (returnType == EVENT_FAKE_TYPE
479 && convert_direction(arg->direction.data) != IN_PARAMETER) {
480 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
481 filename, m->type.type.lineno, index,
482 arg->type.type.data, arg->name.data);
483 err = 1;
484 goto next;
485 }
486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 if (arg->direction.data == NULL
488 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
489 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
490 " parameter, so you must declare it as in,"
491 " out or inout.\n",
492 filename, m->type.type.lineno, index,
493 arg->type.type.data, arg->name.data);
494 err = 1;
495 }
496
497 if (convert_direction(arg->direction.data) != IN_PARAMETER
498 && !t->CanBeOutParameter()
499 && arg->type.dimension == 0) {
500 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
501 " parameter.\n",
502 filename, m->type.type.lineno, index,
503 arg->direction.data, arg->type.type.data,
504 arg->name.data);
505 err = 1;
506 }
507
508 if (arg->type.dimension > 0 && !t->CanBeArray()) {
509 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
510 " array.\n", filename,
511 m->type.array_token.lineno, index, arg->direction.data,
512 arg->type.type.data, arg->type.array_token.data,
513 arg->name.data);
514 err = 1;
515 }
516
517 if (arg->type.dimension > 1) {
518 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
519 " dimensional arrays are supported\n", filename,
520 m->type.array_token.lineno, index, arg->direction.data,
521 arg->type.type.data, arg->type.array_token.data,
522 arg->name.data);
523 err = 1;
524 }
525
526 // check that the name doesn't match a keyword
527 if (matches_keyword(arg->name.data)) {
528 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
Joe Onoratoe24dbea2011-09-23 15:17:52 -0700529 " Java or aidl keyword\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 filename, m->name.lineno, index, arg->name.data);
531 err = 1;
532 }
533
534next:
535 index++;
536 arg = arg->next;
537 }
538
539 return err;
540}
541
542static int
543check_types(const char* filename, document_item_type* items)
544{
545 int err = 0;
546 while (items) {
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700547 // (nothing to check for USER_DATA_TYPE)
Joe Onorato7db766c2011-09-15 21:31:15 -0700548 if (items->item_type == INTERFACE_TYPE_BINDER
549 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 map<string,method_type*> methodNames;
551 interface_type* c = (interface_type*)items;
552
553 interface_item_type* member = c->interface_items;
554 while (member) {
555 if (member->item_type == METHOD_TYPE) {
556 method_type* m = (method_type*)member;
557
Joe Onorato7db766c2011-09-15 21:31:15 -0700558 err |= check_method(filename, items->item_type, m);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559
560 // prevent duplicate methods
561 if (methodNames.find(m->name.data) == methodNames.end()) {
562 methodNames[m->name.data] = m;
563 } else {
564 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
565 filename, m->name.lineno, m->name.data);
566 method_type* old = methodNames[m->name.data];
567 fprintf(stderr, "%s:%d previously defined here.\n",
568 filename, old->name.lineno);
569 err = 1;
570 }
571 }
572 member = member->next;
573 }
574 }
575
576 items = items->next;
577 }
578 return err;
579}
580
581// ==========================================================
582static int
583exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
584 bool* onlyParcelable)
585{
586 if (items == NULL) {
587 fprintf(stderr, "%s: file does not contain any interfaces\n",
588 filename);
589 return 1;
590 }
591
592 const document_item_type* next = items->next;
593 if (items->next != NULL) {
594 int lineno = -1;
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700595 if (next->item_type == INTERFACE_TYPE_BINDER) {
596 lineno = ((interface_type*)next)->interface_token.lineno;
597 }
598 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 lineno = ((interface_type*)next)->interface_token.lineno;
600 }
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700601 else if (next->item_type == USER_DATA_TYPE) {
602 lineno = ((user_data_type*)next)->keyword_token.lineno;
Joe Onorato7db766c2011-09-15 21:31:15 -0700603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
605 filename, lineno);
606 return 1;
607 }
608
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700609 if (items->item_type == USER_DATA_TYPE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 *onlyParcelable = true;
611 if (options.failOnParcelable) {
612 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Joe Onorato7db766c2011-09-15 21:31:15 -0700613 " parcelables or flattenables,\n", filename,
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700614 ((user_data_type*)items)->keyword_token.lineno);
Joe Onorato7db766c2011-09-15 21:31:15 -0700615 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
616 "may not go in the Makefile.\n", filename,
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700617 ((user_data_type*)items)->keyword_token.lineno);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 return 1;
619 }
620 } else {
621 *onlyParcelable = false;
622 }
623
624 return 0;
625}
626
627// ==========================================================
628void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700629generate_dep_file(const Options& options, const document_item_type* items)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630{
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700631 /* we open the file in binary mode to ensure that the same output is
632 * generated on all platforms !!
633 */
634 FILE* to = NULL;
635 if (options.autoDepFile) {
636 string fileName = options.outputFileName + ".d";
637 to = fopen(fileName.c_str(), "wb");
638 } else {
639 to = fopen(options.depFileName.c_str(), "wb");
640 }
641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 if (to == NULL) {
643 return;
644 }
645
646 const char* slash = "\\";
647 import_info* import = g_imports;
648 if (import == NULL) {
649 slash = "";
650 }
651
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700652 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700653 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
654 } else {
655 // parcelable: there's no output file.
656 fprintf(to, " : \\\n");
657 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
659
660 while (import) {
661 if (import->next == NULL) {
662 slash = "";
663 }
664 if (import->filename) {
665 fprintf(to, " %s %s\n", import->filename, slash);
666 }
667 import = import->next;
668 }
669
670 fprintf(to, "\n");
671
672 fclose(to);
673}
674
675// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700676static string
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700677generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700678{
679 string result;
680
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700681 // create the path to the destination folder based on the
682 // interface package name
683 result = options.outputBaseFolder;
684 result += OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700685
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700686 string packageStr = package;
687 size_t len = packageStr.length();
688 for (size_t i=0; i<len; i++) {
689 if (packageStr[i] == '.') {
690 packageStr[i] = OS_PATH_SEPARATOR;
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700691 }
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700692 }
693
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700694 result += packageStr;
695
696 // add the filename by replacing the .aidl extension to .java
697 const char* p = strchr(name.data, '.');
698 len = p ? p-name.data : strlen(name.data);
699
700 result += OS_PATH_SEPARATOR;
701 result.append(name.data, len);
702 result += ".java";
703
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700704 return result;
705}
706
707// ==========================================================
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700708static string
709generate_outputFileName(const Options& options, const document_item_type* items)
710{
711 // items has already been checked to have only one interface.
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700712 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700713 interface_type* type = (interface_type*)items;
714
715 return generate_outputFileName2(options, type->name, type->package);
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700716 } else if (items->item_type == USER_DATA_TYPE) {
717 user_data_type* type = (user_data_type*)items;
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700718 return generate_outputFileName2(options, type->name, type->package);
719 }
720
721 // I don't think we can come here, but safer than returning NULL.
722 string result;
723 return result;
724}
725
726
727
728// ==========================================================
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700729static void
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700730check_outputFilePath(const string& path) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700731 size_t len = path.length();
732 for (size_t i=0; i<len ; i++) {
733 if (path[i] == OS_PATH_SEPARATOR) {
734 string p = path.substr(0, i);
735 if (access(path.data(), F_OK) != 0) {
736#ifdef HAVE_MS_C_RUNTIME
737 _mkdir(p.data());
738#else
739 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
740#endif
741 }
742 }
743 }
744}
745
746
747// ==========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748static int
749parse_preprocessed_file(const string& filename)
750{
751 int err;
752
753 FILE* f = fopen(filename.c_str(), "rb");
754 if (f == NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800755 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 filename.c_str());
757 return 1;
758 }
759
760 int lineno = 1;
761 char line[1024];
762 char type[1024];
763 char fullname[1024];
764 while (fgets(line, sizeof(line), f)) {
765 // skip comments and empty lines
766 if (!line[0] || strncmp(line, "//", 2) == 0) {
767 continue;
768 }
769
770 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
771
772 char* packagename;
773 char* classname = rfind(fullname, '.');
774 if (classname != NULL) {
775 *classname = '\0';
776 classname++;
777 packagename = fullname;
778 } else {
779 classname = fullname;
780 packagename = NULL;
781 }
782
783 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
784 // type, packagename, classname);
785 document_item_type* doc;
786
787 if (0 == strcmp("parcelable", type)) {
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700788 user_data_type* parcl = (user_data_type*)malloc(
789 sizeof(user_data_type));
790 memset(parcl, 0, sizeof(user_data_type));
791 parcl->document_item.item_type = USER_DATA_TYPE;
792 parcl->keyword_token.lineno = lineno;
793 parcl->keyword_token.data = strdup(type);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 parcl->package = packagename ? strdup(packagename) : NULL;
795 parcl->name.lineno = lineno;
796 parcl->name.data = strdup(classname);
797 parcl->semicolon_token.lineno = lineno;
798 parcl->semicolon_token.data = strdup(";");
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700799 parcl->flattening_methods = PARCELABLE_DATA;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 doc = (document_item_type*)parcl;
801 }
Joe Onorato7db766c2011-09-15 21:31:15 -0700802 else if (0 == strcmp("flattenable", type)) {
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700803 user_data_type* parcl = (user_data_type*)malloc(
804 sizeof(user_data_type));
805 memset(parcl, 0, sizeof(user_data_type));
806 parcl->document_item.item_type = USER_DATA_TYPE;
807 parcl->keyword_token.lineno = lineno;
808 parcl->keyword_token.data = strdup(type);
Joe Onorato7db766c2011-09-15 21:31:15 -0700809 parcl->package = packagename ? strdup(packagename) : NULL;
810 parcl->name.lineno = lineno;
811 parcl->name.data = strdup(classname);
812 parcl->semicolon_token.lineno = lineno;
813 parcl->semicolon_token.data = strdup(";");
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700814 parcl->flattening_methods = RPC_DATA;
Joe Onorato7db766c2011-09-15 21:31:15 -0700815 doc = (document_item_type*)parcl;
816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 else if (0 == strcmp("interface", type)) {
818 interface_type* iface = (interface_type*)malloc(
819 sizeof(interface_type));
820 memset(iface, 0, sizeof(interface_type));
Joe Onoratofdfe2ff2011-08-30 17:24:17 -0700821 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 iface->interface_token.lineno = lineno;
823 iface->interface_token.data = strdup(type);
824 iface->package = packagename ? strdup(packagename) : NULL;
825 iface->name.lineno = lineno;
826 iface->name.data = strdup(classname);
827 iface->open_brace_token.lineno = lineno;
828 iface->open_brace_token.data = strdup("{");
829 iface->close_brace_token.lineno = lineno;
830 iface->close_brace_token.data = strdup("}");
831 doc = (document_item_type*)iface;
832 }
833 else {
834 fprintf(stderr, "%s:%d: bad type in line: %s\n",
835 filename.c_str(), lineno, line);
836 return 1;
837 }
838 err = gather_types(filename.c_str(), doc);
839 lineno++;
840 }
841
842 if (!feof(f)) {
843 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
844 filename.c_str(), lineno);
845 return 1;
846 }
847
848 fclose(f);
849 return 0;
850}
851
852// ==========================================================
853static int
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700854compile_aidl(Options& options)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855{
856 int err = 0, N;
857
858 set_import_paths(options.importPaths);
859
860 register_base_types();
861
862 // import the preprocessed file
863 N = options.preprocessedFiles.size();
864 for (int i=0; i<N; i++) {
865 const string& s = options.preprocessedFiles[i];
866 err |= parse_preprocessed_file(s);
867 }
868 if (err != 0) {
869 return err;
870 }
871
872 // parse the main file
873 g_callbacks = &g_mainCallbacks;
874 err = parse_aidl(options.inputFileName.c_str());
875 document_item_type* mainDoc = g_document;
876 g_document = NULL;
877
878 // parse the imports
879 g_callbacks = &g_mainCallbacks;
880 import_info* import = g_imports;
881 while (import) {
882 if (NAMES.Find(import->neededClass) == NULL) {
883 import->filename = find_import_file(import->neededClass);
884 if (!import->filename) {
885 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
886 import->from, import->statement.lineno,
887 import->neededClass);
888 err |= 1;
889 } else {
890 err |= parse_aidl(import->filename);
891 import->doc = g_document;
892 if (import->doc == NULL) {
893 err |= 1;
894 }
895 }
896 }
897 import = import->next;
898 }
899 // bail out now if parsing wasn't successful
900 if (err != 0 || mainDoc == NULL) {
901 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
902 return 1;
903 }
904
905 // complain about ones that aren't in the right files
906 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
907 import = g_imports;
908 while (import) {
909 err |= check_filenames(import->filename, import->doc);
910 import = import->next;
911 }
912
913 // gather the types that have been declared
914 err |= gather_types(options.inputFileName.c_str(), mainDoc);
915 import = g_imports;
916 while (import) {
917 err |= gather_types(import->filename, import->doc);
918 import = import->next;
919 }
920
921#if 0
922 printf("---- main doc ----\n");
923 test_document(mainDoc);
924
925 import = g_imports;
926 while (import) {
927 printf("---- import doc ----\n");
928 test_document(import->doc);
929 import = import->next;
930 }
931 NAMES.Dump();
932#endif
933
934 // check the referenced types in mainDoc to make sure we've imported them
935 err |= check_types(options.inputFileName.c_str(), mainDoc);
936
937 // finally, there really only needs to be one thing in mainDoc, and it
938 // needs to be an interface.
939 bool onlyParcelable = false;
940 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
941
942 // after this, there shouldn't be any more errors because of the
943 // input.
944 if (err != 0 || mainDoc == NULL) {
945 return 1;
946 }
947
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700948 // if needed, generate the outputFileName from the outputBaseFolder
949 if (options.outputFileName.length() == 0 &&
950 options.outputBaseFolder.length() > 0) {
951 options.outputFileName = generate_outputFileName(options, mainDoc);
952 }
953
954 // if we were asked to, generate a make dependency file
955 // unless it's a parcelable *and* it's supposed to fail on parcelable
956 if ((options.autoDepFile || options.depFileName != "") &&
957 !(onlyParcelable && options.failOnParcelable)) {
958 // make sure the folders of the output file all exists
959 check_outputFilePath(options.outputFileName);
960 generate_dep_file(options, mainDoc);
961 }
962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 // they didn't ask to fail on parcelables, so just exit quietly.
964 if (onlyParcelable && !options.failOnParcelable) {
965 return 0;
966 }
967
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700968 // make sure the folders of the output file all exists
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700969 check_outputFilePath(options.outputFileName);
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700970
Xavier Ducrohet18fff112011-08-25 11:58:17 -0700971 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 (interface_type*)mainDoc);
973
974 return err;
975}
976
977static int
978preprocess_aidl(const Options& options)
979{
980 vector<string> lines;
981 int err;
982
983 // read files
984 int N = options.filesToPreprocess.size();
985 for (int i=0; i<N; i++) {
986 g_callbacks = &g_mainCallbacks;
987 err = parse_aidl(options.filesToPreprocess[i].c_str());
988 if (err != 0) {
989 return err;
990 }
991 document_item_type* doc = g_document;
992 string line;
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700993 if (doc->item_type == USER_DATA_TYPE) {
994 user_data_type* parcelable = (user_data_type*)doc;
995 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
996 line = "parcelable ";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
Joe Onoratoa1c6d902011-10-09 22:31:16 -0700998 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
999 line = "flattenable ";
1000 }
Joe Onorato7db766c2011-09-15 21:31:15 -07001001 if (parcelable->package) {
1002 line += parcelable->package;
1003 line += '.';
1004 }
1005 line += parcelable->name.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 } else {
1007 line = "interface ";
1008 interface_type* iface = (interface_type*)doc;
1009 if (iface->package) {
1010 line += iface->package;
1011 line += '.';
1012 }
1013 line += iface->name.data;
1014 }
1015 line += ";\n";
1016 lines.push_back(line);
1017 }
1018
1019 // write preprocessed file
1020 int fd = open( options.outputFileName.c_str(),
1021 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1022#ifdef HAVE_MS_C_RUNTIME
1023 _S_IREAD|_S_IWRITE);
1024#else
1025 S_IRUSR|S_IWUSR|S_IRGRP);
1026#endif
1027 if (fd == -1) {
1028 fprintf(stderr, "aidl: could not open file for write: %s\n",
1029 options.outputFileName.c_str());
1030 return 1;
1031 }
1032
1033 N = lines.size();
1034 for (int i=0; i<N; i++) {
1035 const string& s = lines[i];
1036 int len = s.length();
1037 if (len != write(fd, s.c_str(), len)) {
1038 fprintf(stderr, "aidl: error writing to file %s\n",
1039 options.outputFileName.c_str());
1040 close(fd);
1041 unlink(options.outputFileName.c_str());
1042 return 1;
1043 }
1044 }
1045
1046 close(fd);
1047 return 0;
1048}
1049
1050// ==========================================================
1051int
1052main(int argc, const char **argv)
1053{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 Options options;
1055 int result = parse_options(argc, argv, &options);
1056 if (result) {
1057 return result;
1058 }
1059
1060 switch (options.task)
1061 {
1062 case COMPILE_AIDL:
1063 return compile_aidl(options);
1064 case PREPROCESS_AIDL:
1065 return preprocess_aidl(options);
1066 }
1067 fprintf(stderr, "aidl: internal error\n");
1068 return 1;
1069}