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