blob: e5689b915c4bf4641db4019e2d7eccce1fc252ff [file] [log] [blame]
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -08001
2#include "aidl_language.h"
3#include "options.h"
4#include "search_path.h"
5#include "Type.h"
6#include "generate_java.h"
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/param.h>
10#include <sys/stat.h>
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <map>
16
17#ifdef HAVE_MS_C_RUNTIME
18#include <io.h>
19#include <sys/stat.h>
20#endif
21
22#ifndef O_BINARY
23# define O_BINARY 0
24#endif
25
26using namespace std;
27
28static void
29test_document(document_item_type* d)
30{
31 while (d) {
Joe Onoratoc596cfe2011-08-30 17:24:17 -070032 if (d->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -080033 interface_type* c = (interface_type*)d;
34 printf("interface %s %s {\n", c->package, c->name.data);
35 interface_item_type *q = (interface_item_type*)c->interface_items;
36 while (q) {
37 if (q->item_type == METHOD_TYPE) {
38 method_type *m = (method_type*)q;
39 printf(" %s %s(", m->type.type.data, m->name.data);
40 arg_type *p = m->args;
41 while (p) {
42 printf("%s %s",p->type.type.data,p->name.data);
43 if (p->next) printf(", ");
44 p=p->next;
45 }
46 printf(")");
47 printf(";\n");
48 }
49 q=q->next;
50 }
51 printf("}\n");
52 }
Joe Onoratobaaf9c82011-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 Onorato4135a7d2011-09-15 21:31:15 -070061 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -080062 else {
Scott Turner2c3d74b2010-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 Projecte42b5f52009-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 Onoratobaaf9c82011-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 Projecte42b5f52009-03-03 19:31:44 -0800248 err |= check_filename(filename, p->package, &p->name);
249 }
Joe Onoratoc596cfe2011-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 Projecte42b5f52009-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 Onoratobaaf9c82011-10-09 22:31:16 -0700273 case Type::USERDATA:
274 return "a user data";
The Android Open Source Projecte42b5f52009-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 Onoratobaaf9c82011-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 Onorato4135a7d2011-09-15 21:31:15 -0700304 }
Joe Onoratoc596cfe2011-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 Projecte42b5f52009-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 Onoratoc596cfe2011-08-30 17:24:17 -0700321 if (items->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Projecte42b5f52009-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 Onorato4135a7d2011-09-15 21:31:15 -0700330 name, Type::GENERATED, false, false, false,
The Android Open Source Projecte42b5f52009-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 Onorato4135a7d2011-09-15 21:31:15 -0700337 name, Type::GENERATED, false, false, false,
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800338 filename, c->name.lineno);
339 NAMES.Add(proxy);
340 }
Joe Onoratoc596cfe2011-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 Onorato4135a7d2011-09-15 21:31:15 -0700350 name, Type::GENERATED, false, false, false,
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700351 filename, c->name.lineno);
352 NAMES.Add(base);
353 }
The Android Open Source Projecte42b5f52009-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 Onorato4135a7d2011-09-15 21:31:15 -0700405check_method(const char* filename, int kind, method_type* m)
The Android Open Source Projecte42b5f52009-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 Onoratoe20125d2011-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 Projecte42b5f52009-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 Onoratoe20125d2011-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 Projecte42b5f52009-03-03 19:31:44 -0800470
Joe Onorato4135a7d2011-09-15 21:31:15 -0700471 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
The Android Open Source Projecte42b5f52009-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
478 if (arg->direction.data == NULL
479 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
480 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
481 " parameter, so you must declare it as in,"
482 " out or inout.\n",
483 filename, m->type.type.lineno, index,
484 arg->type.type.data, arg->name.data);
485 err = 1;
486 }
487
488 if (convert_direction(arg->direction.data) != IN_PARAMETER
489 && !t->CanBeOutParameter()
490 && arg->type.dimension == 0) {
491 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
492 " parameter.\n",
493 filename, m->type.type.lineno, index,
494 arg->direction.data, arg->type.type.data,
495 arg->name.data);
496 err = 1;
497 }
498
499 if (arg->type.dimension > 0 && !t->CanBeArray()) {
500 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
501 " array.\n", filename,
502 m->type.array_token.lineno, index, arg->direction.data,
503 arg->type.type.data, arg->type.array_token.data,
504 arg->name.data);
505 err = 1;
506 }
507
508 if (arg->type.dimension > 1) {
509 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
510 " dimensional arrays are supported\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 // check that the name doesn't match a keyword
518 if (matches_keyword(arg->name.data)) {
519 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
Joe Onoratoe20125d2011-09-23 15:17:52 -0700520 " Java or aidl keyword\n",
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800521 filename, m->name.lineno, index, arg->name.data);
522 err = 1;
523 }
524
525next:
526 index++;
527 arg = arg->next;
528 }
529
530 return err;
531}
532
533static int
534check_types(const char* filename, document_item_type* items)
535{
536 int err = 0;
537 while (items) {
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700538 // (nothing to check for USER_DATA_TYPE)
Joe Onorato4135a7d2011-09-15 21:31:15 -0700539 if (items->item_type == INTERFACE_TYPE_BINDER
540 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800541 map<string,method_type*> methodNames;
542 interface_type* c = (interface_type*)items;
543
544 interface_item_type* member = c->interface_items;
545 while (member) {
546 if (member->item_type == METHOD_TYPE) {
547 method_type* m = (method_type*)member;
548
Joe Onorato4135a7d2011-09-15 21:31:15 -0700549 err |= check_method(filename, items->item_type, m);
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800550
551 // prevent duplicate methods
552 if (methodNames.find(m->name.data) == methodNames.end()) {
553 methodNames[m->name.data] = m;
554 } else {
555 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
556 filename, m->name.lineno, m->name.data);
557 method_type* old = methodNames[m->name.data];
558 fprintf(stderr, "%s:%d previously defined here.\n",
559 filename, old->name.lineno);
560 err = 1;
561 }
562 }
563 member = member->next;
564 }
565 }
566
567 items = items->next;
568 }
569 return err;
570}
571
572// ==========================================================
573static int
574exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
575 bool* onlyParcelable)
576{
577 if (items == NULL) {
578 fprintf(stderr, "%s: file does not contain any interfaces\n",
579 filename);
580 return 1;
581 }
582
583 const document_item_type* next = items->next;
584 if (items->next != NULL) {
585 int lineno = -1;
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700586 if (next->item_type == INTERFACE_TYPE_BINDER) {
587 lineno = ((interface_type*)next)->interface_token.lineno;
588 }
589 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800590 lineno = ((interface_type*)next)->interface_token.lineno;
591 }
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700592 else if (next->item_type == USER_DATA_TYPE) {
593 lineno = ((user_data_type*)next)->keyword_token.lineno;
Joe Onorato4135a7d2011-09-15 21:31:15 -0700594 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800595 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
596 filename, lineno);
597 return 1;
598 }
599
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700600 if (items->item_type == USER_DATA_TYPE) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800601 *onlyParcelable = true;
602 if (options.failOnParcelable) {
603 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Joe Onorato4135a7d2011-09-15 21:31:15 -0700604 " parcelables or flattenables,\n", filename,
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700605 ((user_data_type*)items)->keyword_token.lineno);
Joe Onorato4135a7d2011-09-15 21:31:15 -0700606 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
607 "may not go in the Makefile.\n", filename,
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700608 ((user_data_type*)items)->keyword_token.lineno);
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800609 return 1;
610 }
611 } else {
612 *onlyParcelable = false;
613 }
614
615 return 0;
616}
617
618// ==========================================================
619void
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700620generate_dep_file(const Options& options, const document_item_type* items)
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800621{
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700622 /* we open the file in binary mode to ensure that the same output is
623 * generated on all platforms !!
624 */
625 FILE* to = NULL;
626 if (options.autoDepFile) {
627 string fileName = options.outputFileName + ".d";
628 to = fopen(fileName.c_str(), "wb");
629 } else {
630 to = fopen(options.depFileName.c_str(), "wb");
631 }
632
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800633 if (to == NULL) {
634 return;
635 }
636
637 const char* slash = "\\";
638 import_info* import = g_imports;
639 if (import == NULL) {
640 slash = "";
641 }
642
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700643 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700644 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
645 } else {
646 // parcelable: there's no output file.
647 fprintf(to, " : \\\n");
648 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800649 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
650
651 while (import) {
652 if (import->next == NULL) {
653 slash = "";
654 }
655 if (import->filename) {
656 fprintf(to, " %s %s\n", import->filename, slash);
657 }
658 import = import->next;
659 }
660
661 fprintf(to, "\n");
662
663 fclose(to);
664}
665
666// ==========================================================
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700667static string
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700668generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700669{
670 string result;
671
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700672 // create the path to the destination folder based on the
673 // interface package name
674 result = options.outputBaseFolder;
675 result += OS_PATH_SEPARATOR;
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700676
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700677 string packageStr = package;
678 size_t len = packageStr.length();
679 for (size_t i=0; i<len; i++) {
680 if (packageStr[i] == '.') {
681 packageStr[i] = OS_PATH_SEPARATOR;
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700682 }
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700683 }
684
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700685 result += packageStr;
686
687 // add the filename by replacing the .aidl extension to .java
688 const char* p = strchr(name.data, '.');
689 len = p ? p-name.data : strlen(name.data);
690
691 result += OS_PATH_SEPARATOR;
692 result.append(name.data, len);
693 result += ".java";
694
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700695 return result;
696}
697
698// ==========================================================
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700699static string
700generate_outputFileName(const Options& options, const document_item_type* items)
701{
702 // items has already been checked to have only one interface.
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700703 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700704 interface_type* type = (interface_type*)items;
705
706 return generate_outputFileName2(options, type->name, type->package);
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700707 } else if (items->item_type == USER_DATA_TYPE) {
708 user_data_type* type = (user_data_type*)items;
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700709 return generate_outputFileName2(options, type->name, type->package);
710 }
711
712 // I don't think we can come here, but safer than returning NULL.
713 string result;
714 return result;
715}
716
717
718
719// ==========================================================
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700720static void
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700721check_outputFilePath(const string& path) {
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700722 size_t len = path.length();
723 for (size_t i=0; i<len ; i++) {
724 if (path[i] == OS_PATH_SEPARATOR) {
725 string p = path.substr(0, i);
726 if (access(path.data(), F_OK) != 0) {
727#ifdef HAVE_MS_C_RUNTIME
728 _mkdir(p.data());
729#else
730 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
731#endif
732 }
733 }
734 }
735}
736
737
738// ==========================================================
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800739static int
740parse_preprocessed_file(const string& filename)
741{
742 int err;
743
744 FILE* f = fopen(filename.c_str(), "rb");
745 if (f == NULL) {
The Android Open Source Projected7bd9d2009-03-05 14:34:35 -0800746 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800747 filename.c_str());
748 return 1;
749 }
750
751 int lineno = 1;
752 char line[1024];
753 char type[1024];
754 char fullname[1024];
755 while (fgets(line, sizeof(line), f)) {
756 // skip comments and empty lines
757 if (!line[0] || strncmp(line, "//", 2) == 0) {
758 continue;
759 }
760
761 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
762
763 char* packagename;
764 char* classname = rfind(fullname, '.');
765 if (classname != NULL) {
766 *classname = '\0';
767 classname++;
768 packagename = fullname;
769 } else {
770 classname = fullname;
771 packagename = NULL;
772 }
773
774 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
775 // type, packagename, classname);
776 document_item_type* doc;
777
778 if (0 == strcmp("parcelable", type)) {
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700779 user_data_type* parcl = (user_data_type*)malloc(
780 sizeof(user_data_type));
781 memset(parcl, 0, sizeof(user_data_type));
782 parcl->document_item.item_type = USER_DATA_TYPE;
783 parcl->keyword_token.lineno = lineno;
784 parcl->keyword_token.data = strdup(type);
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800785 parcl->package = packagename ? strdup(packagename) : NULL;
786 parcl->name.lineno = lineno;
787 parcl->name.data = strdup(classname);
788 parcl->semicolon_token.lineno = lineno;
789 parcl->semicolon_token.data = strdup(";");
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700790 parcl->flattening_methods = PARCELABLE_DATA;
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800791 doc = (document_item_type*)parcl;
792 }
Joe Onorato4135a7d2011-09-15 21:31:15 -0700793 else if (0 == strcmp("flattenable", type)) {
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700794 user_data_type* parcl = (user_data_type*)malloc(
795 sizeof(user_data_type));
796 memset(parcl, 0, sizeof(user_data_type));
797 parcl->document_item.item_type = USER_DATA_TYPE;
798 parcl->keyword_token.lineno = lineno;
799 parcl->keyword_token.data = strdup(type);
Joe Onorato4135a7d2011-09-15 21:31:15 -0700800 parcl->package = packagename ? strdup(packagename) : NULL;
801 parcl->name.lineno = lineno;
802 parcl->name.data = strdup(classname);
803 parcl->semicolon_token.lineno = lineno;
804 parcl->semicolon_token.data = strdup(";");
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700805 parcl->flattening_methods = RPC_DATA;
Joe Onorato4135a7d2011-09-15 21:31:15 -0700806 doc = (document_item_type*)parcl;
807 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800808 else if (0 == strcmp("interface", type)) {
809 interface_type* iface = (interface_type*)malloc(
810 sizeof(interface_type));
811 memset(iface, 0, sizeof(interface_type));
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700812 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800813 iface->interface_token.lineno = lineno;
814 iface->interface_token.data = strdup(type);
815 iface->package = packagename ? strdup(packagename) : NULL;
816 iface->name.lineno = lineno;
817 iface->name.data = strdup(classname);
818 iface->open_brace_token.lineno = lineno;
819 iface->open_brace_token.data = strdup("{");
820 iface->close_brace_token.lineno = lineno;
821 iface->close_brace_token.data = strdup("}");
822 doc = (document_item_type*)iface;
823 }
824 else {
825 fprintf(stderr, "%s:%d: bad type in line: %s\n",
826 filename.c_str(), lineno, line);
827 return 1;
828 }
829 err = gather_types(filename.c_str(), doc);
830 lineno++;
831 }
832
833 if (!feof(f)) {
834 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
835 filename.c_str(), lineno);
836 return 1;
837 }
838
839 fclose(f);
840 return 0;
841}
842
843// ==========================================================
844static int
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700845compile_aidl(Options& options)
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800846{
847 int err = 0, N;
848
849 set_import_paths(options.importPaths);
850
851 register_base_types();
852
853 // import the preprocessed file
854 N = options.preprocessedFiles.size();
855 for (int i=0; i<N; i++) {
856 const string& s = options.preprocessedFiles[i];
857 err |= parse_preprocessed_file(s);
858 }
859 if (err != 0) {
860 return err;
861 }
862
863 // parse the main file
864 g_callbacks = &g_mainCallbacks;
865 err = parse_aidl(options.inputFileName.c_str());
866 document_item_type* mainDoc = g_document;
867 g_document = NULL;
868
869 // parse the imports
870 g_callbacks = &g_mainCallbacks;
871 import_info* import = g_imports;
872 while (import) {
873 if (NAMES.Find(import->neededClass) == NULL) {
874 import->filename = find_import_file(import->neededClass);
875 if (!import->filename) {
876 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
877 import->from, import->statement.lineno,
878 import->neededClass);
879 err |= 1;
880 } else {
881 err |= parse_aidl(import->filename);
882 import->doc = g_document;
883 if (import->doc == NULL) {
884 err |= 1;
885 }
886 }
887 }
888 import = import->next;
889 }
890 // bail out now if parsing wasn't successful
891 if (err != 0 || mainDoc == NULL) {
892 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
893 return 1;
894 }
895
896 // complain about ones that aren't in the right files
897 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
898 import = g_imports;
899 while (import) {
900 err |= check_filenames(import->filename, import->doc);
901 import = import->next;
902 }
903
904 // gather the types that have been declared
905 err |= gather_types(options.inputFileName.c_str(), mainDoc);
906 import = g_imports;
907 while (import) {
908 err |= gather_types(import->filename, import->doc);
909 import = import->next;
910 }
911
912#if 0
913 printf("---- main doc ----\n");
914 test_document(mainDoc);
915
916 import = g_imports;
917 while (import) {
918 printf("---- import doc ----\n");
919 test_document(import->doc);
920 import = import->next;
921 }
922 NAMES.Dump();
923#endif
924
925 // check the referenced types in mainDoc to make sure we've imported them
926 err |= check_types(options.inputFileName.c_str(), mainDoc);
927
928 // finally, there really only needs to be one thing in mainDoc, and it
929 // needs to be an interface.
930 bool onlyParcelable = false;
931 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
932
933 // after this, there shouldn't be any more errors because of the
934 // input.
935 if (err != 0 || mainDoc == NULL) {
936 return 1;
937 }
938
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700939 // if needed, generate the outputFileName from the outputBaseFolder
940 if (options.outputFileName.length() == 0 &&
941 options.outputBaseFolder.length() > 0) {
942 options.outputFileName = generate_outputFileName(options, mainDoc);
943 }
944
945 // if we were asked to, generate a make dependency file
946 // unless it's a parcelable *and* it's supposed to fail on parcelable
947 if ((options.autoDepFile || options.depFileName != "") &&
948 !(onlyParcelable && options.failOnParcelable)) {
949 // make sure the folders of the output file all exists
950 check_outputFilePath(options.outputFileName);
951 generate_dep_file(options, mainDoc);
952 }
953
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800954 // they didn't ask to fail on parcelables, so just exit quietly.
955 if (onlyParcelable && !options.failOnParcelable) {
956 return 0;
957 }
958
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700959 // make sure the folders of the output file all exists
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700960 check_outputFilePath(options.outputFileName);
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700961
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700962 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800963 (interface_type*)mainDoc);
964
965 return err;
966}
967
968static int
969preprocess_aidl(const Options& options)
970{
971 vector<string> lines;
972 int err;
973
974 // read files
975 int N = options.filesToPreprocess.size();
976 for (int i=0; i<N; i++) {
977 g_callbacks = &g_mainCallbacks;
978 err = parse_aidl(options.filesToPreprocess[i].c_str());
979 if (err != 0) {
980 return err;
981 }
982 document_item_type* doc = g_document;
983 string line;
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700984 if (doc->item_type == USER_DATA_TYPE) {
985 user_data_type* parcelable = (user_data_type*)doc;
986 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
987 line = "parcelable ";
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800988 }
Joe Onoratobaaf9c82011-10-09 22:31:16 -0700989 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
990 line = "flattenable ";
991 }
Joe Onorato4135a7d2011-09-15 21:31:15 -0700992 if (parcelable->package) {
993 line += parcelable->package;
994 line += '.';
995 }
996 line += parcelable->name.data;
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800997 } else {
998 line = "interface ";
999 interface_type* iface = (interface_type*)doc;
1000 if (iface->package) {
1001 line += iface->package;
1002 line += '.';
1003 }
1004 line += iface->name.data;
1005 }
1006 line += ";\n";
1007 lines.push_back(line);
1008 }
1009
1010 // write preprocessed file
1011 int fd = open( options.outputFileName.c_str(),
1012 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1013#ifdef HAVE_MS_C_RUNTIME
1014 _S_IREAD|_S_IWRITE);
1015#else
1016 S_IRUSR|S_IWUSR|S_IRGRP);
1017#endif
1018 if (fd == -1) {
1019 fprintf(stderr, "aidl: could not open file for write: %s\n",
1020 options.outputFileName.c_str());
1021 return 1;
1022 }
1023
1024 N = lines.size();
1025 for (int i=0; i<N; i++) {
1026 const string& s = lines[i];
1027 int len = s.length();
1028 if (len != write(fd, s.c_str(), len)) {
1029 fprintf(stderr, "aidl: error writing to file %s\n",
1030 options.outputFileName.c_str());
1031 close(fd);
1032 unlink(options.outputFileName.c_str());
1033 return 1;
1034 }
1035 }
1036
1037 close(fd);
1038 return 0;
1039}
1040
1041// ==========================================================
1042int
1043main(int argc, const char **argv)
1044{
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -08001045 Options options;
1046 int result = parse_options(argc, argv, &options);
1047 if (result) {
1048 return result;
1049 }
1050
1051 switch (options.task)
1052 {
1053 case COMPILE_AIDL:
1054 return compile_aidl(options);
1055 case PREPROCESS_AIDL:
1056 return preprocess_aidl(options);
1057 }
1058 fprintf(stderr, "aidl: internal error\n");
1059 return 1;
1060}