implemented conditional compilation
[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 "tokenizer.h"
29
30 static int verbose = 0;
31 static void dbg(const char*format, ...)
32 {
33     char buf[1024];
34     int l;
35     va_list arglist;
36     if(!verbose)
37         return;
38     va_start(arglist, format);
39     vsprintf(buf, format, arglist);
40     va_end(arglist);
41     l = strlen(buf);
42     while(l && buf[l-1]=='\n') {
43         buf[l-1] = 0;
44         l--;
45     }
46     printf("(includefilehandler) ");
47     printf("%s\n", buf);
48     fflush(stdout);
49 }
50
51
52 int current_line=1;
53 int current_column=0;
54 char* current_filename=0;
55 char* current_filename_short=0;
56 char* current_filename_long=0;
57 include_dir_t* current_include_dirs=0;
58
59 #define MAX_INCLUDE_DEPTH 16
60
61 void*include_stack[MAX_INCLUDE_DEPTH];
62 int line_stack[MAX_INCLUDE_DEPTH];
63 int column_stack[MAX_INCLUDE_DEPTH];
64 char* filename_stack[MAX_INCLUDE_DEPTH];
65 char* shortfilename_stack[MAX_INCLUDE_DEPTH];
66 char* longfilename_stack[MAX_INCLUDE_DEPTH];
67 include_dir_t* includedir_stack[MAX_INCLUDE_DEPTH];
68 int include_stack_ptr = 0;
69
70 void add_include_dir(char*dir)
71 {
72     include_dir_t*d = malloc(sizeof(include_dir_t));
73     memset(d , 0, sizeof(include_dir_t));
74     d->path = strdup(dir);
75     d->next = current_include_dirs;
76     current_include_dirs = d;
77 }
78
79 void del_include_dirs(include_dir_t*d, include_dir_t*d2)
80 {
81     while(d && d!=d2) {
82         include_dir_t*next = d->next;
83         free(d->path);d->path=0;
84         d->next = 0;
85         free(d);
86         d = next;
87     }
88 }
89
90 char*get_path(const char*file)
91 {
92     char*path = strdup(file);
93     char*r1 = strrchr(path, '/');
94     char*r2 = strrchr(path, '\\');
95     if(r1<r2) {
96         *r2=0;
97         return path;
98     } else if(r1>r2) {
99         *r1=0;
100         return path;
101     } else {
102         return strdup(".");
103     }
104 }
105 char* normalize_path(const char*path)
106 {
107     char*n = 0, *d = 0;
108     if(path[0] != '/') {
109         char buf[512];
110         char*c = getcwd(buf,512);
111         int l = strlen(buf);
112         d = n = malloc(l+strlen(path)+10);
113         strcpy(n, buf);d += l;
114         if(!l || n[l-1]!='/') {
115             *d='/';d++;
116         }
117     } else {
118         d = n = strdup(path);
119     }
120     const char*s=path;
121     char init = 1;
122
123     while(*s) {
124         if(init && s[0] == '.' && (s[1]=='/' || s[1]=='\0')) {
125             if(!s[1]) break;
126             s+=2;
127             init=1;
128             continue;
129         }
130         if(init && s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2]=='\0')) {
131             // step one down
132             char*last = 0;
133             if(d<=n) 
134                 return 0;
135             *--d = 0;
136             if(!(last=strrchr(n, '/'))) {
137                 return 0;
138             }
139             d = last+1;
140             if(!s[2]) break;
141             s+=3;
142             init=1;
143             continue;
144         }
145
146         *d = *s;
147         if(*s=='/') init=1;
148         else init=0;
149         d++;s++;
150     }
151     if(d!=n && d[-1]=='/') 
152         d--;
153     *d = 0;
154     return n;
155 }
156 static void testnormalize()
157 {
158 #define TEST(x) {printf("%s -> %s\n", (x), normalize_path(x));}
159     TEST(".");
160     TEST("../as3");
161     TEST("../as3/");
162     TEST("../as3/parser.y");
163     TEST("../as3/ok/../ok/scope.as");
164     TEST("ok/scope.as");
165     TEST("ok/./scope.as");
166     TEST("./ok/scope.as");
167     TEST("./");
168     TEST("/tmp/");
169     TEST("/./tmp/");
170     TEST("../");
171     TEST("/");
172     TEST("/tmp");
173     TEST("/tmp/../usr/");
174 }
175
176
177 char* concat_paths(const char*base, const char*add)
178 {
179     int l1 = strlen(base);
180     int l2 = strlen(add);
181     int pos = 0;
182     char*n = 0;
183     while(l1 && base[l1-1] == '/')
184         l1--;
185     while(pos < l2 && add[pos] == '/')
186         pos++;
187     n = (char*)malloc(l1 + (l2-pos) + 2);
188     memcpy(n,base,l1);
189     n[l1]='/';
190     memcpy(&n[l1+1],&add[pos],l2-pos+1);
191     return n;
192 }
193 char is_absolute(const char*filename) 
194 {
195     if(!filename || !filename[0])
196         return 0;
197     if(filename[0]=='/' || filename[0]=='\\')
198         return 1;
199     if(filename[1]==':' && filename[1]=='/')
200         return 1;
201     if(filename[1]==':' && filename[1]=='\\')
202         return 1;
203     return 0;
204 }
205
206 char*find_file(const char*filename, char error)
207 {
208     include_dir_t*i = current_include_dirs;
209     FILE*fi = 0;
210     if(is_absolute(filename)) {
211         FILE*fi = fopen(filename, "rb");
212         if(fi) {
213             fclose(fi);
214             return strdup(filename);
215         }
216     } else {
217         if(!i && error) {
218             as3_warning("Include directory stack is empty, while looking for file %s", filename);
219         }
220         while(i) {
221             char*p = concat_paths(i->path, filename);
222             fi = fopen(p, "rb");
223             if(fi) {
224                 fclose(fi);
225                 return p;
226             } else {
227                 free(p);
228             }
229             i = i->next;
230         }
231     }
232     if(!error) {
233         return 0;
234     }
235
236     as3_error("Couldn't find file %s", filename);
237     i = current_include_dirs;
238     while(i) {
239         fprintf(stderr, "include dir: %s\n", i->path);
240         i = i->next;
241     }
242     return 0;
243 }
244
245 void enter_file(const char*name, const char*filename, void*state)
246 {
247     if(include_stack_ptr >= MAX_INCLUDE_DEPTH) {
248         as3_error("Includes nested too deeply");
249         exit(1);
250     }
251     include_stack[include_stack_ptr] = state;
252     line_stack[include_stack_ptr] = current_line;
253     column_stack[include_stack_ptr] = current_column;
254     shortfilename_stack[include_stack_ptr] = current_filename_short;
255     longfilename_stack[include_stack_ptr] = current_filename_long;
256     filename_stack[include_stack_ptr] = current_filename;
257     includedir_stack[include_stack_ptr] = current_include_dirs;
258     
259     /*char*dir = get_path(filename);
260     add_include_dir(dir);
261     free(dir);*/
262
263     include_stack_ptr++;
264     
265     dbg("entering file %s", filename);
266
267     current_line=1;
268     current_column=0;
269     current_filename = strdup(name);
270     current_filename_short = strdup(name);
271     current_filename_long = strdup(filename);
272 }
273
274 FILE*enter_file2(const char*name, const char*filename, void*state)
275 {
276     enter_file(name, filename, state);
277     FILE*fi = fopen(filename, "rb");
278     if(!fi) {
279         as3_error("Couldn't find file %s: %s", filename, strerror(errno));
280     }
281     return fi;
282 }
283
284 void* leave_file()
285 {
286     dbg("leaving file %s", current_filename);
287     if(--include_stack_ptr<=0) {
288         return 0;
289     } else {
290         free(current_filename);current_filename = filename_stack[include_stack_ptr];
291         free(current_filename_short);current_filename_short = shortfilename_stack[include_stack_ptr];
292         free(current_filename_long);current_filename_long = longfilename_stack[include_stack_ptr];
293         current_column = column_stack[include_stack_ptr];
294         current_line = line_stack[include_stack_ptr];
295         del_include_dirs(includedir_stack[include_stack_ptr], current_include_dirs);
296         current_include_dirs = includedir_stack[include_stack_ptr];
297         return include_stack[include_stack_ptr];
298     }
299 }