blob: ab9a2454dab4df1e4f97acfc111da0982e011ea0 [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 }
53 else if (d->item_type == PARCELABLE_TYPE) {
54 parcelable_type* b = (parcelable_type*)d;
55 printf("parcelable %s %s;\n", b->package, b->name.data);
56 }
Joe Onorato4135a7d2011-09-15 21:31:15 -070057 else if (d->item_type == FLATTENABLE_TYPE) {
58 parcelable_type* b = (parcelable_type*)d;
59 printf("flattenable %s %s;\n", b->package, b->name.data);
60 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -080061 else {
Scott Turner2c3d74b2010-01-14 21:05:17 -050062 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -080063 }
64 d = d->next;
65 }
66}
67
68// ==========================================================
69int
70convert_direction(const char* direction)
71{
72 if (direction == NULL) {
73 return IN_PARAMETER;
74 }
75 if (0 == strcmp(direction, "in")) {
76 return IN_PARAMETER;
77 }
78 if (0 == strcmp(direction, "out")) {
79 return OUT_PARAMETER;
80 }
81 return INOUT_PARAMETER;
82}
83
84// ==========================================================
85struct import_info {
86 const char* from;
87 const char* filename;
88 buffer_type statement;
89 const char* neededClass;
90 document_item_type* doc;
91 struct import_info* next;
92};
93
94document_item_type* g_document = NULL;
95import_info* g_imports = NULL;
96
97static void
98main_document_parsed(document_item_type* d)
99{
100 g_document = d;
101}
102
103static void
104main_import_parsed(buffer_type* statement)
105{
106 import_info* import = (import_info*)malloc(sizeof(import_info));
107 memset(import, 0, sizeof(import_info));
108 import->from = strdup(g_currentFilename);
109 import->statement.lineno = statement->lineno;
110 import->statement.data = strdup(statement->data);
111 import->statement.extra = NULL;
112 import->next = g_imports;
113 import->neededClass = parse_import_statement(statement->data);
114 g_imports = import;
115}
116
117static ParserCallbacks g_mainCallbacks = {
118 &main_document_parsed,
119 &main_import_parsed
120};
121
122char*
123parse_import_statement(const char* text)
124{
125 const char* end;
126 int len;
127
128 while (isspace(*text)) {
129 text++;
130 }
131 while (!isspace(*text)) {
132 text++;
133 }
134 while (isspace(*text)) {
135 text++;
136 }
137 end = text;
138 while (!isspace(*end) && *end != ';') {
139 end++;
140 }
141 len = end-text;
142
143 char* rv = (char*)malloc(len+1);
144 memcpy(rv, text, len);
145 rv[len] = '\0';
146
147 return rv;
148}
149
150// ==========================================================
151static void
152import_import_parsed(buffer_type* statement)
153{
154}
155
156static ParserCallbacks g_importCallbacks = {
157 &main_document_parsed,
158 &import_import_parsed
159};
160
161// ==========================================================
162static int
163check_filename(const char* filename, const char* package, buffer_type* name)
164{
165 const char* p;
166 string expected;
167 string fn;
168 size_t len;
169 char cwd[MAXPATHLEN];
170 bool valid = false;
171
172#ifdef HAVE_WINDOWS_PATHS
173 if (isalpha(filename[0]) && filename[1] == ':'
174 && filename[2] == OS_PATH_SEPARATOR) {
175#else
176 if (filename[0] == OS_PATH_SEPARATOR) {
177#endif
178 fn = filename;
179 } else {
180 fn = getcwd(cwd, sizeof(cwd));
181 len = fn.length();
182 if (fn[len-1] != OS_PATH_SEPARATOR) {
183 fn += OS_PATH_SEPARATOR;
184 }
185 fn += filename;
186 }
187
188 if (package) {
189 expected = package;
190 expected += '.';
191 }
192
193 len = expected.length();
194 for (size_t i=0; i<len; i++) {
195 if (expected[i] == '.') {
196 expected[i] = OS_PATH_SEPARATOR;
197 }
198 }
199
200 p = strchr(name->data, '.');
201 len = p ? p-name->data : strlen(name->data);
202 expected.append(name->data, len);
203
204 expected += ".aidl";
205
206 len = fn.length();
207 valid = (len >= expected.length());
208
209 if (valid) {
210 p = fn.c_str() + (len - expected.length());
211
212#ifdef HAVE_WINDOWS_PATHS
213 if (OS_PATH_SEPARATOR != '/') {
214 // Input filename under cygwin most likely has / separators
215 // whereas the expected string uses \\ separators. Adjust
216 // them accordingly.
217 for (char *c = const_cast<char *>(p); *c; ++c) {
218 if (*c == '/') *c = OS_PATH_SEPARATOR;
219 }
220 }
221#endif
222
223#ifdef OS_CASE_SENSITIVE
224 valid = (expected == p);
225#else
226 valid = !strcasecmp(expected.c_str(), p);
227#endif
228 }
229
230 if (!valid) {
231 fprintf(stderr, "%s:%d interface %s should be declared in a file"
232 " called %s.\n",
233 filename, name->lineno, name->data, expected.c_str());
234 return 1;
235 }
236
237 return 0;
238}
239
240static int
241check_filenames(const char* filename, document_item_type* items)
242{
243 int err = 0;
244 while (items) {
Joe Onorato4135a7d2011-09-15 21:31:15 -0700245 if (items->item_type == PARCELABLE_TYPE
246 || items->item_type == FLATTENABLE_TYPE) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800247 parcelable_type* p = (parcelable_type*)items;
248 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";
273 case Type::PARCELABLE:
274 return "a parcelable";
275 default:
276 return "ERROR";
277 }
278}
279
280static char*
281rfind(char* str, char c)
282{
283 char* p = str + strlen(str) - 1;
284 while (p >= str) {
285 if (*p == c) {
286 return p;
287 }
288 p--;
289 }
290 return NULL;
291}
292
293static int
294gather_types(const char* filename, document_item_type* items)
295{
296 int err = 0;
297 while (items) {
298 Type* type;
299 if (items->item_type == PARCELABLE_TYPE) {
300 parcelable_type* p = (parcelable_type*)items;
301 type = new ParcelableType(p->package ? p->package : "",
302 p->name.data, false, filename, p->name.lineno);
303 }
Joe Onorato4135a7d2011-09-15 21:31:15 -0700304 else if (items->item_type == FLATTENABLE_TYPE) {
305 parcelable_type* p = (parcelable_type*)items;
306 type = new FlattenableType(p->package ? p->package : "",
307 p->name.data, false, filename, p->name.lineno);
308 }
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700309 else if (items->item_type == INTERFACE_TYPE_BINDER
310 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800311 interface_type* c = (interface_type*)items;
312 type = new InterfaceType(c->package ? c->package : "",
313 c->name.data, false, c->oneway,
314 filename, c->name.lineno);
315 }
316 else {
317 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
318 return 1;
319 }
320
321 Type* old = NAMES.Find(type->QualifiedName());
322 if (old == NULL) {
323 NAMES.Add(type);
324
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700325 if (items->item_type == INTERFACE_TYPE_BINDER) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800326 // for interfaces, also add the stub and proxy types, we don't
327 // bother checking these for duplicates, because the parser
328 // won't let us do it.
329 interface_type* c = (interface_type*)items;
330
331 string name = c->name.data;
332 name += ".Stub";
333 Type* stub = new Type(c->package ? c->package : "",
Joe Onorato4135a7d2011-09-15 21:31:15 -0700334 name, Type::GENERATED, false, false, false,
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800335 filename, c->name.lineno);
336 NAMES.Add(stub);
337
338 name = c->name.data;
339 name += ".Stub.Proxy";
340 Type* proxy = new Type(c->package ? c->package : "",
Joe Onorato4135a7d2011-09-15 21:31:15 -0700341 name, Type::GENERATED, false, false, false,
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800342 filename, c->name.lineno);
343 NAMES.Add(proxy);
344 }
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700345 else if (items->item_type == INTERFACE_TYPE_RPC) {
346 // for interfaces, also add the service base type, we don't
347 // bother checking these for duplicates, because the parser
348 // won't let us do it.
349 interface_type* c = (interface_type*)items;
350
351 string name = c->name.data;
352 name += ".ServiceBase";
353 Type* base = new Type(c->package ? c->package : "",
Joe Onorato4135a7d2011-09-15 21:31:15 -0700354 name, Type::GENERATED, false, false, false,
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700355 filename, c->name.lineno);
356 NAMES.Add(base);
357 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800358 } else {
359 if (old->Kind() == Type::BUILT_IN) {
360 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
361 filename, type->DeclLine(),
362 type->QualifiedName().c_str());
363 err = 1;
364 }
365 else if (type->Kind() != old->Kind()) {
366 const char* oldKind = kind_to_string(old->Kind());
367 const char* newKind = kind_to_string(type->Kind());
368
369 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
370 filename, type->DeclLine(),
371 type->QualifiedName().c_str(), newKind);
372 fprintf(stderr, "%s:%d previously defined here as %s.\n",
373 old->DeclFile().c_str(), old->DeclLine(), oldKind);
374 err = 1;
375 }
376 }
377
378 items = items->next;
379 }
380 return err;
381}
382
383// ==========================================================
384static bool
385matches_keyword(const char* str)
386{
387 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
388 "byte", "case", "catch", "char", "class", "const", "continue",
389 "default", "do", "double", "else", "enum", "extends", "final",
390 "finally", "float", "for", "goto", "if", "implements", "import",
391 "instanceof", "int", "interface", "long", "native", "new", "package",
392 "private", "protected", "public", "return", "short", "static",
393 "strictfp", "super", "switch", "synchronized", "this", "throw",
394 "throws", "transient", "try", "void", "volatile", "while",
395 "true", "false", "null",
396 NULL
397 };
398 const char** k = KEYWORDS;
399 while (*k) {
400 if (0 == strcmp(str, *k)) {
401 return true;
402 }
403 k++;
404 }
405 return false;
406}
407
408static int
Joe Onorato4135a7d2011-09-15 21:31:15 -0700409check_method(const char* filename, int kind, method_type* m)
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800410{
411 int err = 0;
412
413 // return type
414 Type* returnType = NAMES.Search(m->type.type.data);
415 if (returnType == NULL) {
416 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
417 m->type.type.lineno, m->type.type.data);
418 err = 1;
419 return err;
420 }
421
Joe Onoratoe20125d2011-09-23 15:17:52 -0700422 if (returnType == EVENT_FAKE_TYPE) {
423 if (kind != INTERFACE_TYPE_RPC) {
424 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
425 filename, m->type.type.lineno);
426 err = 1;
427 }
428 } else {
429 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
430 : returnType->CanWriteToRpcData())) {
431 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
432 m->type.type.lineno, m->type.type.data);
433 err = 1;
434 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800435 }
436
437 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
438 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
439 m->type.array_token.lineno, m->type.type.data,
440 m->type.array_token.data);
441 err = 1;
442 }
443
444 if (m->type.dimension > 1) {
445 fprintf(stderr, "%s:%d return type %s%s only one"
446 " dimensional arrays are supported\n", filename,
447 m->type.array_token.lineno, m->type.type.data,
448 m->type.array_token.data);
449 err = 1;
450 }
451
452 int index = 1;
453
454 arg_type* arg = m->args;
455 while (arg) {
456 Type* t = NAMES.Search(arg->type.type.data);
457
458 // check the arg type
459 if (t == NULL) {
460 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
461 filename, m->type.type.lineno, arg->name.data, index,
462 arg->type.type.data);
463 err = 1;
464 goto next;
465 }
Joe Onoratoe20125d2011-09-23 15:17:52 -0700466
467 if (t == EVENT_FAKE_TYPE) {
468 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
469 filename, m->type.type.lineno, arg->name.data, index,
470 arg->type.type.data);
471 err = 1;
472 goto next;
473 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800474
Joe Onorato4135a7d2011-09-15 21:31:15 -0700475 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800476 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
477 filename, m->type.type.lineno, index,
478 arg->type.type.data, arg->name.data);
479 err = 1;
480 }
481
482 if (arg->direction.data == NULL
483 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
484 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
485 " parameter, so you must declare it as in,"
486 " out or inout.\n",
487 filename, m->type.type.lineno, index,
488 arg->type.type.data, arg->name.data);
489 err = 1;
490 }
491
492 if (convert_direction(arg->direction.data) != IN_PARAMETER
493 && !t->CanBeOutParameter()
494 && arg->type.dimension == 0) {
495 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
496 " parameter.\n",
497 filename, m->type.type.lineno, index,
498 arg->direction.data, arg->type.type.data,
499 arg->name.data);
500 err = 1;
501 }
502
503 if (arg->type.dimension > 0 && !t->CanBeArray()) {
504 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
505 " array.\n", filename,
506 m->type.array_token.lineno, index, arg->direction.data,
507 arg->type.type.data, arg->type.array_token.data,
508 arg->name.data);
509 err = 1;
510 }
511
512 if (arg->type.dimension > 1) {
513 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
514 " dimensional arrays are supported\n", filename,
515 m->type.array_token.lineno, index, arg->direction.data,
516 arg->type.type.data, arg->type.array_token.data,
517 arg->name.data);
518 err = 1;
519 }
520
521 // check that the name doesn't match a keyword
522 if (matches_keyword(arg->name.data)) {
523 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
Joe Onoratoe20125d2011-09-23 15:17:52 -0700524 " Java or aidl keyword\n",
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800525 filename, m->name.lineno, index, arg->name.data);
526 err = 1;
527 }
528
529next:
530 index++;
531 arg = arg->next;
532 }
533
534 return err;
535}
536
537static int
538check_types(const char* filename, document_item_type* items)
539{
540 int err = 0;
541 while (items) {
Joe Onorato4135a7d2011-09-15 21:31:15 -0700542 // (nothing to check for PARCELABLE_TYPE or FLATTENABLE_TYPE)
543 if (items->item_type == INTERFACE_TYPE_BINDER
544 || items->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800545 map<string,method_type*> methodNames;
546 interface_type* c = (interface_type*)items;
547
548 interface_item_type* member = c->interface_items;
549 while (member) {
550 if (member->item_type == METHOD_TYPE) {
551 method_type* m = (method_type*)member;
552
Joe Onorato4135a7d2011-09-15 21:31:15 -0700553 err |= check_method(filename, items->item_type, m);
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800554
555 // prevent duplicate methods
556 if (methodNames.find(m->name.data) == methodNames.end()) {
557 methodNames[m->name.data] = m;
558 } else {
559 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
560 filename, m->name.lineno, m->name.data);
561 method_type* old = methodNames[m->name.data];
562 fprintf(stderr, "%s:%d previously defined here.\n",
563 filename, old->name.lineno);
564 err = 1;
565 }
566 }
567 member = member->next;
568 }
569 }
570
571 items = items->next;
572 }
573 return err;
574}
575
576// ==========================================================
577static int
578exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
579 bool* onlyParcelable)
580{
581 if (items == NULL) {
582 fprintf(stderr, "%s: file does not contain any interfaces\n",
583 filename);
584 return 1;
585 }
586
587 const document_item_type* next = items->next;
588 if (items->next != NULL) {
589 int lineno = -1;
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700590 if (next->item_type == INTERFACE_TYPE_BINDER) {
591 lineno = ((interface_type*)next)->interface_token.lineno;
592 }
593 else if (next->item_type == INTERFACE_TYPE_RPC) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800594 lineno = ((interface_type*)next)->interface_token.lineno;
595 }
596 else if (next->item_type == PARCELABLE_TYPE) {
597 lineno = ((parcelable_type*)next)->parcelable_token.lineno;
598 }
Joe Onorato4135a7d2011-09-15 21:31:15 -0700599 else if (next->item_type == FLATTENABLE_TYPE) {
600 lineno = ((parcelable_type*)next)->parcelable_token.lineno;
601 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800602 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
603 filename, lineno);
604 return 1;
605 }
606
Joe Onorato4135a7d2011-09-15 21:31:15 -0700607 if (items->item_type == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) {
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800608 *onlyParcelable = true;
609 if (options.failOnParcelable) {
610 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Joe Onorato4135a7d2011-09-15 21:31:15 -0700611 " parcelables or flattenables,\n", filename,
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800612 ((parcelable_type*)items)->parcelable_token.lineno);
Joe Onorato4135a7d2011-09-15 21:31:15 -0700613 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
614 "may not go in the Makefile.\n", filename,
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800615 ((parcelable_type*)items)->parcelable_token.lineno);
616 return 1;
617 }
618 } else {
619 *onlyParcelable = false;
620 }
621
622 return 0;
623}
624
625// ==========================================================
626void
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700627generate_dep_file(const Options& options, const document_item_type* items)
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800628{
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700629 /* we open the file in binary mode to ensure that the same output is
630 * generated on all platforms !!
631 */
632 FILE* to = NULL;
633 if (options.autoDepFile) {
634 string fileName = options.outputFileName + ".d";
635 to = fopen(fileName.c_str(), "wb");
636 } else {
637 to = fopen(options.depFileName.c_str(), "wb");
638 }
639
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800640 if (to == NULL) {
641 return;
642 }
643
644 const char* slash = "\\";
645 import_info* import = g_imports;
646 if (import == NULL) {
647 slash = "";
648 }
649
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700650 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700651 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
652 } else {
653 // parcelable: there's no output file.
654 fprintf(to, " : \\\n");
655 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800656 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
657
658 while (import) {
659 if (import->next == NULL) {
660 slash = "";
661 }
662 if (import->filename) {
663 fprintf(to, " %s %s\n", import->filename, slash);
664 }
665 import = import->next;
666 }
667
668 fprintf(to, "\n");
669
670 fclose(to);
671}
672
673// ==========================================================
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700674static string
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700675generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700676{
677 string result;
678
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700679 // create the path to the destination folder based on the
680 // interface package name
681 result = options.outputBaseFolder;
682 result += OS_PATH_SEPARATOR;
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700683
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700684 string packageStr = package;
685 size_t len = packageStr.length();
686 for (size_t i=0; i<len; i++) {
687 if (packageStr[i] == '.') {
688 packageStr[i] = OS_PATH_SEPARATOR;
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700689 }
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700690 }
691
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700692 result += packageStr;
693
694 // add the filename by replacing the .aidl extension to .java
695 const char* p = strchr(name.data, '.');
696 len = p ? p-name.data : strlen(name.data);
697
698 result += OS_PATH_SEPARATOR;
699 result.append(name.data, len);
700 result += ".java";
701
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700702 return result;
703}
704
705// ==========================================================
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700706static string
707generate_outputFileName(const Options& options, const document_item_type* items)
708{
709 // items has already been checked to have only one interface.
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700710 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700711 interface_type* type = (interface_type*)items;
712
713 return generate_outputFileName2(options, type->name, type->package);
Joe Onorato4135a7d2011-09-15 21:31:15 -0700714 } else if (items->item_type == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) {
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700715 parcelable_type* type = (parcelable_type*)items;
716 return generate_outputFileName2(options, type->name, type->package);
717 }
718
719 // I don't think we can come here, but safer than returning NULL.
720 string result;
721 return result;
722}
723
724
725
726// ==========================================================
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700727static void
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700728check_outputFilePath(const string& path) {
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700729 size_t len = path.length();
730 for (size_t i=0; i<len ; i++) {
731 if (path[i] == OS_PATH_SEPARATOR) {
732 string p = path.substr(0, i);
733 if (access(path.data(), F_OK) != 0) {
734#ifdef HAVE_MS_C_RUNTIME
735 _mkdir(p.data());
736#else
737 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
738#endif
739 }
740 }
741 }
742}
743
744
745// ==========================================================
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800746static int
747parse_preprocessed_file(const string& filename)
748{
749 int err;
750
751 FILE* f = fopen(filename.c_str(), "rb");
752 if (f == NULL) {
The Android Open Source Projected7bd9d2009-03-05 14:34:35 -0800753 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800754 filename.c_str());
755 return 1;
756 }
757
758 int lineno = 1;
759 char line[1024];
760 char type[1024];
761 char fullname[1024];
762 while (fgets(line, sizeof(line), f)) {
763 // skip comments and empty lines
764 if (!line[0] || strncmp(line, "//", 2) == 0) {
765 continue;
766 }
767
768 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
769
770 char* packagename;
771 char* classname = rfind(fullname, '.');
772 if (classname != NULL) {
773 *classname = '\0';
774 classname++;
775 packagename = fullname;
776 } else {
777 classname = fullname;
778 packagename = NULL;
779 }
780
781 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
782 // type, packagename, classname);
783 document_item_type* doc;
784
785 if (0 == strcmp("parcelable", type)) {
786 parcelable_type* parcl = (parcelable_type*)malloc(
787 sizeof(parcelable_type));
788 memset(parcl, 0, sizeof(parcelable_type));
789 parcl->document_item.item_type = PARCELABLE_TYPE;
790 parcl->parcelable_token.lineno = lineno;
791 parcl->parcelable_token.data = strdup(type);
792 parcl->package = packagename ? strdup(packagename) : NULL;
793 parcl->name.lineno = lineno;
794 parcl->name.data = strdup(classname);
795 parcl->semicolon_token.lineno = lineno;
796 parcl->semicolon_token.data = strdup(";");
797 doc = (document_item_type*)parcl;
798 }
Joe Onorato4135a7d2011-09-15 21:31:15 -0700799 else if (0 == strcmp("flattenable", type)) {
800 parcelable_type* parcl = (parcelable_type*)malloc(
801 sizeof(parcelable_type));
802 memset(parcl, 0, sizeof(parcelable_type));
803 parcl->document_item.item_type = FLATTENABLE_TYPE;
804 parcl->parcelable_token.lineno = lineno;
805 parcl->parcelable_token.data = strdup(type);
806 parcl->package = packagename ? strdup(packagename) : NULL;
807 parcl->name.lineno = lineno;
808 parcl->name.data = strdup(classname);
809 parcl->semicolon_token.lineno = lineno;
810 parcl->semicolon_token.data = strdup(";");
811 doc = (document_item_type*)parcl;
812 }
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800813 else if (0 == strcmp("interface", type)) {
814 interface_type* iface = (interface_type*)malloc(
815 sizeof(interface_type));
816 memset(iface, 0, sizeof(interface_type));
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700817 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800818 iface->interface_token.lineno = lineno;
819 iface->interface_token.data = strdup(type);
820 iface->package = packagename ? strdup(packagename) : NULL;
821 iface->name.lineno = lineno;
822 iface->name.data = strdup(classname);
823 iface->open_brace_token.lineno = lineno;
824 iface->open_brace_token.data = strdup("{");
825 iface->close_brace_token.lineno = lineno;
826 iface->close_brace_token.data = strdup("}");
827 doc = (document_item_type*)iface;
828 }
829 else {
830 fprintf(stderr, "%s:%d: bad type in line: %s\n",
831 filename.c_str(), lineno, line);
832 return 1;
833 }
834 err = gather_types(filename.c_str(), doc);
835 lineno++;
836 }
837
838 if (!feof(f)) {
839 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
840 filename.c_str(), lineno);
841 return 1;
842 }
843
844 fclose(f);
845 return 0;
846}
847
848// ==========================================================
849static int
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700850compile_aidl(Options& options)
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800851{
852 int err = 0, N;
853
854 set_import_paths(options.importPaths);
855
856 register_base_types();
857
858 // import the preprocessed file
859 N = options.preprocessedFiles.size();
860 for (int i=0; i<N; i++) {
861 const string& s = options.preprocessedFiles[i];
862 err |= parse_preprocessed_file(s);
863 }
864 if (err != 0) {
865 return err;
866 }
867
868 // parse the main file
869 g_callbacks = &g_mainCallbacks;
870 err = parse_aidl(options.inputFileName.c_str());
871 document_item_type* mainDoc = g_document;
872 g_document = NULL;
873
874 // parse the imports
875 g_callbacks = &g_mainCallbacks;
876 import_info* import = g_imports;
877 while (import) {
878 if (NAMES.Find(import->neededClass) == NULL) {
879 import->filename = find_import_file(import->neededClass);
880 if (!import->filename) {
881 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
882 import->from, import->statement.lineno,
883 import->neededClass);
884 err |= 1;
885 } else {
886 err |= parse_aidl(import->filename);
887 import->doc = g_document;
888 if (import->doc == NULL) {
889 err |= 1;
890 }
891 }
892 }
893 import = import->next;
894 }
895 // bail out now if parsing wasn't successful
896 if (err != 0 || mainDoc == NULL) {
897 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
898 return 1;
899 }
900
901 // complain about ones that aren't in the right files
902 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
903 import = g_imports;
904 while (import) {
905 err |= check_filenames(import->filename, import->doc);
906 import = import->next;
907 }
908
909 // gather the types that have been declared
910 err |= gather_types(options.inputFileName.c_str(), mainDoc);
911 import = g_imports;
912 while (import) {
913 err |= gather_types(import->filename, import->doc);
914 import = import->next;
915 }
916
917#if 0
918 printf("---- main doc ----\n");
919 test_document(mainDoc);
920
921 import = g_imports;
922 while (import) {
923 printf("---- import doc ----\n");
924 test_document(import->doc);
925 import = import->next;
926 }
927 NAMES.Dump();
928#endif
929
930 // check the referenced types in mainDoc to make sure we've imported them
931 err |= check_types(options.inputFileName.c_str(), mainDoc);
932
933 // finally, there really only needs to be one thing in mainDoc, and it
934 // needs to be an interface.
935 bool onlyParcelable = false;
936 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
937
938 // after this, there shouldn't be any more errors because of the
939 // input.
940 if (err != 0 || mainDoc == NULL) {
941 return 1;
942 }
943
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700944 // if needed, generate the outputFileName from the outputBaseFolder
945 if (options.outputFileName.length() == 0 &&
946 options.outputBaseFolder.length() > 0) {
947 options.outputFileName = generate_outputFileName(options, mainDoc);
948 }
949
950 // if we were asked to, generate a make dependency file
951 // unless it's a parcelable *and* it's supposed to fail on parcelable
952 if ((options.autoDepFile || options.depFileName != "") &&
953 !(onlyParcelable && options.failOnParcelable)) {
954 // make sure the folders of the output file all exists
955 check_outputFilePath(options.outputFileName);
956 generate_dep_file(options, mainDoc);
957 }
958
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800959 // they didn't ask to fail on parcelables, so just exit quietly.
960 if (onlyParcelable && !options.failOnParcelable) {
961 return 0;
962 }
963
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700964 // make sure the folders of the output file all exists
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700965 check_outputFilePath(options.outputFileName);
The Android Open Source Projectdeec6912009-03-13 13:04:22 -0700966
Xavier Ducrohete15d44a2011-08-25 11:58:17 -0700967 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
The Android Open Source Projecte42b5f52009-03-03 19:31:44 -0800968 (interface_type*)mainDoc);
969
970 return err;
971}
972
973static int
974preprocess_aidl(const Options& options)
975{
976 vector<string> lines;
977 int err;
978
979 // read files
980 int N = options.filesToPreprocess.size();
981 for (int i=0; i<N; i++) {
982 g_callbacks = &g_mainCallbacks;
983 err = parse_aidl(options.filesToPreprocess[i].c_str());
984 if (err != 0) {
985 return err;
986 }
987 document_item_type* doc = g_document;
988 string line;
989 if (doc->item_type == PARCELABLE_TYPE) {
990 line = "parcelable ";
991 parcelable_type* parcelable = (parcelable_type*)doc;
992 if (parcelable->package) {
993 line += parcelable->package;
994 line += '.';
995 }
996 line += parcelable->name.data;
Joe Onorato4135a7d2011-09-15 21:31:15 -0700997 }
998 else if (doc->item_type == FLATTENABLE_TYPE) {
999 line = "parcelable ";
1000 parcelable_type* parcelable = (parcelable_type*)doc;
1001 if (parcelable->package) {
1002 line += parcelable->package;
1003 line += '.';
1004 }
1005 line += parcelable->name.data;
The Android Open Source Projecte42b5f52009-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 Projecte42b5f52009-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}