aidl.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1
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) {
620        fprintf(stderr, "aidl: can't open preprocessd file: %s\n",
621                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
905