blob: e24876331c72db54d66adfe453330cbc9b568bc1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001
2#include "aidl_language.h"
3#include "options.h"
4#include "search_path.h"
5#include "Type.h"
6#include "generate_java.h"
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/param.h>
10#include <sys/stat.h>
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <map>
16
17#ifdef HAVE_MS_C_RUNTIME
18#include <io.h>
19#include <sys/stat.h>
20#endif
21
22#ifndef O_BINARY
23# define O_BINARY 0
24#endif
25
26using namespace std;
27
28static void
29test_document(document_item_type* d)
30{
31 while (d) {
32 if (d->item_type == INTERFACE_TYPE) {
33 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 }
57 else {
58 printf("UNKNOWN d=0x%08x d->item_type=%ld\n", (long)d, d->item_type);
59 }
60 d = d->next;
61 }
62}
63
64// ==========================================================
65int
66convert_direction(const char* direction)
67{
68 if (direction == NULL) {
69 return IN_PARAMETER;
70 }
71 if (0 == strcmp(direction, "in")) {
72 return IN_PARAMETER;
73 }
74 if (0 == strcmp(direction, "out")) {
75 return OUT_PARAMETER;
76 }
77 return INOUT_PARAMETER;
78}
79
80// ==========================================================
81struct import_info {
82 const char* from;
83 const char* filename;
84 buffer_type statement;
85 const char* neededClass;
86 document_item_type* doc;
87 struct import_info* next;
88};
89
90document_item_type* g_document = NULL;
91import_info* g_imports = NULL;
92
93static void
94main_document_parsed(document_item_type* d)
95{
96 g_document = d;
97}
98
99static void
100main_import_parsed(buffer_type* statement)
101{
102 import_info* import = (import_info*)malloc(sizeof(import_info));
103 memset(import, 0, sizeof(import_info));
104 import->from = strdup(g_currentFilename);
105 import->statement.lineno = statement->lineno;
106 import->statement.data = strdup(statement->data);
107 import->statement.extra = NULL;
108 import->next = g_imports;
109 import->neededClass = parse_import_statement(statement->data);
110 g_imports = import;
111}
112
113static ParserCallbacks g_mainCallbacks = {
114 &main_document_parsed,
115 &main_import_parsed
116};
117
118char*
119parse_import_statement(const char* text)
120{
121 const char* end;
122 int len;
123
124 while (isspace(*text)) {
125 text++;
126 }
127 while (!isspace(*text)) {
128 text++;
129 }
130 while (isspace(*text)) {
131 text++;
132 }
133 end = text;
134 while (!isspace(*end) && *end != ';') {
135 end++;
136 }
137 len = end-text;
138
139 char* rv = (char*)malloc(len+1);
140 memcpy(rv, text, len);
141 rv[len] = '\0';
142
143 return rv;
144}
145
146// ==========================================================
147static void
148import_import_parsed(buffer_type* statement)
149{
150}
151
152static ParserCallbacks g_importCallbacks = {
153 &main_document_parsed,
154 &import_import_parsed
155};
156
157// ==========================================================
158static int
159check_filename(const char* filename, const char* package, buffer_type* name)
160{
161 const char* p;
162 string expected;
163 string fn;
164 size_t len;
165 char cwd[MAXPATHLEN];
166 bool valid = false;
167
168#ifdef HAVE_WINDOWS_PATHS
169 if (isalpha(filename[0]) && filename[1] == ':'
170 && filename[2] == OS_PATH_SEPARATOR) {
171#else
172 if (filename[0] == OS_PATH_SEPARATOR) {
173#endif
174 fn = filename;
175 } else {
176 fn = getcwd(cwd, sizeof(cwd));
177 len = fn.length();
178 if (fn[len-1] != OS_PATH_SEPARATOR) {
179 fn += OS_PATH_SEPARATOR;
180 }
181 fn += filename;
182 }
183
184 if (package) {
185 expected = package;
186 expected += '.';
187 }
188
189 len = expected.length();
190 for (size_t i=0; i<len; i++) {
191 if (expected[i] == '.') {
192 expected[i] = OS_PATH_SEPARATOR;
193 }
194 }
195
196 p = strchr(name->data, '.');
197 len = p ? p-name->data : strlen(name->data);
198 expected.append(name->data, len);
199
200 expected += ".aidl";
201
202 len = fn.length();
203 valid = (len >= expected.length());
204
205 if (valid) {
206 p = fn.c_str() + (len - expected.length());
207
208#ifdef HAVE_WINDOWS_PATHS
209 if (OS_PATH_SEPARATOR != '/') {
210 // Input filename under cygwin most likely has / separators
211 // whereas the expected string uses \\ separators. Adjust
212 // them accordingly.
213 for (char *c = const_cast<char *>(p); *c; ++c) {
214 if (*c == '/') *c = OS_PATH_SEPARATOR;
215 }
216 }
217#endif
218
219#ifdef OS_CASE_SENSITIVE
220 valid = (expected == p);
221#else
222 valid = !strcasecmp(expected.c_str(), p);
223#endif
224 }
225
226 if (!valid) {
227 fprintf(stderr, "%s:%d interface %s should be declared in a file"
228 " called %s.\n",
229 filename, name->lineno, name->data, expected.c_str());
230 return 1;
231 }
232
233 return 0;
234}
235
236static int
237check_filenames(const char* filename, document_item_type* items)
238{
239 int err = 0;
240 while (items) {
241 if (items->item_type == PARCELABLE_TYPE) {
242 parcelable_type* p = (parcelable_type*)items;
243 err |= check_filename(filename, p->package, &p->name);
244 }
245 else if (items->item_type == INTERFACE_TYPE) {
246 interface_type* c = (interface_type*)items;
247 err |= check_filename(filename, c->package, &c->name);
248 }
249 else {
250 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
251 items->item_type);
252 return 1;
253 }
254 items = items->next;
255 }
256 return err;
257}
258
259// ==========================================================
260static const char*
261kind_to_string(int kind)
262{
263 switch (kind)
264 {
265 case Type::INTERFACE:
266 return "an interface";
267 case Type::PARCELABLE:
268 return "a parcelable";
269 default:
270 return "ERROR";
271 }
272}
273
274static char*
275rfind(char* str, char c)
276{
277 char* p = str + strlen(str) - 1;
278 while (p >= str) {
279 if (*p == c) {
280 return p;
281 }
282 p--;
283 }
284 return NULL;
285}
286
287static int
288gather_types(const char* filename, document_item_type* items)
289{
290 int err = 0;
291 while (items) {
292 Type* type;
293 if (items->item_type == PARCELABLE_TYPE) {
294 parcelable_type* p = (parcelable_type*)items;
295 type = new ParcelableType(p->package ? p->package : "",
296 p->name.data, false, filename, p->name.lineno);
297 }
298 else if (items->item_type == INTERFACE_TYPE) {
299 interface_type* c = (interface_type*)items;
300 type = new InterfaceType(c->package ? c->package : "",
301 c->name.data, false, c->oneway,
302 filename, c->name.lineno);
303 }
304 else {
305 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
306 return 1;
307 }
308
309 Type* old = NAMES.Find(type->QualifiedName());
310 if (old == NULL) {
311 NAMES.Add(type);
312
313 if (items->item_type == INTERFACE_TYPE) {
314 // for interfaces, also add the stub and proxy types, we don't
315 // bother checking these for duplicates, because the parser
316 // won't let us do it.
317 interface_type* c = (interface_type*)items;
318
319 string name = c->name.data;
320 name += ".Stub";
321 Type* stub = new Type(c->package ? c->package : "",
322 name, Type::GENERATED, false, false,
323 filename, c->name.lineno);
324 NAMES.Add(stub);
325
326 name = c->name.data;
327 name += ".Stub.Proxy";
328 Type* proxy = new Type(c->package ? c->package : "",
329 name, Type::GENERATED, false, false,
330 filename, c->name.lineno);
331 NAMES.Add(proxy);
332 }
333 } else {
334 if (old->Kind() == Type::BUILT_IN) {
335 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
336 filename, type->DeclLine(),
337 type->QualifiedName().c_str());
338 err = 1;
339 }
340 else if (type->Kind() != old->Kind()) {
341 const char* oldKind = kind_to_string(old->Kind());
342 const char* newKind = kind_to_string(type->Kind());
343
344 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
345 filename, type->DeclLine(),
346 type->QualifiedName().c_str(), newKind);
347 fprintf(stderr, "%s:%d previously defined here as %s.\n",
348 old->DeclFile().c_str(), old->DeclLine(), oldKind);
349 err = 1;
350 }
351 }
352
353 items = items->next;
354 }
355 return err;
356}
357
358// ==========================================================
359static bool
360matches_keyword(const char* str)
361{
362 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
363 "byte", "case", "catch", "char", "class", "const", "continue",
364 "default", "do", "double", "else", "enum", "extends", "final",
365 "finally", "float", "for", "goto", "if", "implements", "import",
366 "instanceof", "int", "interface", "long", "native", "new", "package",
367 "private", "protected", "public", "return", "short", "static",
368 "strictfp", "super", "switch", "synchronized", "this", "throw",
369 "throws", "transient", "try", "void", "volatile", "while",
370 "true", "false", "null",
371 NULL
372 };
373 const char** k = KEYWORDS;
374 while (*k) {
375 if (0 == strcmp(str, *k)) {
376 return true;
377 }
378 k++;
379 }
380 return false;
381}
382
383static int
384check_method(const char* filename, method_type* m)
385{
386 int err = 0;
387
388 // return type
389 Type* returnType = NAMES.Search(m->type.type.data);
390 if (returnType == NULL) {
391 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
392 m->type.type.lineno, m->type.type.data);
393 err = 1;
394 return err;
395 }
396
397 if (!returnType->CanBeMarshalled()) {
398 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
399 m->type.type.lineno, m->type.type.data);
400 err = 1;
401 }
402
403 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
404 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
405 m->type.array_token.lineno, m->type.type.data,
406 m->type.array_token.data);
407 err = 1;
408 }
409
410 if (m->type.dimension > 1) {
411 fprintf(stderr, "%s:%d return type %s%s only one"
412 " dimensional arrays are supported\n", filename,
413 m->type.array_token.lineno, m->type.type.data,
414 m->type.array_token.data);
415 err = 1;
416 }
417
418 int index = 1;
419
420 arg_type* arg = m->args;
421 while (arg) {
422 Type* t = NAMES.Search(arg->type.type.data);
423
424 // check the arg type
425 if (t == NULL) {
426 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
427 filename, m->type.type.lineno, arg->name.data, index,
428 arg->type.type.data);
429 err = 1;
430 goto next;
431 }
432
433 if (!t->CanBeMarshalled()) {
434 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
435 filename, m->type.type.lineno, index,
436 arg->type.type.data, arg->name.data);
437 err = 1;
438 }
439
440 if (arg->direction.data == NULL
441 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
442 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
443 " parameter, so you must declare it as in,"
444 " out or inout.\n",
445 filename, m->type.type.lineno, index,
446 arg->type.type.data, arg->name.data);
447 err = 1;
448 }
449
450 if (convert_direction(arg->direction.data) != IN_PARAMETER
451 && !t->CanBeOutParameter()
452 && arg->type.dimension == 0) {
453 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
454 " parameter.\n",
455 filename, m->type.type.lineno, index,
456 arg->direction.data, arg->type.type.data,
457 arg->name.data);
458 err = 1;
459 }
460
461 if (arg->type.dimension > 0 && !t->CanBeArray()) {
462 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
463 " array.\n", filename,
464 m->type.array_token.lineno, index, arg->direction.data,
465 arg->type.type.data, arg->type.array_token.data,
466 arg->name.data);
467 err = 1;
468 }
469
470 if (arg->type.dimension > 1) {
471 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
472 " dimensional arrays are supported\n", filename,
473 m->type.array_token.lineno, index, arg->direction.data,
474 arg->type.type.data, arg->type.array_token.data,
475 arg->name.data);
476 err = 1;
477 }
478
479 // check that the name doesn't match a keyword
480 if (matches_keyword(arg->name.data)) {
481 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
482 " Java keyword\n",
483 filename, m->name.lineno, index, arg->name.data);
484 err = 1;
485 }
486
487next:
488 index++;
489 arg = arg->next;
490 }
491
492 return err;
493}
494
495static int
496check_types(const char* filename, document_item_type* items)
497{
498 int err = 0;
499 while (items) {
500 // (nothing to check for PARCELABLE_TYPE)
501 if (items->item_type == INTERFACE_TYPE) {
502 map<string,method_type*> methodNames;
503 interface_type* c = (interface_type*)items;
504
505 interface_item_type* member = c->interface_items;
506 while (member) {
507 if (member->item_type == METHOD_TYPE) {
508 method_type* m = (method_type*)member;
509
510 err |= check_method(filename, m);
511
512 // prevent duplicate methods
513 if (methodNames.find(m->name.data) == methodNames.end()) {
514 methodNames[m->name.data] = m;
515 } else {
516 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
517 filename, m->name.lineno, m->name.data);
518 method_type* old = methodNames[m->name.data];
519 fprintf(stderr, "%s:%d previously defined here.\n",
520 filename, old->name.lineno);
521 err = 1;
522 }
523 }
524 member = member->next;
525 }
526 }
527
528 items = items->next;
529 }
530 return err;
531}
532
533// ==========================================================
534static int
535exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
536 bool* onlyParcelable)
537{
538 if (items == NULL) {
539 fprintf(stderr, "%s: file does not contain any interfaces\n",
540 filename);
541 return 1;
542 }
543
544 const document_item_type* next = items->next;
545 if (items->next != NULL) {
546 int lineno = -1;
547 if (next->item_type == INTERFACE_TYPE) {
548 lineno = ((interface_type*)next)->interface_token.lineno;
549 }
550 else if (next->item_type == PARCELABLE_TYPE) {
551 lineno = ((parcelable_type*)next)->parcelable_token.lineno;
552 }
553 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
554 filename, lineno);
555 return 1;
556 }
557
558 if (items->item_type == PARCELABLE_TYPE) {
559 *onlyParcelable = true;
560 if (options.failOnParcelable) {
561 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
562 " parcelables,\n", filename,
563 ((parcelable_type*)items)->parcelable_token.lineno);
564 fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
565 "don't need to go in the Makefile.\n", filename,
566 ((parcelable_type*)items)->parcelable_token.lineno);
567 return 1;
568 }
569 } else {
570 *onlyParcelable = false;
571 }
572
573 return 0;
574}
575
576// ==========================================================
577void
578generate_dep_file(const Options& options)
579{
580 /* we open the file in binary mode to ensure that the same output is
581 * generated on all platforms !!
582 */
583 FILE* to = fopen(options.depFileName.c_str(), "wb");
584 if (to == NULL) {
585 return;
586 }
587
588 const char* slash = "\\";
589 import_info* import = g_imports;
590 if (import == NULL) {
591 slash = "";
592 }
593
594 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
595 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
596
597 while (import) {
598 if (import->next == NULL) {
599 slash = "";
600 }
601 if (import->filename) {
602 fprintf(to, " %s %s\n", import->filename, slash);
603 }
604 import = import->next;
605 }
606
607 fprintf(to, "\n");
608
609 fclose(to);
610}
611
612// ==========================================================
613static int
614parse_preprocessed_file(const string& filename)
615{
616 int err;
617
618 FILE* f = fopen(filename.c_str(), "rb");
619 if (f == NULL) {
The Android Open Source Project4df24232009-03-05 14:34:35 -0800620 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 filename.c_str());
622 return 1;
623 }
624
625 int lineno = 1;
626 char line[1024];
627 char type[1024];
628 char fullname[1024];
629 while (fgets(line, sizeof(line), f)) {
630 // skip comments and empty lines
631 if (!line[0] || strncmp(line, "//", 2) == 0) {
632 continue;
633 }
634
635 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
636
637 char* packagename;
638 char* classname = rfind(fullname, '.');
639 if (classname != NULL) {
640 *classname = '\0';
641 classname++;
642 packagename = fullname;
643 } else {
644 classname = fullname;
645 packagename = NULL;
646 }
647
648 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
649 // type, packagename, classname);
650 document_item_type* doc;
651
652 if (0 == strcmp("parcelable", type)) {
653 parcelable_type* parcl = (parcelable_type*)malloc(
654 sizeof(parcelable_type));
655 memset(parcl, 0, sizeof(parcelable_type));
656 parcl->document_item.item_type = PARCELABLE_TYPE;
657 parcl->parcelable_token.lineno = lineno;
658 parcl->parcelable_token.data = strdup(type);
659 parcl->package = packagename ? strdup(packagename) : NULL;
660 parcl->name.lineno = lineno;
661 parcl->name.data = strdup(classname);
662 parcl->semicolon_token.lineno = lineno;
663 parcl->semicolon_token.data = strdup(";");
664 doc = (document_item_type*)parcl;
665 }
666 else if (0 == strcmp("interface", type)) {
667 interface_type* iface = (interface_type*)malloc(
668 sizeof(interface_type));
669 memset(iface, 0, sizeof(interface_type));
670 iface->document_item.item_type = INTERFACE_TYPE;
671 iface->interface_token.lineno = lineno;
672 iface->interface_token.data = strdup(type);
673 iface->package = packagename ? strdup(packagename) : NULL;
674 iface->name.lineno = lineno;
675 iface->name.data = strdup(classname);
676 iface->open_brace_token.lineno = lineno;
677 iface->open_brace_token.data = strdup("{");
678 iface->close_brace_token.lineno = lineno;
679 iface->close_brace_token.data = strdup("}");
680 doc = (document_item_type*)iface;
681 }
682 else {
683 fprintf(stderr, "%s:%d: bad type in line: %s\n",
684 filename.c_str(), lineno, line);
685 return 1;
686 }
687 err = gather_types(filename.c_str(), doc);
688 lineno++;
689 }
690
691 if (!feof(f)) {
692 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
693 filename.c_str(), lineno);
694 return 1;
695 }
696
697 fclose(f);
698 return 0;
699}
700
701// ==========================================================
702static int
703compile_aidl(const Options& options)
704{
705 int err = 0, N;
706
707 set_import_paths(options.importPaths);
708
709 register_base_types();
710
711 // import the preprocessed file
712 N = options.preprocessedFiles.size();
713 for (int i=0; i<N; i++) {
714 const string& s = options.preprocessedFiles[i];
715 err |= parse_preprocessed_file(s);
716 }
717 if (err != 0) {
718 return err;
719 }
720
721 // parse the main file
722 g_callbacks = &g_mainCallbacks;
723 err = parse_aidl(options.inputFileName.c_str());
724 document_item_type* mainDoc = g_document;
725 g_document = NULL;
726
727 // parse the imports
728 g_callbacks = &g_mainCallbacks;
729 import_info* import = g_imports;
730 while (import) {
731 if (NAMES.Find(import->neededClass) == NULL) {
732 import->filename = find_import_file(import->neededClass);
733 if (!import->filename) {
734 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
735 import->from, import->statement.lineno,
736 import->neededClass);
737 err |= 1;
738 } else {
739 err |= parse_aidl(import->filename);
740 import->doc = g_document;
741 if (import->doc == NULL) {
742 err |= 1;
743 }
744 }
745 }
746 import = import->next;
747 }
748 // bail out now if parsing wasn't successful
749 if (err != 0 || mainDoc == NULL) {
750 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
751 return 1;
752 }
753
754 // complain about ones that aren't in the right files
755 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
756 import = g_imports;
757 while (import) {
758 err |= check_filenames(import->filename, import->doc);
759 import = import->next;
760 }
761
762 // gather the types that have been declared
763 err |= gather_types(options.inputFileName.c_str(), mainDoc);
764 import = g_imports;
765 while (import) {
766 err |= gather_types(import->filename, import->doc);
767 import = import->next;
768 }
769
770#if 0
771 printf("---- main doc ----\n");
772 test_document(mainDoc);
773
774 import = g_imports;
775 while (import) {
776 printf("---- import doc ----\n");
777 test_document(import->doc);
778 import = import->next;
779 }
780 NAMES.Dump();
781#endif
782
783 // check the referenced types in mainDoc to make sure we've imported them
784 err |= check_types(options.inputFileName.c_str(), mainDoc);
785
786 // finally, there really only needs to be one thing in mainDoc, and it
787 // needs to be an interface.
788 bool onlyParcelable = false;
789 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
790
791 // after this, there shouldn't be any more errors because of the
792 // input.
793 if (err != 0 || mainDoc == NULL) {
794 return 1;
795 }
796
797 // they didn't ask to fail on parcelables, so just exit quietly.
798 if (onlyParcelable && !options.failOnParcelable) {
799 return 0;
800 }
801
802 // if we were asked to, generate a make dependency file
803 if (options.depFileName != "") {
804 generate_dep_file(options);
805 }
806
807 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
808 (interface_type*)mainDoc);
809
810 return err;
811}
812
813static int
814preprocess_aidl(const Options& options)
815{
816 vector<string> lines;
817 int err;
818
819 // read files
820 int N = options.filesToPreprocess.size();
821 for (int i=0; i<N; i++) {
822 g_callbacks = &g_mainCallbacks;
823 err = parse_aidl(options.filesToPreprocess[i].c_str());
824 if (err != 0) {
825 return err;
826 }
827 document_item_type* doc = g_document;
828 string line;
829 if (doc->item_type == PARCELABLE_TYPE) {
830 line = "parcelable ";
831 parcelable_type* parcelable = (parcelable_type*)doc;
832 if (parcelable->package) {
833 line += parcelable->package;
834 line += '.';
835 }
836 line += parcelable->name.data;
837 } else {
838 line = "interface ";
839 interface_type* iface = (interface_type*)doc;
840 if (iface->package) {
841 line += iface->package;
842 line += '.';
843 }
844 line += iface->name.data;
845 }
846 line += ";\n";
847 lines.push_back(line);
848 }
849
850 // write preprocessed file
851 int fd = open( options.outputFileName.c_str(),
852 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
853#ifdef HAVE_MS_C_RUNTIME
854 _S_IREAD|_S_IWRITE);
855#else
856 S_IRUSR|S_IWUSR|S_IRGRP);
857#endif
858 if (fd == -1) {
859 fprintf(stderr, "aidl: could not open file for write: %s\n",
860 options.outputFileName.c_str());
861 return 1;
862 }
863
864 N = lines.size();
865 for (int i=0; i<N; i++) {
866 const string& s = lines[i];
867 int len = s.length();
868 if (len != write(fd, s.c_str(), len)) {
869 fprintf(stderr, "aidl: error writing to file %s\n",
870 options.outputFileName.c_str());
871 close(fd);
872 unlink(options.outputFileName.c_str());
873 return 1;
874 }
875 }
876
877 close(fd);
878 return 0;
879}
880
881// ==========================================================
882int
883main(int argc, const char **argv)
884{
885 int err = 0;
886
887 Options options;
888 int result = parse_options(argc, argv, &options);
889 if (result) {
890 return result;
891 }
892
893 switch (options.task)
894 {
895 case COMPILE_AIDL:
896 return compile_aidl(options);
897 case PREPROCESS_AIDL:
898 return preprocess_aidl(options);
899 }
900 fprintf(stderr, "aidl: internal error\n");
901 return 1;
902}
903
904