2 #include "aidl_language.h"
4 #include "search_path.h"
6 #include "generate_java.h"
17 #ifdef HAVE_MS_C_RUNTIME
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
36 test_document(document_item_type* 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;
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;
49 printf("%s %s",p->type.type.data,p->name.data);
50 if (p->next) printf(", ");
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);
65 if ((b->flattening_methods & RPC_DATA) != 0) {
66 printf("flattenable %s %s;\n", b->package, b->name.data);
70 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
76 // ==========================================================
78 convert_direction(const char* direction)
80 if (direction == NULL) {
83 if (0 == strcmp(direction, "in")) {
86 if (0 == strcmp(direction, "out")) {
89 return INOUT_PARAMETER;
92 // ==========================================================
96 buffer_type statement;
97 const char* neededClass;
98 document_item_type* doc;
99 struct import_info* next;
102 document_item_type* g_document = NULL;
103 import_info* g_imports = NULL;
106 main_document_parsed(document_item_type* d)
112 main_import_parsed(buffer_type* statement)
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);
125 static ParserCallbacks g_mainCallbacks = {
126 &main_document_parsed,
131 parse_import_statement(const char* text)
136 while (isspace(*text)) {
139 while (!isspace(*text)) {
142 while (isspace(*text)) {
146 while (!isspace(*end) && *end != ';') {
151 char* rv = (char*)malloc(len+1);
152 memcpy(rv, text, len);
158 // ==========================================================
160 import_import_parsed(buffer_type* statement)
164 static ParserCallbacks g_importCallbacks = {
165 &main_document_parsed,
166 &import_import_parsed
169 // ==========================================================
171 check_filename(const char* filename, const char* package, buffer_type* name)
177 char cwd[MAXPATHLEN];
180 #ifdef HAVE_WINDOWS_PATHS
181 if (isalpha(filename[0]) && filename[1] == ':'
182 && filename[2] == OS_PATH_SEPARATOR) {
184 if (filename[0] == OS_PATH_SEPARATOR) {
188 fn = getcwd(cwd, sizeof(cwd));
190 if (fn[len-1] != OS_PATH_SEPARATOR) {
191 fn += OS_PATH_SEPARATOR;
201 len = expected.length();
202 for (size_t i=0; i<len; i++) {
203 if (expected[i] == '.') {
204 expected[i] = OS_PATH_SEPARATOR;
208 p = strchr(name->data, '.');
209 len = p ? p-name->data : strlen(name->data);
210 expected.append(name->data, len);
215 valid = (len >= expected.length());
218 p = fn.c_str() + (len - expected.length());
220 #ifdef HAVE_WINDOWS_PATHS
221 if (OS_PATH_SEPARATOR != '/') {
222 // Input filename under cygwin most likely has / separators
223 // whereas the expected string uses \\ separators. Adjust
225 for (char *c = const_cast<char *>(p); *c; ++c) {
226 if (*c == '/') *c = OS_PATH_SEPARATOR;
231 // aidl assumes case-insensitivity on Mac Os and Windows.
232 #if defined(__linux__)
233 valid = (expected == p);
235 valid = !strcasecmp(expected.c_str(), p);
240 fprintf(stderr, "%s:%d interface %s should be declared in a file"
242 filename, name->lineno, name->data, expected.c_str());
250 check_filenames(const char* filename, document_item_type* 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);
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);
264 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
273 // ==========================================================
275 kind_to_string(int kind)
279 case Type::INTERFACE:
280 return "an interface";
282 return "a user data";
289 rfind(char* str, char c)
291 char* p = str + strlen(str) - 1;
302 gather_types(const char* filename, document_item_type* items)
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);
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);
321 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
325 Type* old = NAMES.Find(type->QualifiedName());
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;
335 string name = c->name.data;
337 Type* stub = new Type(c->package ? c->package : "",
338 name, Type::GENERATED, false, false, false,
339 filename, c->name.lineno);
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);
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;
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);
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());
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());
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);
387 // ==========================================================
389 matches_keyword(const char* str)
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",
402 const char** k = KEYWORDS;
404 if (0 == strcmp(str, *k)) {
413 check_method(const char* filename, int kind, method_type* m)
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);
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);
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);
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);
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);
458 arg_type* arg = m->args;
460 Type* t = NAMES.Search(arg->type.type.data);
462 // check the arg type
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);
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);
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);
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);
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,"
500 filename, m->type.type.lineno, index,
501 arg->type.type.data, arg->name.data);
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"
510 filename, m->type.type.lineno, index,
511 arg->direction.data, arg->type.type.data,
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,
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,
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);
551 check_types(const char* filename, document_item_type* 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;
561 interface_item_type* member = c->interface_items;
563 if (member->item_type == METHOD_TYPE) {
564 method_type* m = (method_type*)member;
566 err |= check_method(filename, items->item_type, m);
568 // prevent duplicate methods
569 if (methodNames.find(m->name.data) == methodNames.end()) {
570 methodNames[m->name.data] = m;
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);
580 member = member->next;
589 // ==========================================================
591 exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
592 bool* onlyParcelable)
595 fprintf(stderr, "%s: file does not contain any interfaces\n",
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) {
604 if (next->item_type == INTERFACE_TYPE_BINDER) {
605 lineno = ((interface_type*)next)->interface_token.lineno;
607 else if (next->item_type == INTERFACE_TYPE_RPC) {
608 lineno = ((interface_type*)next)->interface_token.lineno;
610 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
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);
627 *onlyParcelable = false;
633 // ==========================================================
635 generate_dep_file(const Options& options, const document_item_type* items)
637 /* we open the file in binary mode to ensure that the same output is
638 * generated on all platforms !!
641 if (options.autoDepFile) {
642 string fileName = options.outputFileName + ".d";
643 to = fopen(fileName.c_str(), "wb");
645 to = fopen(options.depFileName.c_str(), "wb");
652 const char* slash = "\\";
653 import_info* import = g_imports;
654 if (import == NULL) {
658 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
659 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
661 // parcelable: there's no output file.
662 fprintf(to, " : \\\n");
664 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
667 if (import->next == NULL) {
670 if (import->filename) {
671 fprintf(to, " %s %s\n", import->filename, slash);
673 import = import->next;
678 // Output "<imported_file>: " so make won't fail if the imported file has
679 // been deleted, moved or renamed in incremental build.
682 if (import->filename) {
683 fprintf(to, "%s :\n", import->filename);
685 import = import->next;
691 // ==========================================================
693 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
697 // create the path to the destination folder based on the
698 // interface package name
699 result = options.outputBaseFolder;
700 result += OS_PATH_SEPARATOR;
702 string packageStr = package;
703 size_t len = packageStr.length();
704 for (size_t i=0; i<len; i++) {
705 if (packageStr[i] == '.') {
706 packageStr[i] = OS_PATH_SEPARATOR;
710 result += packageStr;
712 // add the filename by replacing the .aidl extension to .java
713 const char* p = strchr(name.data, '.');
714 len = p ? p-name.data : strlen(name.data);
716 result += OS_PATH_SEPARATOR;
717 result.append(name.data, len);
723 // ==========================================================
725 generate_outputFileName(const Options& options, const document_item_type* items)
727 // items has already been checked to have only one interface.
728 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
729 interface_type* type = (interface_type*)items;
731 return generate_outputFileName2(options, type->name, type->package);
732 } else if (items->item_type == USER_DATA_TYPE) {
733 user_data_type* type = (user_data_type*)items;
734 return generate_outputFileName2(options, type->name, type->package);
737 // I don't think we can come here, but safer than returning NULL.
744 // ==========================================================
746 check_outputFilePath(const string& path) {
747 size_t len = path.length();
748 for (size_t i=0; i<len ; i++) {
749 if (path[i] == OS_PATH_SEPARATOR) {
750 string p = path.substr(0, i);
751 if (access(path.data(), F_OK) != 0) {
752 #ifdef HAVE_MS_C_RUNTIME
755 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
763 // ==========================================================
765 parse_preprocessed_file(const string& filename)
769 FILE* f = fopen(filename.c_str(), "rb");
771 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
780 while (fgets(line, sizeof(line), f)) {
781 // skip comments and empty lines
782 if (!line[0] || strncmp(line, "//", 2) == 0) {
786 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
789 char* classname = rfind(fullname, '.');
790 if (classname != NULL) {
793 packagename = fullname;
795 classname = fullname;
799 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
800 // type, packagename, classname);
801 document_item_type* doc;
803 if (0 == strcmp("parcelable", type)) {
804 user_data_type* parcl = (user_data_type*)malloc(
805 sizeof(user_data_type));
806 memset(parcl, 0, sizeof(user_data_type));
807 parcl->document_item.item_type = USER_DATA_TYPE;
808 parcl->keyword_token.lineno = lineno;
809 parcl->keyword_token.data = strdup(type);
810 parcl->package = packagename ? strdup(packagename) : NULL;
811 parcl->name.lineno = lineno;
812 parcl->name.data = strdup(classname);
813 parcl->semicolon_token.lineno = lineno;
814 parcl->semicolon_token.data = strdup(";");
815 parcl->flattening_methods = PARCELABLE_DATA;
816 doc = (document_item_type*)parcl;
818 else if (0 == strcmp("flattenable", type)) {
819 user_data_type* parcl = (user_data_type*)malloc(
820 sizeof(user_data_type));
821 memset(parcl, 0, sizeof(user_data_type));
822 parcl->document_item.item_type = USER_DATA_TYPE;
823 parcl->keyword_token.lineno = lineno;
824 parcl->keyword_token.data = strdup(type);
825 parcl->package = packagename ? strdup(packagename) : NULL;
826 parcl->name.lineno = lineno;
827 parcl->name.data = strdup(classname);
828 parcl->semicolon_token.lineno = lineno;
829 parcl->semicolon_token.data = strdup(";");
830 parcl->flattening_methods = RPC_DATA;
831 doc = (document_item_type*)parcl;
833 else if (0 == strcmp("interface", type)) {
834 interface_type* iface = (interface_type*)malloc(
835 sizeof(interface_type));
836 memset(iface, 0, sizeof(interface_type));
837 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
838 iface->interface_token.lineno = lineno;
839 iface->interface_token.data = strdup(type);
840 iface->package = packagename ? strdup(packagename) : NULL;
841 iface->name.lineno = lineno;
842 iface->name.data = strdup(classname);
843 iface->open_brace_token.lineno = lineno;
844 iface->open_brace_token.data = strdup("{");
845 iface->close_brace_token.lineno = lineno;
846 iface->close_brace_token.data = strdup("}");
847 doc = (document_item_type*)iface;
850 fprintf(stderr, "%s:%d: bad type in line: %s\n",
851 filename.c_str(), lineno, line);
855 err = gather_types(filename.c_str(), doc);
860 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
861 filename.c_str(), lineno);
870 check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
872 // Check whether there are any methods with manually assigned id's and any that are not.
873 // Either all method id's must be manually assigned or all of them must not.
874 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
876 interface_item_type* item = first_item;
877 bool hasUnassignedIds = false;
878 bool hasAssignedIds = false;
879 while (item != NULL) {
880 if (item->item_type == METHOD_TYPE) {
881 method_type* method_item = (method_type*)item;
882 if (method_item->hasId) {
883 hasAssignedIds = true;
884 method_item->assigned_id = atoi(method_item->id.data);
885 // Ensure that the user set id is not duplicated.
886 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
887 // We found a duplicate id, so throw an error.
889 "%s:%d Found duplicate method id (%d) for method: %s\n",
890 filename, method_item->id.lineno,
891 method_item->assigned_id, method_item->name.data);
894 // Ensure that the user set id is within the appropriate limits
895 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
896 method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
897 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
898 filename, method_item->id.lineno,
899 method_item->assigned_id, method_item->name.data);
900 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
901 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
904 usedIds.insert(method_item->assigned_id);
906 hasUnassignedIds = true;
908 if (hasAssignedIds && hasUnassignedIds) {
910 "%s: You must either assign id's to all methods or to none of them.\n",
918 // In the case that all methods have unassigned id's, set a unique id for them.
919 if (hasUnassignedIds) {
922 while (item != NULL) {
923 if (item->item_type == METHOD_TYPE) {
924 method_type* method_item = (method_type*)item;
925 method_item->assigned_id = newId++;
935 // ==========================================================
937 compile_aidl(Options& options)
941 set_import_paths(options.importPaths);
943 register_base_types();
945 // import the preprocessed file
946 N = options.preprocessedFiles.size();
947 for (int i=0; i<N; i++) {
948 const string& s = options.preprocessedFiles[i];
949 err |= parse_preprocessed_file(s);
955 // parse the main file
956 g_callbacks = &g_mainCallbacks;
957 err = parse_aidl(options.inputFileName.c_str());
958 document_item_type* mainDoc = g_document;
962 g_callbacks = &g_mainCallbacks;
963 import_info* import = g_imports;
965 if (NAMES.Find(import->neededClass) == NULL) {
966 import->filename = find_import_file(import->neededClass);
967 if (!import->filename) {
968 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
969 import->from, import->statement.lineno,
970 import->neededClass);
973 err |= parse_aidl(import->filename);
974 import->doc = g_document;
975 if (import->doc == NULL) {
980 import = import->next;
982 // bail out now if parsing wasn't successful
983 if (err != 0 || mainDoc == NULL) {
984 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
988 // complain about ones that aren't in the right files
989 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
992 err |= check_filenames(import->filename, import->doc);
993 import = import->next;
996 // gather the types that have been declared
997 err |= gather_types(options.inputFileName.c_str(), mainDoc);
1000 err |= gather_types(import->filename, import->doc);
1001 import = import->next;
1005 printf("---- main doc ----\n");
1006 test_document(mainDoc);
1010 printf("---- import doc ----\n");
1011 test_document(import->doc);
1012 import = import->next;
1017 // check the referenced types in mainDoc to make sure we've imported them
1018 err |= check_types(options.inputFileName.c_str(), mainDoc);
1020 // finally, there really only needs to be one thing in mainDoc, and it
1021 // needs to be an interface.
1022 bool onlyParcelable = false;
1023 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
1025 // If this includes an interface definition, then assign method ids and validate.
1026 if (!onlyParcelable) {
1027 err |= check_and_assign_method_ids(options.inputFileName.c_str(),
1028 ((interface_type*)mainDoc)->interface_items);
1031 // after this, there shouldn't be any more errors because of the
1033 if (err != 0 || mainDoc == NULL) {
1037 // if needed, generate the outputFileName from the outputBaseFolder
1038 if (options.outputFileName.length() == 0 &&
1039 options.outputBaseFolder.length() > 0) {
1040 options.outputFileName = generate_outputFileName(options, mainDoc);
1043 // if we were asked to, generate a make dependency file
1044 // unless it's a parcelable *and* it's supposed to fail on parcelable
1045 if ((options.autoDepFile || options.depFileName != "") &&
1046 !(onlyParcelable && options.failOnParcelable)) {
1047 // make sure the folders of the output file all exists
1048 check_outputFilePath(options.outputFileName);
1049 generate_dep_file(options, mainDoc);
1052 // they didn't ask to fail on parcelables, so just exit quietly.
1053 if (onlyParcelable && !options.failOnParcelable) {
1057 // make sure the folders of the output file all exists
1058 check_outputFilePath(options.outputFileName);
1060 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1061 (interface_type*)mainDoc);
1067 preprocess_aidl(const Options& options)
1069 vector<string> lines;
1073 int N = options.filesToPreprocess.size();
1074 for (int i=0; i<N; i++) {
1075 g_callbacks = &g_mainCallbacks;
1076 err = parse_aidl(options.filesToPreprocess[i].c_str());
1080 document_item_type* doc = g_document;
1082 if (doc->item_type == USER_DATA_TYPE) {
1083 user_data_type* parcelable = (user_data_type*)doc;
1084 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
1085 line = "parcelable ";
1087 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1088 line = "flattenable ";
1090 if (parcelable->package) {
1091 line += parcelable->package;
1094 line += parcelable->name.data;
1096 line = "interface ";
1097 interface_type* iface = (interface_type*)doc;
1098 if (iface->package) {
1099 line += iface->package;
1102 line += iface->name.data;
1105 lines.push_back(line);
1108 // write preprocessed file
1109 int fd = open( options.outputFileName.c_str(),
1110 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1111 #ifdef HAVE_MS_C_RUNTIME
1112 _S_IREAD|_S_IWRITE);
1114 S_IRUSR|S_IWUSR|S_IRGRP);
1117 fprintf(stderr, "aidl: could not open file for write: %s\n",
1118 options.outputFileName.c_str());
1123 for (int i=0; i<N; i++) {
1124 const string& s = lines[i];
1125 int len = s.length();
1126 if (len != write(fd, s.c_str(), len)) {
1127 fprintf(stderr, "aidl: error writing to file %s\n",
1128 options.outputFileName.c_str());
1130 unlink(options.outputFileName.c_str());
1139 // ==========================================================
1141 main(int argc, const char **argv)
1144 int result = parse_options(argc, argv, &options);
1149 switch (options.task)
1152 return compile_aidl(options);
1153 case PREPROCESS_AIDL:
1154 return preprocess_aidl(options);
1156 fprintf(stderr, "aidl: internal error\n");