fixed a security bug in logging, added basic xml support to as3 compiler
[swftools.git] / lib / as3 / files.c
1 /* files.c
2
3    Extension module for the rfxswf library.
4    Part of the swftools package.
5
6    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <memory.h>
26 #include <errno.h>
27 #include "files.h"
28 #include "common.h"
29 #include "tokenizer.h"
30
31 static int verbose = 0;
32 static void dbg(const char*format, ...)
33 {
34     char buf[1024];
35     int l;
36     va_list arglist;
37     if(!verbose)
38         return;
39     va_start(arglist, format);
40     vsnprintf(buf, sizeof(buf)-1, format, arglist);
41     va_end(arglist);
42     l = strlen(buf);
43     while(l && buf[l-1]=='\n') {
44         buf[l-1] = 0;
45         l--;
46     }
47     printf("(includefilehandler) ");
48     printf("%s\n", buf);
49     fflush(stdout);
50 }
51
52
53 int current_line=1;
54 int current_column=0;
55 char* current_filename=0;
56 char* current_filename_short=0;
57 char* current_filename_long=0;
58 include_dir_t* current_include_dirs=0;
59
60 #define MAX_INCLUDE_DEPTH 16
61
62 void*include_stack[MAX_INCLUDE_DEPTH];
63 int line_stack[MAX_INCLUDE_DEPTH];
64 int column_stack[MAX_INCLUDE_DEPTH];
65 char* filename_stack[MAX_INCLUDE_DEPTH];
66 char* shortfilename_stack[MAX_INCLUDE_DEPTH];
67 char* longfilename_stack[MAX_INCLUDE_DEPTH];
68 include_dir_t* includedir_stack[MAX_INCLUDE_DEPTH];
69 int include_stack_ptr = 0;
70
71 void add_include_dir(char*dir)
72 {
73     include_dir_t*d = malloc(sizeof(include_dir_t));
74     memset(d , 0, sizeof(include_dir_t));
75     d->path = strdup(dir);
76     d->next = current_include_dirs;
77     current_include_dirs = d;
78 }
79
80 void del_include_dirs(include_dir_t*d, include_dir_t*d2)
81 {
82     while(d && d!=d2) {
83         include_dir_t*next = d->next;
84         free(d->path);d->path=0;
85         d->next = 0;
86         free(d);
87         d = next;
88     }
89 }
90
91 char*get_path(const char*file)
92 {
93     char*path = strdup(file);
94     char*r1 = strrchr(path, '/');
95     char*r2 = strrchr(path, '\\');
96     if(r1<r2) {
97         *r2=0;
98         return path;
99     } else if(r1>r2) {
100         *r1=0;
101         return path;
102     } else {
103         return strdup(".");
104     }
105 }
106 char* normalize_path(const char*path)
107 {
108     char*n = 0, *d = 0;
109     if(path[0] != '/') {
110         char buf[512];
111         char*c = getcwd(buf,512);
112         int l = strlen(buf);
113         d = n = malloc(l+strlen(path)+10);
114         strcpy(n, buf);d += l;
115         if(!l || n[l-1]!='/') {
116             *d='/';d++;
117         }
118     } else {
119         d = n = strdup(path);
120     }
121     const char*s=path;
122     char init = 1;
123
124     while(*s) {
125         if(init && s[0] == '.' && (s[1]=='/' || s[1]=='\0')) {
126             if(!s[1]) break;
127             s+=2;
128             init=1;
129             continue;
130         }
131         if(init && s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2]=='\0')) {
132             // step one down
133             char*last = 0;
134             if(d<=n) 
135                 return 0;
136             *--d = 0;
137             if(!(last=strrchr(n, '/'))) {
138                 return 0;
139             }
140             d = last+1;
141             if(!s[2]) break;
142             s+=3;
143             init=1;
144             continue;
145         }
146
147         *d = *s;
148         if(*s=='/') init=1;
149         else init=0;
150         d++;s++;
151     }
152     if(d!=n && d[-1]=='/') 
153         d--;
154     *d = 0;
155     return n;
156 }
157 static void testnormalize()
158 {
159 #define TEST(x) {printf("%s -> %s\n", (x), normalize_path(x));}
160     TEST(".");
161     TEST("../as3");
162     TEST("../as3/");
163     TEST("../as3/parser.y");
164     TEST("../as3/ok/../ok/scope.as");
165     TEST("ok/scope.as");
166     TEST("ok/./scope.as");
167     TEST("./ok/scope.as");
168     TEST("./");
169     TEST("/tmp/");
170     TEST("/./tmp/");
171     TEST("../");
172     TEST("/");
173     TEST("/tmp");
174     TEST("/tmp/../usr/");
175 }
176
177
178 char* concat_paths(const char*base, const char*add)
179 {
180     int l1 = strlen(base);
181     int l2 = strlen(add);
182     int pos = 0;
183     char*n = 0;
184     while(l1 && base[l1-1] == '/')
185         l1--;
186     while(pos < l2 && add[pos] == '/')
187         pos++;
188     n = (char*)malloc(l1 + (l2-pos) + 2);
189     memcpy(n,base,l1);
190     n[l1]='/';
191     memcpy(&n[l1+1],&add[pos],l2-pos+1);
192     return n;
193 }
194 char is_absolute(const char*filename) 
195 {
196     if(!filename || !filename[0])
197         return 0;
198     if(filename[0]=='/' || filename[0]=='\\')
199         return 1;
200     if(filename[1]==':' && filename[1]=='/')
201         return 1;
202     if(filename[1]==':' && filename[1]=='\\')
203         return 1;
204     return 0;
205 }
206
207 char*find_file(const char*filename, char error)
208 {
209     include_dir_t*i = current_include_dirs;
210     FILE*fi = 0;
211     if(is_absolute(filename)) {
212         FILE*fi = fopen(filename, "rb");
213         if(fi) {
214             fclose(fi);
215             return strdup(filename);
216         }
217     } else {
218         if(!i && error) {
219             as3_warning("Include directory stack is empty, while looking for file %s", filename);
220         }
221         while(i) {
222             char*p = concat_paths(i->path, filename);
223             fi = fopen(p, "rb");
224             if(fi) {
225                 fclose(fi);
226                 return p;
227             } else {
228                 free(p);
229             }
230             i = i->next;
231         }
232     }
233     if(!error) {
234         return 0;
235     }
236
237     as3_error("Couldn't find file %s", filename);
238     i = current_include_dirs;
239     while(i) {
240         fprintf(stderr, "include dir: %s\n", i->path);
241         i = i->next;
242     }
243     return 0;
244 }
245
246 void enter_file(const char*name, const char*filename, void*state)
247 {
248     if(include_stack_ptr >= MAX_INCLUDE_DEPTH) {
249         as3_error("Includes nested too deeply");
250         exit(1);
251     }
252     include_stack[include_stack_ptr] = state;
253     line_stack[include_stack_ptr] = current_line;
254     column_stack[include_stack_ptr] = current_column;
255     shortfilename_stack[include_stack_ptr] = current_filename_short;
256     longfilename_stack[include_stack_ptr] = current_filename_long;
257     filename_stack[include_stack_ptr] = current_filename;
258     includedir_stack[include_stack_ptr] = current_include_dirs;
259     
260     /*char*dir = get_path(filename);
261     add_include_dir(dir);
262     free(dir);*/
263
264     include_stack_ptr++;
265     
266     dbg("entering file %s", filename);
267
268     current_line=1;
269     current_column=0;
270     current_filename = strdup(name);
271     current_filename_short = strdup(name);
272     current_filename_long = strdup(filename);
273 }
274
275 FILE*enter_file2(const char*name, const char*filename, void*state)
276 {
277     enter_file(name, filename, state);
278     FILE*fi = fopen(filename, "rb");
279     if(!fi) {
280         as3_error("Couldn't find file %s: %s", filename, strerror(errno));
281     }
282     return fi;
283 }
284
285 void* leave_file()
286 {
287     dbg("leaving file %s", current_filename);
288     if(--include_stack_ptr<=0) {
289         return 0;
290     } else {
291         free(current_filename);current_filename = filename_stack[include_stack_ptr];
292         free(current_filename_short);current_filename_short = shortfilename_stack[include_stack_ptr];
293         free(current_filename_long);current_filename_long = longfilename_stack[include_stack_ptr];
294         current_column = column_stack[include_stack_ptr];
295         current_line = line_stack[include_stack_ptr];
296         del_include_dirs(includedir_stack[include_stack_ptr], current_include_dirs);
297         current_include_dirs = includedir_stack[include_stack_ptr];
298         return include_stack[include_stack_ptr];
299     }
300 }