handle filesystems where lowercase(file)==file more gracefully
[swftools.git] / lib / as3 / compiler.c
1 /* compiler.h
2
3    Compiler for parsing Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008/2009 Matthias Kramm <kramm@quiss.org>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23
24 #include "common.h"
25 #include "tokenizer.h"
26 #include "files.h"
27 #include "parser.h"
28 #include "parser.tab.h"
29 #include "compiler.h"
30 #include "../os.h"
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34 #ifdef HAVE_DIRENT_H
35 #include <dirent.h>
36 #endif
37
38 /* flex/bison definitions */
39 extern int a3_parse();
40 extern int as3_lex();
41 extern int as3_lex_destroy();
42
43 static char config_recurse = 0;
44
45 void as3_setverbosity(int level)
46 {
47     as3_verbosity=level;
48 }
49 void as3_add_include_dir(char*dir)
50 {
51     add_include_dir(dir);
52 }
53 void as3_set_option(const char*key, const char*value)
54 {
55     if(!strcmp(key, "recurse")) {
56         config_recurse=atoi(value);
57     }
58 }
59
60 static char registry_initialized = 0;
61 static char parser_initialized = 0;
62
63 //#define STORE_TOKENS
64
65 //#define DEBUG
66 #define DEBUG if(0)
67
68 int a3_lex()
69 {
70     as3_tokencount++;
71     return as3_lex();
72 }
73
74 typedef struct _compile_list {
75     const char*name;
76     const char*filename;
77     struct _compile_list*next;
78 } compile_list_t;
79 static compile_list_t*compile_list=0;
80
81 static void as3_parse_file_or_array(const char*name, const char*filename, const void*mem, int length)
82 {
83     if(!registry_initialized) {
84         registry_initialized = 1;
85         registry_init();
86     }
87     if(!parser_initialized) {
88         parser_initialized = 1;
89         initialize_parser();
90     }
91
92     FILE*fi = 0;
93     if(filename) {
94         if(as3_pass==1 && !mem) {
95             // record the fact that we compiled this file
96             compile_list_t*c = rfx_calloc(sizeof(compile_list_t));
97             c->next = compile_list;
98             c->name = strdup(name);
99             c->filename = strdup(filename);
100             compile_list = c;
101         }
102         DEBUG printf("[pass %d] parse file %s %s\n", as3_pass, name, filename);
103         fi = enter_file2(name, filename, 0);
104         as3_file_input(fi);
105     } else {
106         DEBUG printf("[pass %d] parse bytearray %s (%d bytes)\n", as3_pass, name, length);
107         enter_file(name, name, 0);
108         as3_buffer_input((void*)mem, length);
109     }
110
111     as3_tokencount=0;
112     initialize_file(name, filename);
113     a3_parse();
114     as3_lex_destroy();
115     finish_file();
116     if(fi) fclose(fi);
117 }
118
119 typedef struct _scheduled_file {
120     char*name;
121     char*filename;
122     struct _scheduled_file*next;
123 } scheduled_file_t;
124
125 static scheduled_file_t*scheduled=0;
126 dict_t*scheduled_dict=0;
127
128 void as3_parse_scheduled()
129 {
130     DEBUG printf("[pass %d] parse scheduled\n", as3_pass);
131
132     while(scheduled) {
133         scheduled_file_t*s = scheduled;
134         scheduled = 0;
135         while(s) {
136             scheduled_file_t*old = s;
137             as3_parse_file_or_array(s->name, s->filename, 0,0);
138             s = s->next;
139
140             free(old->filename);
141             free(old->name);
142             old->filename = old->name = 0;
143             free(old);
144         }
145     }
146     if(scheduled_dict) {
147         dict_destroy(scheduled_dict);
148         scheduled_dict=0;
149     }
150 }
151
152 void as3_schedule_file(const char*name, const char*filename) 
153 {
154     if(!scheduled_dict) {
155         scheduled_dict = dict_new();
156     }
157
158     filename = normalize_path(filename);
159
160     if(dict_contains(scheduled_dict, filename)) {
161         return; //already processed
162     } else {
163         dict_put(scheduled_dict, filename, 0);
164     }
165     DEBUG printf("[pass %d] schedule %s %s\n", as3_pass, name, filename);
166
167     NEW(scheduled_file_t, f);
168     f->name = strdup(name);
169     f->filename = strdup(filename);
170     f->next = scheduled; // dfs
171     scheduled = f;
172 }
173
174 void as3_parse_list()
175 {
176     while(compile_list) {
177         as3_parse_file_or_array(compile_list->name, compile_list->filename, 0,0);
178         compile_list = compile_list->next;
179     }
180 }
181
182 void as3_parse_bytearray(const char*name, const void*mem, int length)
183 {
184     as3_pass = 1;
185     as3_parse_file_or_array(name, 0, mem, length);
186     as3_parse_scheduled();
187     
188     registry_resolve_all();
189     
190     as3_pass = 2;
191     as3_parse_file_or_array(name, 0, mem, length);
192     as3_parse_list();
193 }
194
195 void as3_parse_file(const char*filename) 
196 {
197     char*fullfilename = find_file(filename, 1);
198     if(!fullfilename)
199         return; // not found
200
201     compile_list = 0;
202     as3_pass = 1;
203     as3_schedule_file(filename, fullfilename);
204     as3_parse_scheduled();
205     
206     registry_resolve_all();
207
208     as3_pass = 2;
209     as3_parse_list();
210
211     free(fullfilename);
212 }
213
214 void as3_parse_directory(const char*dir)
215 {
216     compile_list = 0;
217
218     as3_pass = 1;
219     as3_schedule_directory(dir);
220     if(!scheduled)
221         as3_warning("Directory %s doesn't contain any ActionScript files", dir);
222     as3_parse_scheduled();
223
224     registry_resolve_all();
225
226     as3_pass = 2;
227     as3_parse_list();
228 }
229
230 char as3_schedule_directory(const char*dirname)
231 {
232     DEBUG printf("[pass %d] schedule directory %s\n", as3_pass, dirname);
233     char ok=0;
234 #ifdef HAVE_DIRENT_H
235     include_dir_t*i = current_include_dirs;
236     while(i) {
237         char*fulldirname = concat_paths(i->path, dirname);
238         DEBUG printf("[pass %d] ... %s\n", as3_pass, fulldirname);
239         DIR*dir = opendir(fulldirname);
240         if(dir) {
241             ok = 1;
242             struct dirent*ent;
243             while(1) {
244                 ent = readdir(dir);
245                 if (!ent) 
246                     break;
247                 char*name = ent->d_name;
248                 char type = 0;
249                 if(!name) continue;
250                 int l=strlen(name);
251                 if(l<4)
252                     continue;
253                 if(strncasecmp(&name[l-3], ".as", 3)) 
254                     continue;
255                 char*fullfilename = concatPaths(fulldirname, name);
256                 as3_schedule_file(name, fullfilename);
257                 free(fullfilename);
258             }
259         }
260         free(fulldirname);
261         i = i->next;
262     }
263 #endif
264     return ok;
265 }
266
267 void as3_schedule_package(const char*package)
268 {
269     DEBUG printf("[pass %d] schedule package %s\n", as3_pass, package);
270     char*dirname = strdup(package);
271     int s=0;
272     while(dirname[s]) {
273         if(dirname[s]=='.') 
274             dirname[s] = path_seperator;
275         s++;
276     };
277     if(!as3_schedule_directory(dirname))
278         as3_softwarning("Could not find package %s in file system", package);
279 }
280
281 static void schedule_class(const char*package, const char*cls, char error)
282 {
283     if(error) {
284         DEBUG printf("[pass %d] schedule class %s.%s\n",  as3_pass, package, cls);
285     }
286     if(!cls) {
287         as3_schedule_package(package);
288         return;
289     }
290     int l1 = package?strlen(package):0;
291     int l2 = cls?strlen(cls):0;
292     char*filename = malloc(l1+l2+5);
293     int s=0,t=0;
294     while(package[s]) {
295         if(package[s]=='.')
296             filename[t++]='/';
297         else
298             filename[t++] = package[s];
299         s++;
300     }
301     if(t)
302         filename[t++] = '/';
303
304     strcpy(filename+t, cls);
305     strcpy(filename+t+l2, ".as");
306     char*f=find_file(filename, error);
307     if(!f) {
308         int i;
309         filename = filename_to_lowercase(filename);
310         f=find_file(filename, error);
311     }
312     if(!f) {
313         if(error) {
314             strcpy(filename+t, cls);
315             strcpy(filename+t+l2, ".as");
316             as3_warning("Could not open file %s", filename);
317         }
318         return;
319     }
320     as3_schedule_file(filename, f);
321 }
322
323 void as3_schedule_class(const char*package, const char*cls)
324 {
325     schedule_class(package, cls, 1);
326 }
327
328 void as3_schedule_class_noerror(const char*package, const char*cls)
329 {
330     if(config_recurse) {
331         schedule_class(package, cls, 0);
332     }
333 }
334
335
336 static void*as3code = 0;
337 void* as3_getcode()
338 {
339     if(parser_initialized) {
340         parser_initialized = 0;
341         as3code = finish_parser();
342     }
343     return as3code;
344 }
345 char* as3_getglobalclass()
346 {
347     return as3_globalclass;
348 }
349
350 void as3_destroy() 
351 {
352     if(parser_initialized) {
353         parser_initialized = 0;
354         swf_FreeABC(finish_parser());
355 #ifdef STORE_TOKENS
356         mem_clear(&tokens);
357 #endif
358     }
359     if(as3_globalclass) {
360         free(as3_globalclass);as3_globalclass=0;
361     }
362 }
363