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