fixed a few mem leaks, enter_file now doesn't do an implicit find_file anymore
[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 typedef struct _include_dir {
53     char*path;
54     struct _include_dir*next;
55 } include_dir_t;
56
57 int current_line=1;
58 int current_column=0;
59 char* current_filename=0;
60 char* current_filename_short=0;
61 include_dir_t* current_include_dirs=0;
62
63 #define MAX_INCLUDE_DEPTH 16
64
65 void*include_stack[MAX_INCLUDE_DEPTH];
66 int line_stack[MAX_INCLUDE_DEPTH];
67 int column_stack[MAX_INCLUDE_DEPTH];
68 char* filename_stack[MAX_INCLUDE_DEPTH];
69 char* shortfilename_stack[MAX_INCLUDE_DEPTH];
70 include_dir_t* includedir_stack[MAX_INCLUDE_DEPTH];
71 int include_stack_ptr = 0;
72
73 void add_include_dir(char*dir)
74 {
75     include_dir_t*d = malloc(sizeof(include_dir_t));
76     memset(d , 0, sizeof(include_dir_t));
77     d->path = strdup(dir);
78     d->next = current_include_dirs;
79     current_include_dirs = d;
80 }
81
82 void del_include_dirs(include_dir_t*d, include_dir_t*d2)
83 {
84     while(d && d!=d2) {
85         include_dir_t*next = d->next;
86         free(d->path);d->path=0;
87         d->next = 0;
88         free(d);
89         d = next;
90     }
91 }
92
93 char*get_path(const char*file)
94 {
95     char*path = strdup(file);
96     char*r1 = strrchr(path, '/');
97     char*r2 = strrchr(path, '\\');
98     if(r1<r2) {
99         *r2=0;
100         return path;
101     } else if(r1>r2) {
102         *r1=0;
103         return path;
104     } else {
105         return strdup(".");
106     }
107 }
108 char* concat_paths(const char*base, const char*add)
109 {
110     int l1 = strlen(base);
111     int l2 = strlen(add);
112     int pos = 0;
113     char*n = 0;
114     while(l1 && base[l1-1] == '/')
115         l1--;
116     while(pos < l2 && add[pos] == '/')
117         pos++;
118     n = (char*)malloc(l1 + (l2-pos) + 2);
119     memcpy(n,base,l1);
120     n[l1]='/';
121     memcpy(&n[l1+1],&add[pos],l2-pos+1);
122     return n;
123 }
124 char is_absolute(char*filename) 
125 {
126     if(!filename || !filename[0])
127         return 0;
128     if(filename[0]=='/' || filename[0]=='\\')
129         return 1;
130     if(filename[1]==':' && filename[1]=='/')
131         return 1;
132     if(filename[1]==':' && filename[1]=='\\')
133         return 1;
134     return 0;
135 }
136
137 char*find_file(char*filename)
138 {
139     include_dir_t*i = current_include_dirs;
140     FILE*fi = 0;
141     if(is_absolute(filename)) {
142         FILE*fi = fopen(filename, "rb");
143         if(fi) {
144             fclose(fi);
145             return strdup(filename);
146         }
147     } else {
148         if(!i) {
149             as3_warning("Include directory stack is empty, while looking for file %s", filename);
150         }
151         while(i) {
152             char*p = concat_paths(i->path, filename);
153             fi = fopen(p, "rb");
154             if(fi) {
155                 fclose(fi);
156                 return p;
157             }
158             i = i->next;
159         }
160     }
161
162     as3_error("Couldn't find file %s", filename);
163     i = current_include_dirs;
164     while(i) {
165         fprintf(stderr, "include dir: %s\n", i->path);
166         i = i->next;
167     }
168     return 0;
169 }
170
171 void enter_file(const char*name, const char*filename, void*state)
172 {
173     if(include_stack_ptr >= MAX_INCLUDE_DEPTH) {
174         as3_error("Includes nested too deeply");
175         exit(1);
176     }
177     include_stack[include_stack_ptr] = state;
178     line_stack[include_stack_ptr] = current_line;
179     column_stack[include_stack_ptr] = current_column;
180     shortfilename_stack[include_stack_ptr] = current_filename_short;
181     filename_stack[include_stack_ptr] = current_filename;
182     includedir_stack[include_stack_ptr] = current_include_dirs;
183     char*dir = get_path(filename);
184     add_include_dir(dir);
185     free(dir);
186     include_stack_ptr++;
187     
188     dbg("entering file %s", filename);
189
190     current_line=1;
191     current_column=0;
192     current_filename = strdup(filename);
193     current_filename_short = strdup(name);
194 }
195
196 FILE*enter_file2(const char*name, const char*filename, void*state)
197 {
198     enter_file(name, filename, state);
199     FILE*fi = fopen(filename, "rb");
200     if(!fi) {
201         as3_error("Couldn't find file %s: %s", filename, strerror(errno));
202     }
203     return fi;
204 }
205
206 void* leave_file()
207 {
208     dbg("leaving file %s", current_filename);
209     if(--include_stack_ptr<=0) {
210         return 0;
211     } else {
212         free(current_filename);current_filename = filename_stack[include_stack_ptr];
213         free(current_filename_short);current_filename_short = shortfilename_stack[include_stack_ptr];
214         current_column = column_stack[include_stack_ptr];
215         current_line = line_stack[include_stack_ptr];
216         del_include_dirs(includedir_stack[include_stack_ptr], current_include_dirs);
217         current_include_dirs = includedir_stack[include_stack_ptr];
218         return include_stack[include_stack_ptr];
219     }
220 }