handle filesystems where lowercase(file)==file more gracefully
[swftools.git] / lib / as3 / files.c
index 580c9db..f6284dd 100644 (file)
@@ -25,7 +25,9 @@
 #include <memory.h>
 #include <errno.h>
 #include "files.h"
+#include "common.h"
 #include "tokenizer.h"
+#include "../os.h"
 
 static int verbose = 0;
 static void dbg(const char*format, ...)
@@ -36,7 +38,7 @@ static void dbg(const char*format, ...)
     if(!verbose)
        return;
     va_start(arglist, format);
-    vsprintf(buf, format, arglist);
+    vsnprintf(buf, sizeof(buf)-1, format, arglist);
     va_end(arglist);
     l = strlen(buf);
     while(l && buf[l-1]=='\n') {
@@ -49,15 +51,11 @@ static void dbg(const char*format, ...)
 }
 
 
-typedef struct _include_dir {
-    char*path;
-    struct _include_dir*next;
-} include_dir_t;
-
 int current_line=1;
 int current_column=0;
 char* current_filename=0;
 char* current_filename_short=0;
+char* current_filename_long=0;
 include_dir_t* current_include_dirs=0;
 
 #define MAX_INCLUDE_DEPTH 16
@@ -67,6 +65,7 @@ int line_stack[MAX_INCLUDE_DEPTH];
 int column_stack[MAX_INCLUDE_DEPTH];
 char* filename_stack[MAX_INCLUDE_DEPTH];
 char* shortfilename_stack[MAX_INCLUDE_DEPTH];
+char* longfilename_stack[MAX_INCLUDE_DEPTH];
 include_dir_t* includedir_stack[MAX_INCLUDE_DEPTH];
 int include_stack_ptr = 0;
 
@@ -105,36 +104,133 @@ char*get_path(const char*file)
         return strdup(".");
     }
 }
+
+char is_absolute(const char*filename) 
+{
+    if(!filename || !filename[0])
+        return 0;
+    if(filename[0]=='/' || filename[0]=='\\')
+        return 1;
+    if(filename[1]==':' && filename[2]=='/')
+        return 1;
+    if(filename[1]==':' && filename[2]=='\\')
+        return 1;
+    return 0;
+}
+
+char* filename_to_lowercase(const char*name)
+{
+    char*n = strdup(name);
+    //char*x1 = strrchr(name, '/');
+    //char*x2 = strrchr(name, '\\');
+    char*s = n;
+    //if(x1+1>s) s=x1+1;
+    //if(x2+1>s) s=x2+1;
+    while(*s) {
+       /* FIXME: what we probably should do here is use libc's tolower().
+          I don't really know yet, though, how Windows (or MacOS X) handles
+          lowercasing of Unicode filenames */
+       if(*s>='A' && *s<='Z')
+           *s += 'a'-'A';
+       s++;
+    }
+    return n;
+}
+
+char* normalize_path(const char*path)
+{
+    char*n = 0, *d = 0;
+    if(!is_absolute(path)) {
+        char buf[512];
+        char*c = getcwd(buf,512);
+        int l = strlen(buf);
+        d = n = malloc(l+strlen(path)+10);
+        strcpy(n, buf);d += l;
+        if(!l || n[l-1]!=path_seperator) {
+            *d=path_seperator;d++;
+        }
+    } else {
+        d = n = strdup(path);
+    }
+    const char*s=path;
+    char init = 1;
+
+    while(*s) {
+        if(init && s[0] == '.' && (s[1]==path_seperator || s[1]=='\0')) {
+            if(!s[1]) break;
+            s+=2;
+            init=1;
+            continue;
+        }
+        if(init && s[0] == '.' && s[1] == '.' && (s[2] == path_seperator || s[2]=='\0')) {
+            // step one down
+            char*last = 0;
+            if(d<=n) 
+                return 0;
+            *--d = 0;
+            if(!(last=strrchr(n, path_seperator))) {
+                return 0;
+            }
+            d = last+1;
+            if(!s[2]) break;
+            s+=3;
+            init=1;
+            continue;
+        }
+
+        *d = *s;
+        if(*s==path_seperator) init=1;
+        else init=0;
+        d++;s++;
+    }
+    if(d!=n && d[-1]==path_seperator) 
+        d--;
+    *d = 0;
+#ifdef LOWERCASE_UPPERCASE
+    n = filename_to_lowercase(n);
+#endif
+    
+    return n;
+}
+static void testnormalize()
+{
+#define TEST(x) {printf("%s -> %s\n", (x), normalize_path(x));}
+    TEST(".");
+    TEST("../as3");
+    TEST("../as3/");
+    TEST("../as3/parser.y");
+    TEST("../as3/ok/../ok/scope.as");
+    TEST("ok/scope.as");
+    TEST("ok/./scope.as");
+    TEST("./ok/scope.as");
+    TEST("./");
+    TEST("/tmp/");
+    TEST("/./tmp/");
+    TEST("../");
+    TEST("/");
+    TEST("/tmp");
+    TEST("/tmp/../usr/");
+}
+
 char* concat_paths(const char*base, const char*add)
 {
     int l1 = strlen(base);
     int l2 = strlen(add);
     int pos = 0;
     char*n = 0;
-    while(l1 && base[l1-1] == '/')
+    while(l1 && base[l1-1] == path_seperator)
        l1--;
-    while(pos < l2 && add[pos] == '/')
+    while(pos < l2 && add[pos] == path_seperator)
        pos++;
     n = (char*)malloc(l1 + (l2-pos) + 2);
     memcpy(n,base,l1);
-    n[l1]='/';
+    n[l1]=path_seperator;
     memcpy(&n[l1+1],&add[pos],l2-pos+1);
     return n;
 }
-char is_absolute(char*filename) 
-{
-    if(!filename || !filename[0])
-        return 0;
-    if(filename[0]=='/' || filename[0]=='\\')
-        return 1;
-    if(filename[1]==':' && filename[1]=='/')
-        return 1;
-    if(filename[1]==':' && filename[1]=='\\')
-        return 1;
-    return 0;
-}
 
-char*find_file(char*filename)
+char*find_file(const char*filename, char error)
 {
     include_dir_t*i = current_include_dirs;
     FILE*fi = 0;
@@ -145,7 +241,7 @@ char*find_file(char*filename)
             return strdup(filename);
         }
     } else {
-        if(!i) {
+        if(!i && error) {
             as3_warning("Include directory stack is empty, while looking for file %s", filename);
         }
         while(i) {
@@ -154,10 +250,15 @@ char*find_file(char*filename)
             if(fi) {
                 fclose(fi);
                 return p;
+            } else {
+                free(p);
             }
             i = i->next;
         }
     }
+    if(!error) {
+        return 0;
+    }
 
     as3_error("Couldn't find file %s", filename);
     i = current_include_dirs;
@@ -178,19 +279,23 @@ void enter_file(const char*name, const char*filename, void*state)
     line_stack[include_stack_ptr] = current_line;
     column_stack[include_stack_ptr] = current_column;
     shortfilename_stack[include_stack_ptr] = current_filename_short;
+    longfilename_stack[include_stack_ptr] = current_filename_long;
     filename_stack[include_stack_ptr] = current_filename;
     includedir_stack[include_stack_ptr] = current_include_dirs;
-    char*dir = get_path(filename);
+    
+    /*char*dir = get_path(filename);
     add_include_dir(dir);
-    free(dir);
+    free(dir);*/
+
     include_stack_ptr++;
     
     dbg("entering file %s", filename);
 
     current_line=1;
     current_column=0;
-    current_filename = strdup(filename);
+    current_filename = strdup(name);
     current_filename_short = strdup(name);
+    current_filename_long = strdup(filename);
 }
 
 FILE*enter_file2(const char*name, const char*filename, void*state)
@@ -211,6 +316,7 @@ void* leave_file()
     } else {
         free(current_filename);current_filename = filename_stack[include_stack_ptr];
         free(current_filename_short);current_filename_short = shortfilename_stack[include_stack_ptr];
+        free(current_filename_long);current_filename_long = longfilename_stack[include_stack_ptr];
         current_column = column_stack[include_stack_ptr];
         current_line = line_stack[include_stack_ptr];
         del_include_dirs(includedir_stack[include_stack_ptr], current_include_dirs);
@@ -218,3 +324,4 @@ void* leave_file()
         return include_stack[include_stack_ptr];
     }
 }
+