blob: ff08b67fe234cb1a08d4bda70e2fd90c1e8b3cb6 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -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>
Andrew Hsiehc9d32392014-05-07 20:14:30 +080019#include <direct.h>
Adam Lesinski282e1812014-01-23 18:17:42 -080020#include <sys/stat.h>
21#endif
22
23#ifndef O_BINARY
24# define O_BINARY 0
25#endif
26
27// The following are gotten as the offset from the allowable id's between
28// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
29// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
30#define MIN_USER_SET_METHOD_ID 0
31#define MAX_USER_SET_METHOD_ID 16777214
32
33using namespace std;
34
35static void
36test_document(document_item_type* d)
37{
38 while (d) {
39 if (d->item_type == INTERFACE_TYPE_BINDER) {
40 interface_type* c = (interface_type*)d;
41 printf("interface %s %s {\n", c->package, c->name.data);
42 interface_item_type *q = (interface_item_type*)c->interface_items;
43 while (q) {
44 if (q->item_type == METHOD_TYPE) {
45 method_type *m = (method_type*)q;
46 printf(" %s %s(", m->type.type.data, m->name.data);
47 arg_type *p = m->args;
48 while (p) {
49 printf("%s %s",p->type.type.data,p->name.data);
50 if (p->next) printf(", ");
51 p=p->next;
52 }
53 printf(")");
54 printf(";\n");
55 }
56 q=q->next;
57 }
58 printf("}\n");
59 }
60 else if (d->item_type == USER_DATA_TYPE) {
61 user_data_type* b = (user_data_type*)d;
62 if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
63 printf("parcelable %s %s;\n", b->package, b->name.data);
64 }
65 if ((b->flattening_methods & RPC_DATA) != 0) {
66 printf("flattenable %s %s;\n", b->package, b->name.data);
67 }
68 }
69 else {
70 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
71 }
72 d = d->next;
73 }
74}
75
76// ==========================================================
77int
78convert_direction(const char* direction)
79{
80 if (direction == NULL) {
81 return IN_PARAMETER;
82 }
83 if (0 == strcmp(direction, "in")) {
84 return IN_PARAMETER;
85 }
86 if (0 == strcmp(direction, "out")) {
87 return OUT_PARAMETER;
88 }
89 return INOUT_PARAMETER;
90}
91
92// ==========================================================
93struct import_info {
94 const char* from;
95 const char* filename;
96 buffer_type statement;
97 const char* neededClass;
98 document_item_type* doc;
99 struct import_info* next;
100};
101
102document_item_type* g_document = NULL;
103import_info* g_imports = NULL;
104
105static void
106main_document_parsed(document_item_type* d)
107{
108 g_document = d;
109}
110
111static void
112main_import_parsed(buffer_type* statement)
113{
114 import_info* import = (import_info*)malloc(sizeof(import_info));
115 memset(import, 0, sizeof(import_info));
116 import->from = strdup(g_currentFilename);
117 import->statement.lineno = statement->lineno;
118 import->statement.data = strdup(statement->data);
119 import->statement.extra = NULL;
120 import->next = g_imports;
121 import->neededClass = parse_import_statement(statement->data);
122 g_imports = import;
123}
124
125static ParserCallbacks g_mainCallbacks = {
126 &main_document_parsed,
127 &main_import_parsed
128};
129
130char*
131parse_import_statement(const char* text)
132{
133 const char* end;
134 int len;
135
136 while (isspace(*text)) {
137 text++;
138 }
139 while (!isspace(*text)) {
140 text++;
141 }
142 while (isspace(*text)) {
143 text++;
144 }
145 end = text;
146 while (!isspace(*end) && *end != ';') {
147 end++;
148 }
149 len = end-text;
150
151 char* rv = (char*)malloc(len+1);
152 memcpy(rv, text, len);
153 rv[len] = '\0';
154
155 return rv;
156}
157
158// ==========================================================
159static void
160import_import_parsed(buffer_type* statement)
161{
162}
163
164static ParserCallbacks g_importCallbacks = {
165 &main_document_parsed,
166 &import_import_parsed
167};
168
169// ==========================================================
170static int
171check_filename(const char* filename, const char* package, buffer_type* name)
172{
173 const char* p;
174 string expected;
175 string fn;
176 size_t len;
177 char cwd[MAXPATHLEN];
178 bool valid = false;
179
Elliott Hughes98c11b52015-07-29 08:44:17 -0700180#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800181 if (isalpha(filename[0]) && filename[1] == ':'
182 && filename[2] == OS_PATH_SEPARATOR) {
183#else
184 if (filename[0] == OS_PATH_SEPARATOR) {
185#endif
186 fn = filename;
187 } else {
188 fn = getcwd(cwd, sizeof(cwd));
189 len = fn.length();
190 if (fn[len-1] != OS_PATH_SEPARATOR) {
191 fn += OS_PATH_SEPARATOR;
192 }
193 fn += filename;
194 }
195
196 if (package) {
197 expected = package;
198 expected += '.';
199 }
200
201 len = expected.length();
202 for (size_t i=0; i<len; i++) {
203 if (expected[i] == '.') {
204 expected[i] = OS_PATH_SEPARATOR;
205 }
206 }
207
208 p = strchr(name->data, '.');
209 len = p ? p-name->data : strlen(name->data);
210 expected.append(name->data, len);
211
212 expected += ".aidl";
213
214 len = fn.length();
215 valid = (len >= expected.length());
216
217 if (valid) {
218 p = fn.c_str() + (len - expected.length());
219
Elliott Hughes98c11b52015-07-29 08:44:17 -0700220#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800221 if (OS_PATH_SEPARATOR != '/') {
222 // Input filename under cygwin most likely has / separators
223 // whereas the expected string uses \\ separators. Adjust
224 // them accordingly.
225 for (char *c = const_cast<char *>(p); *c; ++c) {
226 if (*c == '/') *c = OS_PATH_SEPARATOR;
227 }
228 }
229#endif
230
Yabin Cuifb8e2b12014-11-10 15:01:43 -0800231 // aidl assumes case-insensitivity on Mac Os and Windows.
232#if defined(__linux__)
Adam Lesinski282e1812014-01-23 18:17:42 -0800233 valid = (expected == p);
234#else
235 valid = !strcasecmp(expected.c_str(), p);
236#endif
237 }
238
239 if (!valid) {
240 fprintf(stderr, "%s:%d interface %s should be declared in a file"
241 " called %s.\n",
242 filename, name->lineno, name->data, expected.c_str());
243 return 1;
244 }
245
246 return 0;
247}
248
249static int
250check_filenames(const char* filename, document_item_type* items)
251{
252 int err = 0;
253 while (items) {
254 if (items->item_type == USER_DATA_TYPE) {
255 user_data_type* p = (user_data_type*)items;
256 err |= check_filename(filename, p->package, &p->name);
257 }
258 else if (items->item_type == INTERFACE_TYPE_BINDER
259 || items->item_type == INTERFACE_TYPE_RPC) {
260 interface_type* c = (interface_type*)items;
261 err |= check_filename(filename, c->package, &c->name);
262 }
263 else {
264 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
265 items->item_type);
266 return 1;
267 }
268 items = items->next;
269 }
270 return err;
271}
272
273// ==========================================================
274static const char*
275kind_to_string(int kind)
276{
277 switch (kind)
278 {
279 case Type::INTERFACE:
280 return "an interface";
281 case Type::USERDATA:
282 return "a user data";
283 default:
284 return "ERROR";
285 }
286}
287
288static char*
289rfind(char* str, char c)
290{
291 char* p = str + strlen(str) - 1;
292 while (p >= str) {
293 if (*p == c) {
294 return p;
295 }
296 p--;
297 }
298 return NULL;
299}
300
301static int
302gather_types(const char* filename, document_item_type* items)
303{
304 int err = 0;
305 while (items) {
306 Type* type;
307 if (items->item_type == USER_DATA_TYPE) {
308 user_data_type* p = (user_data_type*)items;
309 type = new UserDataType(p->package ? p->package : "", p->name.data,
310 false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
311 ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
312 }
313 else if (items->item_type == INTERFACE_TYPE_BINDER
314 || items->item_type == INTERFACE_TYPE_RPC) {
315 interface_type* c = (interface_type*)items;
316 type = new InterfaceType(c->package ? c->package : "",
317 c->name.data, false, c->oneway,
318 filename, c->name.lineno);
319 }
320 else {
321 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
322 return 1;
323 }
324
325 Type* old = NAMES.Find(type->QualifiedName());
326 if (old == NULL) {
327 NAMES.Add(type);
328
329 if (items->item_type == INTERFACE_TYPE_BINDER) {
330 // for interfaces, also add the stub and proxy types, we don't
331 // bother checking these for duplicates, because the parser
332 // won't let us do it.
333 interface_type* c = (interface_type*)items;
334
335 string name = c->name.data;
336 name += ".Stub";
337 Type* stub = new Type(c->package ? c->package : "",
338 name, Type::GENERATED, false, false, false,
339 filename, c->name.lineno);
340 NAMES.Add(stub);
341
342 name = c->name.data;
343 name += ".Stub.Proxy";
344 Type* proxy = new Type(c->package ? c->package : "",
345 name, Type::GENERATED, false, false, false,
346 filename, c->name.lineno);
347 NAMES.Add(proxy);
348 }
349 else if (items->item_type == INTERFACE_TYPE_RPC) {
350 // for interfaces, also add the service base type, we don't
351 // bother checking these for duplicates, because the parser
352 // won't let us do it.
353 interface_type* c = (interface_type*)items;
354
355 string name = c->name.data;
356 name += ".ServiceBase";
357 Type* base = new Type(c->package ? c->package : "",
358 name, Type::GENERATED, false, false, false,
359 filename, c->name.lineno);
360 NAMES.Add(base);
361 }
362 } else {
363 if (old->Kind() == Type::BUILT_IN) {
364 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
365 filename, type->DeclLine(),
366 type->QualifiedName().c_str());
367 err = 1;
368 }
369 else if (type->Kind() != old->Kind()) {
370 const char* oldKind = kind_to_string(old->Kind());
371 const char* newKind = kind_to_string(type->Kind());
372
373 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
374 filename, type->DeclLine(),
375 type->QualifiedName().c_str(), newKind);
376 fprintf(stderr, "%s:%d previously defined here as %s.\n",
377 old->DeclFile().c_str(), old->DeclLine(), oldKind);
378 err = 1;
379 }
380 }
381
382 items = items->next;
383 }
384 return err;
385}
386
387// ==========================================================
388static bool
389matches_keyword(const char* str)
390{
391 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
392 "byte", "case", "catch", "char", "class", "const", "continue",
393 "default", "do", "double", "else", "enum", "extends", "final",
394 "finally", "float", "for", "goto", "if", "implements", "import",
395 "instanceof", "int", "interface", "long", "native", "new", "package",
396 "private", "protected", "public", "return", "short", "static",
397 "strictfp", "super", "switch", "synchronized", "this", "throw",
398 "throws", "transient", "try", "void", "volatile", "while",
399 "true", "false", "null",
400 NULL
401 };
402 const char** k = KEYWORDS;
403 while (*k) {
404 if (0 == strcmp(str, *k)) {
405 return true;
406 }
407 k++;
408 }
409 return false;
410}
411
412static int
413check_method(const char* filename, int kind, method_type* m)
414{
415 int err = 0;
416
417 // return type
418 Type* returnType = NAMES.Search(m->type.type.data);
419 if (returnType == NULL) {
420 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
421 m->type.type.lineno, m->type.type.data);
422 err = 1;
423 return err;
424 }
425
426 if (returnType == EVENT_FAKE_TYPE) {
427 if (kind != INTERFACE_TYPE_RPC) {
428 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
429 filename, m->type.type.lineno);
430 err = 1;
431 }
432 } else {
433 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
434 : returnType->CanWriteToRpcData())) {
435 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
436 m->type.type.lineno, m->type.type.data);
437 err = 1;
438 }
439 }
440
441 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
442 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
443 m->type.array_token.lineno, m->type.type.data,
444 m->type.array_token.data);
445 err = 1;
446 }
447
448 if (m->type.dimension > 1) {
449 fprintf(stderr, "%s:%d return type %s%s only one"
450 " dimensional arrays are supported\n", filename,
451 m->type.array_token.lineno, m->type.type.data,
452 m->type.array_token.data);
453 err = 1;
454 }
455
456 int index = 1;
457
458 arg_type* arg = m->args;
459 while (arg) {
460 Type* t = NAMES.Search(arg->type.type.data);
461
462 // check the arg type
463 if (t == NULL) {
464 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
465 filename, m->type.type.lineno, arg->name.data, index,
466 arg->type.type.data);
467 err = 1;
468 goto next;
469 }
470
471 if (t == EVENT_FAKE_TYPE) {
472 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
473 filename, m->type.type.lineno, arg->name.data, index,
474 arg->type.type.data);
475 err = 1;
476 goto next;
477 }
478
479 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
480 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
481 filename, m->type.type.lineno, index,
482 arg->type.type.data, arg->name.data);
483 err = 1;
484 }
485
486 if (returnType == EVENT_FAKE_TYPE
487 && convert_direction(arg->direction.data) != IN_PARAMETER) {
488 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
489 filename, m->type.type.lineno, index,
490 arg->type.type.data, arg->name.data);
491 err = 1;
492 goto next;
493 }
494
495 if (arg->direction.data == NULL
496 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
497 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
498 " parameter, so you must declare it as in,"
499 " out or inout.\n",
500 filename, m->type.type.lineno, index,
501 arg->type.type.data, arg->name.data);
502 err = 1;
503 }
504
505 if (convert_direction(arg->direction.data) != IN_PARAMETER
506 && !t->CanBeOutParameter()
507 && arg->type.dimension == 0) {
508 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
509 " parameter.\n",
510 filename, m->type.type.lineno, index,
511 arg->direction.data, arg->type.type.data,
512 arg->name.data);
513 err = 1;
514 }
515
516 if (arg->type.dimension > 0 && !t->CanBeArray()) {
517 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
518 " array.\n", filename,
519 m->type.array_token.lineno, index, arg->direction.data,
520 arg->type.type.data, arg->type.array_token.data,
521 arg->name.data);
522 err = 1;
523 }
524
525 if (arg->type.dimension > 1) {
526 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
527 " dimensional arrays are supported\n", filename,
528 m->type.array_token.lineno, index, arg->direction.data,
529 arg->type.type.data, arg->type.array_token.data,
530 arg->name.data);
531 err = 1;
532 }
533
534 // check that the name doesn't match a keyword
535 if (matches_keyword(arg->name.data)) {
536 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
537 " Java or aidl keyword\n",
538 filename, m->name.lineno, index, arg->name.data);
539 err = 1;
540 }
541
542next:
543 index++;
544 arg = arg->next;
545 }
546
547 return err;
548}
549
550static int
551check_types(const char* filename, document_item_type* items)
552{
553 int err = 0;
554 while (items) {
555 // (nothing to check for USER_DATA_TYPE)
556 if (items->item_type == INTERFACE_TYPE_BINDER
557 || items->item_type == INTERFACE_TYPE_RPC) {
558 map<string,method_type*> methodNames;
559 interface_type* c = (interface_type*)items;
560
561 interface_item_type* member = c->interface_items;
562 while (member) {
563 if (member->item_type == METHOD_TYPE) {
564 method_type* m = (method_type*)member;
565
566 err |= check_method(filename, items->item_type, m);
567
568 // prevent duplicate methods
569 if (methodNames.find(m->name.data) == methodNames.end()) {
570 methodNames[m->name.data] = m;
571 } else {
572 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
573 filename, m->name.lineno, m->name.data);
574 method_type* old = methodNames[m->name.data];
575 fprintf(stderr, "%s:%d previously defined here.\n",
576 filename, old->name.lineno);
577 err = 1;
578 }
579 }
580 member = member->next;
581 }
582 }
583
584 items = items->next;
585 }
586 return err;
587}
588
589// ==========================================================
590static int
591exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
592 bool* onlyParcelable)
593{
594 if (items == NULL) {
595 fprintf(stderr, "%s: file does not contain any interfaces\n",
596 filename);
597 return 1;
598 }
599
600 const document_item_type* next = items->next;
601 // Allow parcelables to skip the "one-only" rule.
602 if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
603 int lineno = -1;
604 if (next->item_type == INTERFACE_TYPE_BINDER) {
605 lineno = ((interface_type*)next)->interface_token.lineno;
606 }
607 else if (next->item_type == INTERFACE_TYPE_RPC) {
608 lineno = ((interface_type*)next)->interface_token.lineno;
609 }
610 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
611 filename, lineno);
612 return 1;
613 }
614
615 if (items->item_type == USER_DATA_TYPE) {
616 *onlyParcelable = true;
617 if (options.failOnParcelable) {
618 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
619 " parcelables or flattenables,\n", filename,
620 ((user_data_type*)items)->keyword_token.lineno);
621 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
622 "may not go in the Makefile.\n", filename,
623 ((user_data_type*)items)->keyword_token.lineno);
624 return 1;
625 }
626 } else {
627 *onlyParcelable = false;
628 }
629
630 return 0;
631}
632
633// ==========================================================
634void
635generate_dep_file(const Options& options, const document_item_type* items)
636{
637 /* we open the file in binary mode to ensure that the same output is
638 * generated on all platforms !!
639 */
640 FILE* to = NULL;
641 if (options.autoDepFile) {
642 string fileName = options.outputFileName + ".d";
643 to = fopen(fileName.c_str(), "wb");
644 } else {
645 to = fopen(options.depFileName.c_str(), "wb");
646 }
647
648 if (to == NULL) {
649 return;
650 }
651
652 const char* slash = "\\";
653 import_info* import = g_imports;
654 if (import == NULL) {
655 slash = "";
656 }
657
658 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
659 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
660 } else {
661 // parcelable: there's no output file.
662 fprintf(to, " : \\\n");
663 }
664 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
665
666 while (import) {
667 if (import->next == NULL) {
668 slash = "";
669 }
670 if (import->filename) {
671 fprintf(to, " %s %s\n", import->filename, slash);
672 }
673 import = import->next;
674 }
675
676 fprintf(to, "\n");
677
Ying Wang50fb02d2015-07-22 17:42:35 -0700678 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
679 // has been deleted, moved or renamed in incremental build.
680 fprintf(to, "%s :\n", options.inputFileName.c_str());
681
Adam Lesinski282e1812014-01-23 18:17:42 -0800682 // Output "<imported_file>: " so make won't fail if the imported file has
683 // been deleted, moved or renamed in incremental build.
684 import = g_imports;
685 while (import) {
686 if (import->filename) {
687 fprintf(to, "%s :\n", import->filename);
688 }
689 import = import->next;
690 }
691
692 fclose(to);
693}
694
695// ==========================================================
696static string
697generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
698{
699 string result;
700
701 // create the path to the destination folder based on the
702 // interface package name
703 result = options.outputBaseFolder;
704 result += OS_PATH_SEPARATOR;
705
706 string packageStr = package;
707 size_t len = packageStr.length();
708 for (size_t i=0; i<len; i++) {
709 if (packageStr[i] == '.') {
710 packageStr[i] = OS_PATH_SEPARATOR;
711 }
712 }
713
714 result += packageStr;
715
716 // add the filename by replacing the .aidl extension to .java
717 const char* p = strchr(name.data, '.');
718 len = p ? p-name.data : strlen(name.data);
719
720 result += OS_PATH_SEPARATOR;
721 result.append(name.data, len);
722 result += ".java";
723
724 return result;
725}
726
727// ==========================================================
728static string
729generate_outputFileName(const Options& options, const document_item_type* items)
730{
731 // items has already been checked to have only one interface.
732 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
733 interface_type* type = (interface_type*)items;
734
735 return generate_outputFileName2(options, type->name, type->package);
736 } else if (items->item_type == USER_DATA_TYPE) {
737 user_data_type* type = (user_data_type*)items;
738 return generate_outputFileName2(options, type->name, type->package);
739 }
740
741 // I don't think we can come here, but safer than returning NULL.
742 string result;
743 return result;
744}
745
746
747
748// ==========================================================
749static void
750check_outputFilePath(const string& path) {
751 size_t len = path.length();
752 for (size_t i=0; i<len ; i++) {
753 if (path[i] == OS_PATH_SEPARATOR) {
754 string p = path.substr(0, i);
755 if (access(path.data(), F_OK) != 0) {
756#ifdef HAVE_MS_C_RUNTIME
757 _mkdir(p.data());
758#else
759 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
760#endif
761 }
762 }
763 }
764}
765
766
767// ==========================================================
768static int
769parse_preprocessed_file(const string& filename)
770{
771 int err;
772
773 FILE* f = fopen(filename.c_str(), "rb");
774 if (f == NULL) {
775 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
776 filename.c_str());
777 return 1;
778 }
779
780 int lineno = 1;
781 char line[1024];
782 char type[1024];
783 char fullname[1024];
784 while (fgets(line, sizeof(line), f)) {
785 // skip comments and empty lines
786 if (!line[0] || strncmp(line, "//", 2) == 0) {
787 continue;
788 }
789
790 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
791
792 char* packagename;
793 char* classname = rfind(fullname, '.');
794 if (classname != NULL) {
795 *classname = '\0';
796 classname++;
797 packagename = fullname;
798 } else {
799 classname = fullname;
800 packagename = NULL;
801 }
802
803 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
804 // type, packagename, classname);
805 document_item_type* doc;
806
807 if (0 == strcmp("parcelable", type)) {
808 user_data_type* parcl = (user_data_type*)malloc(
809 sizeof(user_data_type));
810 memset(parcl, 0, sizeof(user_data_type));
811 parcl->document_item.item_type = USER_DATA_TYPE;
812 parcl->keyword_token.lineno = lineno;
813 parcl->keyword_token.data = strdup(type);
814 parcl->package = packagename ? strdup(packagename) : NULL;
815 parcl->name.lineno = lineno;
816 parcl->name.data = strdup(classname);
817 parcl->semicolon_token.lineno = lineno;
818 parcl->semicolon_token.data = strdup(";");
819 parcl->flattening_methods = PARCELABLE_DATA;
820 doc = (document_item_type*)parcl;
821 }
822 else if (0 == strcmp("flattenable", type)) {
823 user_data_type* parcl = (user_data_type*)malloc(
824 sizeof(user_data_type));
825 memset(parcl, 0, sizeof(user_data_type));
826 parcl->document_item.item_type = USER_DATA_TYPE;
827 parcl->keyword_token.lineno = lineno;
828 parcl->keyword_token.data = strdup(type);
829 parcl->package = packagename ? strdup(packagename) : NULL;
830 parcl->name.lineno = lineno;
831 parcl->name.data = strdup(classname);
832 parcl->semicolon_token.lineno = lineno;
833 parcl->semicolon_token.data = strdup(";");
834 parcl->flattening_methods = RPC_DATA;
835 doc = (document_item_type*)parcl;
836 }
837 else if (0 == strcmp("interface", type)) {
838 interface_type* iface = (interface_type*)malloc(
839 sizeof(interface_type));
840 memset(iface, 0, sizeof(interface_type));
841 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
842 iface->interface_token.lineno = lineno;
843 iface->interface_token.data = strdup(type);
844 iface->package = packagename ? strdup(packagename) : NULL;
845 iface->name.lineno = lineno;
846 iface->name.data = strdup(classname);
847 iface->open_brace_token.lineno = lineno;
848 iface->open_brace_token.data = strdup("{");
849 iface->close_brace_token.lineno = lineno;
850 iface->close_brace_token.data = strdup("}");
851 doc = (document_item_type*)iface;
852 }
853 else {
854 fprintf(stderr, "%s:%d: bad type in line: %s\n",
855 filename.c_str(), lineno, line);
Elliott Hughesb30296b2013-10-29 15:25:52 -0700856 fclose(f);
Adam Lesinski282e1812014-01-23 18:17:42 -0800857 return 1;
858 }
859 err = gather_types(filename.c_str(), doc);
860 lineno++;
861 }
862
863 if (!feof(f)) {
864 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
865 filename.c_str(), lineno);
866 return 1;
867 }
868
869 fclose(f);
870 return 0;
871}
872
873static int
874check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
875{
876 // Check whether there are any methods with manually assigned id's and any that are not.
877 // Either all method id's must be manually assigned or all of them must not.
878 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
879 set<int> usedIds;
880 interface_item_type* item = first_item;
881 bool hasUnassignedIds = false;
882 bool hasAssignedIds = false;
883 while (item != NULL) {
884 if (item->item_type == METHOD_TYPE) {
885 method_type* method_item = (method_type*)item;
886 if (method_item->hasId) {
887 hasAssignedIds = true;
888 method_item->assigned_id = atoi(method_item->id.data);
889 // Ensure that the user set id is not duplicated.
890 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
891 // We found a duplicate id, so throw an error.
892 fprintf(stderr,
893 "%s:%d Found duplicate method id (%d) for method: %s\n",
894 filename, method_item->id.lineno,
895 method_item->assigned_id, method_item->name.data);
896 return 1;
897 }
898 // Ensure that the user set id is within the appropriate limits
899 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
900 method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
901 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
902 filename, method_item->id.lineno,
903 method_item->assigned_id, method_item->name.data);
904 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
905 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
906 return 1;
907 }
908 usedIds.insert(method_item->assigned_id);
909 } else {
910 hasUnassignedIds = true;
911 }
912 if (hasAssignedIds && hasUnassignedIds) {
913 fprintf(stderr,
914 "%s: You must either assign id's to all methods or to none of them.\n",
915 filename);
916 return 1;
917 }
918 }
919 item = item->next;
920 }
921
922 // In the case that all methods have unassigned id's, set a unique id for them.
923 if (hasUnassignedIds) {
924 int newId = 0;
925 item = first_item;
926 while (item != NULL) {
927 if (item->item_type == METHOD_TYPE) {
928 method_type* method_item = (method_type*)item;
929 method_item->assigned_id = newId++;
930 }
931 item = item->next;
932 }
933 }
934
935 // success
936 return 0;
937}
938
939// ==========================================================
940static int
941compile_aidl(Options& options)
942{
943 int err = 0, N;
944
945 set_import_paths(options.importPaths);
946
947 register_base_types();
948
949 // import the preprocessed file
950 N = options.preprocessedFiles.size();
951 for (int i=0; i<N; i++) {
952 const string& s = options.preprocessedFiles[i];
953 err |= parse_preprocessed_file(s);
954 }
955 if (err != 0) {
956 return err;
957 }
958
959 // parse the main file
960 g_callbacks = &g_mainCallbacks;
961 err = parse_aidl(options.inputFileName.c_str());
962 document_item_type* mainDoc = g_document;
963 g_document = NULL;
964
965 // parse the imports
966 g_callbacks = &g_mainCallbacks;
967 import_info* import = g_imports;
968 while (import) {
969 if (NAMES.Find(import->neededClass) == NULL) {
970 import->filename = find_import_file(import->neededClass);
971 if (!import->filename) {
972 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
973 import->from, import->statement.lineno,
974 import->neededClass);
975 err |= 1;
976 } else {
977 err |= parse_aidl(import->filename);
978 import->doc = g_document;
979 if (import->doc == NULL) {
980 err |= 1;
981 }
982 }
983 }
984 import = import->next;
985 }
986 // bail out now if parsing wasn't successful
987 if (err != 0 || mainDoc == NULL) {
988 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
989 return 1;
990 }
991
992 // complain about ones that aren't in the right files
993 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
994 import = g_imports;
995 while (import) {
996 err |= check_filenames(import->filename, import->doc);
997 import = import->next;
998 }
999
1000 // gather the types that have been declared
1001 err |= gather_types(options.inputFileName.c_str(), mainDoc);
1002 import = g_imports;
1003 while (import) {
1004 err |= gather_types(import->filename, import->doc);
1005 import = import->next;
1006 }
1007
1008#if 0
1009 printf("---- main doc ----\n");
1010 test_document(mainDoc);
1011
1012 import = g_imports;
1013 while (import) {
1014 printf("---- import doc ----\n");
1015 test_document(import->doc);
1016 import = import->next;
1017 }
1018 NAMES.Dump();
1019#endif
1020
1021 // check the referenced types in mainDoc to make sure we've imported them
1022 err |= check_types(options.inputFileName.c_str(), mainDoc);
1023
1024 // finally, there really only needs to be one thing in mainDoc, and it
1025 // needs to be an interface.
1026 bool onlyParcelable = false;
1027 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
1028
1029 // If this includes an interface definition, then assign method ids and validate.
1030 if (!onlyParcelable) {
1031 err |= check_and_assign_method_ids(options.inputFileName.c_str(),
1032 ((interface_type*)mainDoc)->interface_items);
1033 }
1034
1035 // after this, there shouldn't be any more errors because of the
1036 // input.
1037 if (err != 0 || mainDoc == NULL) {
1038 return 1;
1039 }
1040
1041 // if needed, generate the outputFileName from the outputBaseFolder
1042 if (options.outputFileName.length() == 0 &&
1043 options.outputBaseFolder.length() > 0) {
1044 options.outputFileName = generate_outputFileName(options, mainDoc);
1045 }
1046
1047 // if we were asked to, generate a make dependency file
1048 // unless it's a parcelable *and* it's supposed to fail on parcelable
1049 if ((options.autoDepFile || options.depFileName != "") &&
1050 !(onlyParcelable && options.failOnParcelable)) {
1051 // make sure the folders of the output file all exists
1052 check_outputFilePath(options.outputFileName);
1053 generate_dep_file(options, mainDoc);
1054 }
1055
1056 // they didn't ask to fail on parcelables, so just exit quietly.
1057 if (onlyParcelable && !options.failOnParcelable) {
1058 return 0;
1059 }
1060
1061 // make sure the folders of the output file all exists
1062 check_outputFilePath(options.outputFileName);
1063
1064 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1065 (interface_type*)mainDoc);
1066
1067 return err;
1068}
1069
1070static int
1071preprocess_aidl(const Options& options)
1072{
1073 vector<string> lines;
1074 int err;
1075
1076 // read files
1077 int N = options.filesToPreprocess.size();
1078 for (int i=0; i<N; i++) {
1079 g_callbacks = &g_mainCallbacks;
1080 err = parse_aidl(options.filesToPreprocess[i].c_str());
1081 if (err != 0) {
1082 return err;
1083 }
1084 document_item_type* doc = g_document;
1085 string line;
1086 if (doc->item_type == USER_DATA_TYPE) {
1087 user_data_type* parcelable = (user_data_type*)doc;
1088 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
1089 line = "parcelable ";
1090 }
1091 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1092 line = "flattenable ";
1093 }
1094 if (parcelable->package) {
1095 line += parcelable->package;
1096 line += '.';
1097 }
1098 line += parcelable->name.data;
1099 } else {
1100 line = "interface ";
1101 interface_type* iface = (interface_type*)doc;
1102 if (iface->package) {
1103 line += iface->package;
1104 line += '.';
1105 }
1106 line += iface->name.data;
1107 }
1108 line += ";\n";
1109 lines.push_back(line);
1110 }
1111
1112 // write preprocessed file
1113 int fd = open( options.outputFileName.c_str(),
1114 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1115#ifdef HAVE_MS_C_RUNTIME
1116 _S_IREAD|_S_IWRITE);
1117#else
1118 S_IRUSR|S_IWUSR|S_IRGRP);
1119#endif
1120 if (fd == -1) {
1121 fprintf(stderr, "aidl: could not open file for write: %s\n",
1122 options.outputFileName.c_str());
1123 return 1;
1124 }
1125
1126 N = lines.size();
1127 for (int i=0; i<N; i++) {
1128 const string& s = lines[i];
1129 int len = s.length();
1130 if (len != write(fd, s.c_str(), len)) {
1131 fprintf(stderr, "aidl: error writing to file %s\n",
1132 options.outputFileName.c_str());
1133 close(fd);
1134 unlink(options.outputFileName.c_str());
1135 return 1;
1136 }
1137 }
1138
1139 close(fd);
1140 return 0;
1141}
1142
1143// ==========================================================
1144int
1145main(int argc, const char **argv)
1146{
1147 Options options;
1148 int result = parse_options(argc, argv, &options);
1149 if (result) {
1150 return result;
1151 }
1152
1153 switch (options.task)
1154 {
1155 case COMPILE_AIDL:
1156 return compile_aidl(options);
1157 case PREPROCESS_AIDL:
1158 return preprocess_aidl(options);
1159 }
1160 fprintf(stderr, "aidl: internal error\n");
1161 return 1;
1162}