aidl.cpp revision 18fff11e15dc1b4fe53cb37fa39637aa3fb9bc36
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%08lx d->item_type=%d\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, const document_item_type* items)
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 = NULL;
584    if (options.autoDepFile) {
585        string fileName = options.outputFileName + ".d";
586        to = fopen(fileName.c_str(), "wb");
587    } else {
588        to = fopen(options.depFileName.c_str(), "wb");
589    }
590
591    if (to == NULL) {
592        return;
593    }
594
595    const char* slash = "\\";
596    import_info* import = g_imports;
597    if (import == NULL) {
598        slash = "";
599    }
600
601    if (items->item_type == INTERFACE_TYPE) {
602        fprintf(to, "%s: \\\n", options.outputFileName.c_str());
603    } else {
604        // parcelable: there's no output file.
605        fprintf(to, " : \\\n");
606    }
607    fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
608
609    while (import) {
610        if (import->next == NULL) {
611            slash = "";
612        }
613        if (import->filename) {
614            fprintf(to, "  %s %s\n", import->filename, slash);
615        }
616        import = import->next;
617    }
618
619    fprintf(to, "\n");
620
621    fclose(to);
622}
623
624// ==========================================================
625static string
626generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
627{
628    string result;
629
630    // create the path to the destination folder based on the
631    // interface package name
632    result = options.outputBaseFolder;
633    result += OS_PATH_SEPARATOR;
634
635    string packageStr = package;
636    size_t len = packageStr.length();
637    for (size_t i=0; i<len; i++) {
638        if (packageStr[i] == '.') {
639            packageStr[i] = OS_PATH_SEPARATOR;
640        }
641    }
642
643    result += packageStr;
644
645    // add the filename by replacing the .aidl extension to .java
646    const char* p = strchr(name.data, '.');
647    len = p ? p-name.data : strlen(name.data);
648
649    result += OS_PATH_SEPARATOR;
650    result.append(name.data, len);
651    result += ".java";
652
653    return result;
654}
655
656// ==========================================================
657static string
658generate_outputFileName(const Options& options, const document_item_type* items)
659{
660    // items has already been checked to have only one interface.
661    if (items->item_type == INTERFACE_TYPE) {
662        interface_type* type = (interface_type*)items;
663
664        return generate_outputFileName2(options, type->name, type->package);
665    } else if (items->item_type == PARCELABLE_TYPE) {
666        parcelable_type* type = (parcelable_type*)items;
667        return generate_outputFileName2(options, type->name, type->package);
668    }
669
670    // I don't think we can come here, but safer than returning NULL.
671    string result;
672    return result;
673}
674
675
676
677// ==========================================================
678static void
679check_outputFilePath(const string& path) {
680    size_t len = path.length();
681    for (size_t i=0; i<len ; i++) {
682        if (path[i] == OS_PATH_SEPARATOR) {
683            string p = path.substr(0, i);
684            if (access(path.data(), F_OK) != 0) {
685#ifdef HAVE_MS_C_RUNTIME
686                _mkdir(p.data());
687#else
688                mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
689#endif
690            }
691        }
692    }
693}
694
695
696// ==========================================================
697static int
698parse_preprocessed_file(const string& filename)
699{
700    int err;
701
702    FILE* f = fopen(filename.c_str(), "rb");
703    if (f == NULL) {
704        fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
705                filename.c_str());
706        return 1;
707    }
708
709    int lineno = 1;
710    char line[1024];
711    char type[1024];
712    char fullname[1024];
713    while (fgets(line, sizeof(line), f)) {
714        // skip comments and empty lines
715        if (!line[0] || strncmp(line, "//", 2) == 0) {
716          continue;
717        }
718
719        sscanf(line, "%s %[^; \r\n\t];", type, fullname);
720
721        char* packagename;
722        char* classname = rfind(fullname, '.');
723        if (classname != NULL) {
724            *classname = '\0';
725            classname++;
726            packagename = fullname;
727        } else {
728            classname = fullname;
729            packagename = NULL;
730        }
731
732        //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
733        //        type, packagename, classname);
734        document_item_type* doc;
735
736        if (0 == strcmp("parcelable", type)) {
737            parcelable_type* parcl = (parcelable_type*)malloc(
738                    sizeof(parcelable_type));
739            memset(parcl, 0, sizeof(parcelable_type));
740            parcl->document_item.item_type = PARCELABLE_TYPE;
741            parcl->parcelable_token.lineno = lineno;
742            parcl->parcelable_token.data = strdup(type);
743            parcl->package = packagename ? strdup(packagename) : NULL;
744            parcl->name.lineno = lineno;
745            parcl->name.data = strdup(classname);
746            parcl->semicolon_token.lineno = lineno;
747            parcl->semicolon_token.data = strdup(";");
748            doc = (document_item_type*)parcl;
749        }
750        else if (0 == strcmp("interface", type)) {
751            interface_type* iface = (interface_type*)malloc(
752                    sizeof(interface_type));
753            memset(iface, 0, sizeof(interface_type));
754            iface->document_item.item_type = INTERFACE_TYPE;
755            iface->interface_token.lineno = lineno;
756            iface->interface_token.data = strdup(type);
757            iface->package = packagename ? strdup(packagename) : NULL;
758            iface->name.lineno = lineno;
759            iface->name.data = strdup(classname);
760            iface->open_brace_token.lineno = lineno;
761            iface->open_brace_token.data = strdup("{");
762            iface->close_brace_token.lineno = lineno;
763            iface->close_brace_token.data = strdup("}");
764            doc = (document_item_type*)iface;
765        }
766        else {
767            fprintf(stderr, "%s:%d: bad type in line: %s\n",
768                    filename.c_str(), lineno, line);
769            return 1;
770        }
771        err = gather_types(filename.c_str(), doc);
772        lineno++;
773    }
774
775    if (!feof(f)) {
776        fprintf(stderr, "%s:%d: error reading file, line to long.\n",
777                filename.c_str(), lineno);
778        return 1;
779    }
780
781    fclose(f);
782    return 0;
783}
784
785// ==========================================================
786static int
787compile_aidl(Options& options)
788{
789    int err = 0, N;
790
791    set_import_paths(options.importPaths);
792
793    register_base_types();
794
795    // import the preprocessed file
796    N = options.preprocessedFiles.size();
797    for (int i=0; i<N; i++) {
798        const string& s = options.preprocessedFiles[i];
799        err |= parse_preprocessed_file(s);
800    }
801    if (err != 0) {
802        return err;
803    }
804
805    // parse the main file
806    g_callbacks = &g_mainCallbacks;
807    err = parse_aidl(options.inputFileName.c_str());
808    document_item_type* mainDoc = g_document;
809    g_document = NULL;
810
811    // parse the imports
812    g_callbacks = &g_mainCallbacks;
813    import_info* import = g_imports;
814    while (import) {
815        if (NAMES.Find(import->neededClass) == NULL) {
816            import->filename = find_import_file(import->neededClass);
817            if (!import->filename) {
818                fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
819                        import->from, import->statement.lineno,
820                        import->neededClass);
821                err |= 1;
822            } else {
823                err |= parse_aidl(import->filename);
824                import->doc = g_document;
825                if (import->doc == NULL) {
826                    err |= 1;
827                }
828            }
829        }
830        import = import->next;
831    }
832    // bail out now if parsing wasn't successful
833    if (err != 0 || mainDoc == NULL) {
834        //fprintf(stderr, "aidl: parsing failed, stopping.\n");
835        return 1;
836    }
837
838    // complain about ones that aren't in the right files
839    err |= check_filenames(options.inputFileName.c_str(), mainDoc);
840    import = g_imports;
841    while (import) {
842        err |= check_filenames(import->filename, import->doc);
843        import = import->next;
844    }
845
846    // gather the types that have been declared
847    err |= gather_types(options.inputFileName.c_str(), mainDoc);
848    import = g_imports;
849    while (import) {
850        err |= gather_types(import->filename, import->doc);
851        import = import->next;
852    }
853
854#if 0
855    printf("---- main doc ----\n");
856    test_document(mainDoc);
857
858    import = g_imports;
859    while (import) {
860        printf("---- import doc ----\n");
861        test_document(import->doc);
862        import = import->next;
863    }
864    NAMES.Dump();
865#endif
866
867    // check the referenced types in mainDoc to make sure we've imported them
868    err |= check_types(options.inputFileName.c_str(), mainDoc);
869
870    // finally, there really only needs to be one thing in mainDoc, and it
871    // needs to be an interface.
872    bool onlyParcelable = false;
873    err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
874
875    // after this, there shouldn't be any more errors because of the
876    // input.
877    if (err != 0 || mainDoc == NULL) {
878        return 1;
879    }
880
881    // if needed, generate the outputFileName from the outputBaseFolder
882    if (options.outputFileName.length() == 0 &&
883            options.outputBaseFolder.length() > 0) {
884        options.outputFileName = generate_outputFileName(options, mainDoc);
885    }
886
887    // if we were asked to, generate a make dependency file
888    // unless it's a parcelable *and* it's supposed to fail on parcelable
889    if ((options.autoDepFile || options.depFileName != "") &&
890            !(onlyParcelable && options.failOnParcelable)) {
891        // make sure the folders of the output file all exists
892        check_outputFilePath(options.outputFileName);
893        generate_dep_file(options, mainDoc);
894    }
895
896    // they didn't ask to fail on parcelables, so just exit quietly.
897    if (onlyParcelable && !options.failOnParcelable) {
898        return 0;
899    }
900
901    // make sure the folders of the output file all exists
902    check_outputFilePath(options.outputFileName);
903
904    err = generate_java(options.outputFileName, options.inputFileName.c_str(),
905                        (interface_type*)mainDoc);
906
907    return err;
908}
909
910static int
911preprocess_aidl(const Options& options)
912{
913    vector<string> lines;
914    int err;
915
916    // read files
917    int N = options.filesToPreprocess.size();
918    for (int i=0; i<N; i++) {
919        g_callbacks = &g_mainCallbacks;
920        err = parse_aidl(options.filesToPreprocess[i].c_str());
921        if (err != 0) {
922            return err;
923        }
924        document_item_type* doc = g_document;
925        string line;
926        if (doc->item_type == PARCELABLE_TYPE) {
927            line = "parcelable ";
928            parcelable_type* parcelable = (parcelable_type*)doc;
929            if (parcelable->package) {
930                line += parcelable->package;
931                line += '.';
932            }
933            line += parcelable->name.data;
934        } else {
935            line = "interface ";
936            interface_type* iface = (interface_type*)doc;
937            if (iface->package) {
938                line += iface->package;
939                line += '.';
940            }
941            line += iface->name.data;
942        }
943        line += ";\n";
944        lines.push_back(line);
945    }
946
947    // write preprocessed file
948    int fd = open( options.outputFileName.c_str(),
949                   O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
950#ifdef HAVE_MS_C_RUNTIME
951                   _S_IREAD|_S_IWRITE);
952#else
953                   S_IRUSR|S_IWUSR|S_IRGRP);
954#endif
955    if (fd == -1) {
956        fprintf(stderr, "aidl: could not open file for write: %s\n",
957                options.outputFileName.c_str());
958        return 1;
959    }
960
961    N = lines.size();
962    for (int i=0; i<N; i++) {
963        const string& s = lines[i];
964        int len = s.length();
965        if (len != write(fd, s.c_str(), len)) {
966            fprintf(stderr, "aidl: error writing to file %s\n",
967                options.outputFileName.c_str());
968            close(fd);
969            unlink(options.outputFileName.c_str());
970            return 1;
971        }
972    }
973
974    close(fd);
975    return 0;
976}
977
978// ==========================================================
979int
980main(int argc, const char **argv)
981{
982    Options options;
983    int result = parse_options(argc, argv, &options);
984    if (result) {
985        return result;
986    }
987
988    switch (options.task)
989    {
990        case COMPILE_AIDL:
991            return compile_aidl(options);
992        case PREPROCESS_AIDL:
993            return preprocess_aidl(options);
994    }
995    fprintf(stderr, "aidl: internal error\n");
996    return 1;
997}
998
999
1000