]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' into cooking
authorWolfgang Bumiller <blub@speed.at>
Wed, 20 Feb 2013 22:08:58 +0000 (23:08 +0100)
committerWolfgang Bumiller <blub@speed.at>
Wed, 20 Feb 2013 22:08:58 +0000 (23:08 +0100)
22 files changed:
.gitignore
Makefile
ast.c
ast.h
code.c
conout.c
exec.c
file.c [deleted file]
fs.c [new file with mode: 0644]
ftepp.c
gmqcc.h
lexer.c
lexer.h
main.c
opts.c
pak.c [new file with mode: 0644]
parser.c
test.c
tests/aliases.qc [new file with mode: 0644]
tests/aliases.tmpl [new file with mode: 0644]
tests/pops.qc [new file with mode: 0644]
tests/pops.tmpl [new file with mode: 0644]

index 8ccf6a5aa127fe88c83f9faf22af1e1703ddc857..596972e8cb5100df4a55eda4523fa440b1a2681d 100644 (file)
@@ -9,8 +9,8 @@ qcvm
 gmqcc
 
 distro/arch/*
-!distro/arch/git/PKGBUILD
-!distro/arch/release/PKGBUILD
-!distro/arch/bsd-release/PKGBUILD
-!distro/arch/bsd-git/PKGBUILD
+!distro/archlinux/git/PKGBUILD
+!distro/archlinux/release/PKGBUILD
+!distro/archbsd/release/PKGBUILD
+!distro/archbsd/git/PKGBUILD
 !distro/arch/this/Makefile
index e31c0987124ba0596fd39040d18a920c312cabfe..307673ce9afbde3b006a61c8e74f79359f0de772 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,14 +9,14 @@ CYGWIN  = $(findstring CYGWIN,  $(UNAME))
 MINGW   = $(findstring MINGW32, $(UNAME))
 
 CC     ?= clang
-CFLAGS += -Wall -Wextra -I. -fno-strict-aliasing -fsigned-char -Wno-overlength-strings
+CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing -fsigned-char
 ifneq ($(shell git describe --always 2>/dev/null),)
     CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\""
 endif
 #turn on tons of warnings if clang is present
 # but also turn off the STUPID ONES
 ifeq ($(CC), clang)
-       CFLAGS +=                               \
+       CFLAGS +=                              \
                -Weverything                       \
                -Wno-padded                        \
                -Wno-format-nonliteral             \
@@ -41,10 +41,11 @@ ifeq ($(track), no)
     CFLAGS += -DNOTRACK
 endif
 
-OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o file.o utf8.o correct.o
-OBJ_T = test.o util.o conout.o file.o
-OBJ_C = main.o lexer.o parser.o file.o
-OBJ_X = exec-standalone.o util.o conout.o file.o
+OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o
+OBJ_P = util.o fs.o conout.o opts.o pak.o
+OBJ_T = test.o util.o conout.o fs.o
+OBJ_C = main.o lexer.o parser.o fs.o
+OBJ_X = exec-standalone.o util.o conout.o fs.o
 
 ifneq ("$(CYGWIN)", "")
        #nullify the common variables that
@@ -56,6 +57,7 @@ ifneq ("$(CYGWIN)", "")
        QCVM      = qcvm.exe
        GMQCC     = gmqcc.exe
        TESTSUITE = testsuite.exe
+       PAK       = pak.exe
 else
 ifneq ("$(MINGW)", "")
        #nullify the common variables that
@@ -67,6 +69,7 @@ ifneq ("$(MINGW)", "")
        QCVM      = qcvm.exe
        GMQCC     = gmqcc.exe
        TESTSUITE = testsuite.exe
+       PAK       = pak.exe
 else
        #arm support for linux .. we need to allow unaligned accesses
        #to memory otherwise we just segfault everywhere
@@ -77,6 +80,7 @@ else
        QCVM      = qcvm
        GMQCC     = gmqcc
        TESTSUITE = testsuite
+       PAK       = pak
 endif
 endif
 
@@ -148,15 +152,18 @@ $(GMQCC): $(OBJ_C) $(OBJ_D)
 $(TESTSUITE): $(OBJ_T)
        $(CC) -o $@ $^ $(CFLAGS)
 
-all: $(GMQCC) $(QCVM) $(TESTSUITE)
+$(PAK): $(OBJ_P)
+       $(CC) -o $@ $^ $(CFLAGS)
+
+all: $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK)
 
 check: all
        @ ./$(TESTSUITE)
-test: check
+test: all
        @ ./$(TESTSUITE)
 
 clean:
-       rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) *.dat
+       rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat
 
 splint:
        @  splint $(SPLINTFLAGS) *.c *.h
@@ -170,6 +177,8 @@ depend:
                $(subst .o,.c,$(OBJ_C))
        @makedepend -a -Y -w 65536 2> /dev/null \
                $(subst .o,.c,$(OBJ_X))
+       @makedepend -a -Y -w 65536 2> /dev/null \
+               $(subst .o,.c,$(OBJ_P))
 
 #install rules
 install: install-gmqcc install-qcvm install-doc
@@ -199,20 +208,20 @@ ir.o: gmqcc.h opts.def ir.h
 conout.o: gmqcc.h opts.def
 ftepp.o: gmqcc.h opts.def lexer.h
 opts.o: gmqcc.h opts.def
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
 utf8.o: gmqcc.h opts.def
 correct.o: gmqcc.h opts.def
 
 test.o: gmqcc.h opts.def
 util.o: gmqcc.h opts.def
 conout.o: gmqcc.h opts.def
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
 
 main.o: gmqcc.h opts.def lexer.h
 lexer.o: gmqcc.h opts.def lexer.h
 parser.o: gmqcc.h opts.def lexer.h ast.h ir.h
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
 
 util.o: gmqcc.h opts.def
 conout.o: gmqcc.h opts.def
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
diff --git a/ast.c b/ast.c
index 294c13b42dc175f369db95f6101868041b43a670..c0c92fbe3ab122f7c15fa0b0a588b54f7f549c0a 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -103,10 +103,6 @@ ast_value* ast_value_copy(const ast_value *self)
     ast_value *cp = ast_value_new(self->expression.node.context, self->name, self->expression.vtype);
     if (self->expression.next) {
         cp->expression.next = ast_type_copy(self->expression.node.context, self->expression.next);
-        if (!cp->expression.next) {
-            ast_value_delete(cp);
-            return NULL;
-        }
     }
     fromex   = &self->expression;
     selfex = &cp->expression;
@@ -114,16 +110,12 @@ ast_value* ast_value_copy(const ast_value *self)
     selfex->flags    = fromex->flags;
     for (i = 0; i < vec_size(fromex->params); ++i) {
         ast_value *v = ast_value_copy(fromex->params[i]);
-        if (!v) {
-            ast_value_delete(cp);
-            return NULL;
-        }
         vec_push(selfex->params, v);
     }
     return cp;
 }
 
-bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
+void ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
 {
     size_t i;
     const ast_expression_common *fromex;
@@ -131,8 +123,6 @@ bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
     self->expression.vtype = other->expression.vtype;
     if (other->expression.next) {
         self->expression.next = (ast_expression*)ast_type_copy(ast_ctx(self), other->expression.next);
-        if (!self->expression.next)
-            return false;
     }
     fromex   = &other->expression;
     selfex = &self->expression;
@@ -140,11 +130,8 @@ bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other)
     selfex->flags    = fromex->flags;
     for (i = 0; i < vec_size(fromex->params); ++i) {
         ast_value *v = ast_value_copy(fromex->params[i]);
-        if (!v)
-            return false;
         vec_push(selfex->params, v);
     }
-    return true;
 }
 
 static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype)
@@ -178,13 +165,7 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
 
         selfex->vtype = fromex->vtype;
         if (fromex->next)
-        {
             selfex->next = ast_type_copy(ctx, fromex->next);
-            if (!selfex->next) {
-                ast_expression_delete_full(self);
-                return NULL;
-            }
-        }
         else
             selfex->next = NULL;
 
@@ -192,10 +173,6 @@ ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
         selfex->flags    = fromex->flags;
         for (i = 0; i < vec_size(fromex->params); ++i) {
             ast_value *v = ast_value_copy(fromex->params[i]);
-            if (!v) {
-                ast_expression_delete_full(self);
-                return NULL;
-            }
             vec_push(selfex->params, v);
         }
 
@@ -429,13 +406,17 @@ ast_binary* ast_binary_new(lex_ctx ctx, int op,
     else
         self->expression.vtype = left->expression.vtype;
 
+    /* references all */
+    self->refs = AST_REF_ALL;
+
     return self;
 }
 
 void ast_binary_delete(ast_binary *self)
 {
-    ast_unref(self->left);
-    ast_unref(self->right);
+    if (self->refs & AST_REF_LEFT)  ast_unref(self->left);
+    if (self->refs & AST_REF_RIGHT) ast_unref(self->right);
+
     ast_expression_delete((ast_expression*)self);
     mem_d(self);
 }
@@ -455,11 +436,7 @@ ast_binstore* ast_binstore_new(lex_ctx ctx, int storop, int op,
 
     self->keep_dest = false;
 
-    if (!ast_type_adopt(self, left)) {
-        ast_delete(self);
-        return NULL;
-    }
-
+    ast_type_adopt(self, left);
     return self;
 }
 
@@ -545,11 +522,7 @@ ast_entfield* ast_entfield_new_force(lex_ctx ctx, ast_expression *entity, ast_ex
     ast_propagate_effects(self, entity);
     ast_propagate_effects(self, field);
 
-    if (!ast_type_adopt(self, outtype)) {
-        ast_entfield_delete(self);
-        return NULL;
-    }
-
+    ast_type_adopt(self, outtype);
     return self;
 }
 
@@ -641,10 +614,7 @@ ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_exp
     ast_propagate_effects(self, array);
     ast_propagate_effects(self, index);
 
-    if (!ast_type_adopt(self, outtype)) {
-        ast_array_index_delete(self);
-        return NULL;
-    }
+    ast_type_adopt(self, outtype);
     if (array->expression.vtype == TYPE_FIELD && outtype->expression.vtype == TYPE_ARRAY) {
         if (self->expression.vtype != TYPE_ARRAY) {
             compile_error(ast_ctx(self), "array_index node on type");
@@ -721,10 +691,7 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *
 
     if (ontrue->expression.vtype == TYPE_NIL)
         exprtype = onfalse;
-    if (!ast_type_adopt(self, exprtype)) {
-        ast_ternary_delete(self);
-        return NULL;
-    }
+    ast_type_adopt(self, exprtype);
 
     return self;
 }
@@ -978,10 +945,7 @@ ast_store* ast_store_new(lex_ctx ctx, int op,
     self->dest = dest;
     self->source = source;
 
-    if (!ast_type_adopt(self, dest)) {
-        ast_delete(self);
-        return NULL;
-    }
+    ast_type_adopt(self, dest);
 
     return self;
 }
@@ -1015,10 +979,7 @@ bool ast_block_add_expr(ast_block *self, ast_expression *e)
         ast_delete(self->expression.next);
         self->expression.next = NULL;
     }
-    if (!ast_type_adopt(self, e)) {
-        compile_error(ast_ctx(self), "internal error: failed to adopt type");
-        return false;
-    }
+    ast_type_adopt(self, e);
     return true;
 }
 
@@ -1044,13 +1005,11 @@ void ast_block_delete(ast_block *self)
     mem_d(self);
 }
 
-bool ast_block_set_type(ast_block *self, ast_expression *from)
+void ast_block_set_type(ast_block *self, ast_expression *from)
 {
     if (self->expression.next)
         ast_delete(self->expression.next);
-    if (!ast_type_adopt(self, from))
-        return false;
-    return true;
+    ast_type_adopt(self, from);
 }
 
 ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
@@ -2228,9 +2187,11 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva
 
     if (!lvalue && self->expression.outr) {
         *out = self->expression.outr;
+        return true;
     }
     if (lvalue && self->expression.outl) {
         *out = self->expression.outl;
+        return true;
     }
 
     if (!ast_istype(self->array, ast_value)) {
diff --git a/ast.h b/ast.h
index 94f388e596a36ee395788a29585799d83a49546d..9b554214361258d9ddebf140e5107ccdaee7466f 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -151,6 +151,7 @@ typedef struct
 #define AST_FLAG_DEPRECATED   (1<<4)
 #define AST_FLAG_INCLUDE_DEF  (1<<5)
 #define AST_FLAG_IS_VARARG    (1<<6)
+#define AST_FLAG_ALIAS        (1<<7)
 #define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
 
 /* Value
@@ -215,9 +216,16 @@ void ast_value_params_add(ast_value*, ast_value*);
 bool ast_compare_type(ast_expression *a, ast_expression *b);
 ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex);
 #define ast_type_adopt(a, b) ast_type_adopt_impl((ast_expression*)(a), (ast_expression*)(b))
-bool ast_type_adopt_impl(ast_expression *self, const ast_expression *other);
+void ast_type_adopt_impl(ast_expression *self, const ast_expression *other);
 void ast_type_to_string(ast_expression *e, char *buf, size_t bufsize);
 
+typedef enum ast_binary_ref_s {
+    AST_REF_LEFT  = 1 << 1,
+    AST_REF_RIGHT = 1 << 2,
+    AST_REF_ALL   = (AST_REF_LEFT | AST_REF_RIGHT)
+} ast_binary_ref;
+
+
 /* Binary
  *
  * A value-returning binary expression.
@@ -229,6 +237,8 @@ struct ast_binary_s
     int             op;
     ast_expression *left;
     ast_expression *right;
+    ast_binary_ref  refs;
+    
 };
 ast_binary* ast_binary_new(lex_ctx    ctx,
                            int        op,
@@ -597,7 +607,7 @@ struct ast_block_s
 };
 ast_block* ast_block_new(lex_ctx ctx);
 void ast_block_delete(ast_block*);
-bool ast_block_set_type(ast_block*, ast_expression *from);
+void ast_block_set_type(ast_block*, ast_expression *from);
 
 bool ast_block_codegen(ast_block*, ast_function*, bool lvalue, ir_value**);
 void ast_block_collect(ast_block*, ast_expression*);
diff --git a/code.c b/code.c
index 43a34c9de78aec26749824fc03d436b502538c5c..5728a8db425f7b724a44717ba8510b400654637e 100644 (file)
--- a/code.c
+++ b/code.c
@@ -171,7 +171,7 @@ bool code_write(const char *filename, const char *lnofile) {
     if (lnofile) {
         uint32_t version = 1;
 
-        fp = file_open(lnofile, "wb");
+        fp = fs_file_open(lnofile, "wb");
         if (!fp)
             return false;
 
@@ -179,34 +179,34 @@ bool code_write(const char *filename, const char *lnofile) {
         util_endianswap(code_linenums, vec_size(code_linenums), sizeof(code_linenums[0]));
 
 
-        if (file_write("LNOF",                          4,                                      1,                       fp) != 1 ||
-            file_write(&version,                        sizeof(version),                        1,                       fp) != 1 ||
-            file_write(&code_header.defs.length,        sizeof(code_header.defs.length),        1,                       fp) != 1 ||
-            file_write(&code_header.globals.length,     sizeof(code_header.globals.length),     1,                       fp) != 1 ||
-            file_write(&code_header.fields.length,      sizeof(code_header.fields.length),      1,                       fp) != 1 ||
-            file_write(&code_header.statements.length,  sizeof(code_header.statements.length),  1,                       fp) != 1 ||
-            file_write(code_linenums,                   sizeof(code_linenums[0]),               vec_size(code_linenums), fp) != vec_size(code_linenums))
+        if (fs_file_write("LNOF",                          4,                                      1,                       fp) != 1 ||
+            fs_file_write(&version,                        sizeof(version),                        1,                       fp) != 1 ||
+            fs_file_write(&code_header.defs.length,        sizeof(code_header.defs.length),        1,                       fp) != 1 ||
+            fs_file_write(&code_header.globals.length,     sizeof(code_header.globals.length),     1,                       fp) != 1 ||
+            fs_file_write(&code_header.fields.length,      sizeof(code_header.fields.length),      1,                       fp) != 1 ||
+            fs_file_write(&code_header.statements.length,  sizeof(code_header.statements.length),  1,                       fp) != 1 ||
+            fs_file_write(code_linenums,                   sizeof(code_linenums[0]),               vec_size(code_linenums), fp) != vec_size(code_linenums))
         {
             con_err("failed to write lno file\n");
         }
 
-        file_close(fp);
+        fs_file_close(fp);
         fp = NULL;
     }
 
-    fp = file_open(filename, "wb");
+    fp = fs_file_open(filename, "wb");
     if (!fp)
         return false;
 
-    if (1                         != file_write(&code_header,    sizeof(prog_header)           , 1                        , fp) ||
-        vec_size(code_statements) != file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) ||
-        vec_size(code_defs)       != file_write(code_defs,       sizeof(prog_section_def)      , vec_size(code_defs)      , fp) ||
-        vec_size(code_fields)     != file_write(code_fields,     sizeof(prog_section_field)    , vec_size(code_fields)    , fp) ||
-        vec_size(code_functions)  != file_write(code_functions,  sizeof(prog_section_function) , vec_size(code_functions) , fp) ||
-        vec_size(code_globals)    != file_write(code_globals,    sizeof(int32_t)               , vec_size(code_globals)   , fp) ||
-        vec_size(code_chars)      != file_write(code_chars,      1                             , vec_size(code_chars)     , fp))
+    if (1                         != fs_file_write(&code_header,    sizeof(prog_header)           , 1                        , fp) ||
+        vec_size(code_statements) != fs_file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) ||
+        vec_size(code_defs)       != fs_file_write(code_defs,       sizeof(prog_section_def)      , vec_size(code_defs)      , fp) ||
+        vec_size(code_fields)     != fs_file_write(code_fields,     sizeof(prog_section_field)    , vec_size(code_fields)    , fp) ||
+        vec_size(code_functions)  != fs_file_write(code_functions,  sizeof(prog_section_function) , vec_size(code_functions) , fp) ||
+        vec_size(code_globals)    != fs_file_write(code_globals,    sizeof(int32_t)               , vec_size(code_globals)   , fp) ||
+        vec_size(code_chars)      != fs_file_write(code_chars,      1                             , vec_size(code_chars)     , fp))
     {
-        file_close(fp);
+        fs_file_close(fp);
         return false;
     }
 
@@ -273,6 +273,6 @@ bool code_write(const char *filename, const char *lnofile) {
     vec_free(code_chars);
     util_htdel(code_string_cache);
 
-    file_close(fp);
+    fs_file_close(fp);
     return true;
 }
index 81cf48135433264abeffa2e659ab1d7915dc6f00..8613ece127e502c01123dfb00e6a96ca525b6537 100644 (file)
--- a/conout.c
+++ b/conout.c
@@ -168,7 +168,7 @@ static int win_fputs(FILE *h, const char *str) {
                 state    = -1;
             }
         } else {
-            file_putc(h, *str);
+            fs_file_putc(h, *str);
             length ++;
         }
         str++;
@@ -219,7 +219,7 @@ static int con_write(FILE *handle, const char *fmt, va_list va) {
         char data[4096];
         memset(data, 0, sizeof(data));
         vsnprintf(data, sizeof(data), fmt, va);
-        ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(handle, data) : file_puts(handle, data);
+        ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(handle, data) : fs_file_puts(handle, data);
     }
     #endif
     return ln;
@@ -231,9 +231,9 @@ static int con_write(FILE *handle, const char *fmt, va_list va) {
 
 void con_close() {
     if (!GMQCC_IS_DEFINE(console.handle_err))
-        file_close(console.handle_err);
+        fs_file_close(console.handle_err);
     if (!GMQCC_IS_DEFINE(console.handle_out))
-        file_close(console.handle_out);
+        fs_file_close(console.handle_out);
 }
 
 void con_color(int state) {
@@ -275,12 +275,12 @@ int con_change(const char *out, const char *err) {
     if (GMQCC_IS_DEFINE(out)) {
         console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
         con_enablecolor();
-    } else if (!(console.handle_out = file_open(out, "w"))) return 0;
+    } else if (!(console.handle_out = fs_file_open(out, "w"))) return 0;
 
     if (GMQCC_IS_DEFINE(err)) {
         console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr;
         con_enablecolor();
-    } else if (!(console.handle_err = file_open(err, "w"))) return 0;
+    } else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
 
     /* no buffering */
     setvbuf(console.handle_out, NULL, _IONBF, 0);
diff --git a/exec.c b/exec.c
index d5448153072039287445a609555ad11fed39bf84..f44bd6295f8bd35f409f31519caf857041286619 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -55,26 +55,26 @@ qc_program* prog_load(const char *filename, bool skipversion)
 {
     qc_program   *prog;
     prog_header   header;
-    FILE         *file   = file_open(filename, "rb");
+    FILE         *file   = fs_file_open(filename, "rb");
 
     if (!file)
         return NULL;
 
-    if (file_read(&header, sizeof(header), 1, file) != 1) {
+    if (fs_file_read(&header, sizeof(header), 1, file) != 1) {
         loaderror("failed to read header from '%s'", filename);
-        file_close(file);
+        fs_file_close(file);
         return NULL;
     }
 
     if (!skipversion && header.version != 6) {
         loaderror("header says this is a version %i progs, we need version 6\n", header.version);
-        file_close(file);
+        fs_file_close(file);
         return NULL;
     }
 
     prog = (qc_program*)mem_a(sizeof(qc_program));
     if (!prog) {
-        file_close(file);
+        fs_file_close(file);
         fprintf(stderr, "failed to allocate program data\n");
         return NULL;
     }
@@ -90,11 +90,11 @@ qc_program* prog_load(const char *filename, bool skipversion)
     }
 
 #define read_data(hdrvar, progvar, reserved)                           \
-    if (file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) {        \
+    if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) {        \
         loaderror("seek failed");                                      \
         goto error;                                                    \
     }                                                                  \
-    if (file_read (                                                    \
+    if (fs_file_read (                                                    \
             vec_add(prog->progvar, header.hdrvar.length + reserved),   \
             sizeof(*prog->progvar),                                    \
             header.hdrvar.length,                                      \
@@ -114,7 +114,7 @@ qc_program* prog_load(const char *filename, bool skipversion)
     read_data1(strings);
     read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */
 
-    file_close(file);
+    fs_file_close(file);
 
     /* profile counters */
     memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code));
@@ -354,7 +354,7 @@ static void trace_print_global(qc_program *prog, unsigned int glob, int vtype)
 done:
     if (len < (int)sizeof(spaces)-1) {
         spaces[sizeof(spaces)-1-len] = 0;
-        file_puts(stdout, spaces);
+        fs_file_puts(stdout, spaces);
         spaces[sizeof(spaces)-1-len] = ' ';
     }
 }
diff --git a/file.c b/file.c
deleted file mode 100644 (file)
index fe6167f..0000000
--- a/file.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2012, 2013
- *     Dale Weiler
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "gmqcc.h"
-
-/*
- * This is essentially a "wrapper" interface around standard C's IO
- * library.  There is two reason we implement this, 1) visual studio
- * hearts for "secure" varations, as part of it's "Security Enhancements
- * in the CRT" (http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx).
- * 2) But one of the greater reasons is for the possibility of large file
- * support in the future.  I don't expect to reach the 2GB limit any
- * time soon (mainly because that would be insane).  But when it comes
- * to adding support for some other larger IO tasks (in the test-suite,
- * or even the QCVM we'll need it). There is also a third possibility of
- * building .dat files directly from zip files (which would be very cool
- * at least I think so).  
- */
-#ifdef _MSC_VER
-/* {{{ */
-    /*
-     * Visual Studio has security CRT features which I actually want to support
-     * if we ever port to Windows 8, and want GMQCC to be API safe.
-     *
-     * We handle them here, for all file-operations. 
-     */
-
-    static void file_exception (
-        const wchar_t *expression,
-        const wchar_t *function,
-        const wchar_t *file,
-        unsigned int   line,
-        uintptr_t      reserved
-    ) {
-        wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression);
-        wprintf(L"Aborting ...\n");
-        abort();
-    }
-
-    static void file_init() {
-        static bool init = false;
-
-        if (init)
-            return;
-
-        _set_invalid_parameter_handler(&file_exception);
-
-        /*
-         * Turnoff the message box for CRT asserations otherwise
-         * we don't get the error reported to the console as we should
-         * otherwise get.
-         */
-        _CrtSetReportMode(_CRT_ASSERT, 0);
-        init = !init;
-    }
-
-
-    FILE *file_open(const char *filename, const char *mode) {
-        FILE *handle = NULL;
-        file_init();
-
-        return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
-    }
-
-    size_t file_read(void *buffer, size_t size, size_t count, FILE *fp) {
-        file_init();
-        return fread_s(buffer, size*count, size, count, fp);
-    }
-
-    int file_printf(FILE *fp, const char *format, ...) {
-        int      rt;
-        va_list  va;
-        va_start(va, format);
-
-        file_init();
-        rt = vfprintf_s(fp, format, va);
-        va_end  (va);
-
-        return rt;
-    }
-
-/* }}} */
-#else
-/* {{{ */
-    /*
-     * All other compilers/platforms that don't restrict insane policies on
-     * IO for no aparent reason.
-     */
-    FILE *file_open(const char *filename, const char *mode) {
-        return fopen(filename, mode);
-    }
-
-    size_t file_read(void *buffer, size_t size, size_t count, FILE *fp) {
-        return fread(buffer, size, count, fp);
-    }
-
-    int file_printf(FILE *fp, const char *format, ...) {
-        int      rt;
-        va_list  va;
-        va_start(va, format);
-        rt = vfprintf(fp, format, va);
-        va_end  (va);
-
-        return rt;
-    }
-
-/* }}} */
-#endif
-
-/*
- * These are implemented as just generic wrappers to keep consistency in
- * the API.  Not as macros though  
- */
-void file_close(FILE *fp) {
-    /* Invokes file_exception on windows if fp is null */
-    fclose (fp);
-}
-
-size_t  file_write (
-    const void    *buffer,
-    size_t         size,
-    size_t         count,
-    FILE          *fp
-) {
-    /* Invokes file_exception on windows if fp is null */
-    return fwrite(buffer, size, count, fp);
-}
-
-int file_error(FILE *fp) {
-    /* Invokes file_exception on windows if fp is null */
-    return ferror(fp);
-}
-
-int file_getc(FILE *fp) {
-    /* Invokes file_exception on windows if fp is null */
-    return fgetc(fp);
-}
-
-int file_puts(FILE *fp, const char *str) {
-    /* Invokes file_exception on windows if fp is null */
-    return fputs(str, fp);
-}
-
-int file_seek(FILE *fp, long int off, int whence) {
-    /* Invokes file_exception on windows if fp is null */
-    return fseek(fp, off, whence);
-}
-
-int file_putc(FILE *fp, int ch) {
-    /* Invokes file_exception on windows if fp is null */
-    return fputc(ch, fp);
-}
-
-/*
- * Implements libc getline for systems that don't have it, which is
- * assmed all.  This works the same as getline().
- */
-int file_getline(char **lineptr, size_t *n, FILE *stream) {
-    int   chr;
-    int   ret;
-    char *pos;
-
-    if (!lineptr || !n || !stream)
-        return -1;
-    if (!*lineptr) {
-        if (!(*lineptr = (char*)mem_a((*n=64))))
-            return -1;
-    }
-
-    chr = *n;
-    pos = *lineptr;
-
-    for (;;) {
-        int c = file_getc(stream);
-
-        if (chr < 2) {
-            *n += (*n > 16) ? *n : 64;
-            chr = *n + *lineptr - pos;
-            if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
-                return -1;
-            pos = *n - chr + *lineptr;
-        }
-
-        if (ferror(stream))
-            return -1;
-        if (c == EOF) {
-            if (pos == *lineptr)
-                return -1;
-            else
-                break;
-        }
-
-        *pos++ = c;
-        chr--;
-        if (c == '\n')
-            break;
-    }
-    *pos = '\0';
-    return (ret = pos - *lineptr);
-}
diff --git a/fs.c b/fs.c
new file mode 100644 (file)
index 0000000..8d73b1d
--- /dev/null
+++ b/fs.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2012, 2013
+ *     Dale Weiler
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "gmqcc.h"
+
+/*
+ * This is essentially a "wrapper" interface around standard C's IO
+ * library.  There is two reason we implement this, 1) visual studio
+ * hearts for "secure" varations, as part of it's "Security Enhancements
+ * in the CRT" (http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx).
+ * 2) But one of the greater reasons is for the possibility of large file
+ * support in the future.  I don't expect to reach the 2GB limit any
+ * time soon (mainly because that would be insane).  But when it comes
+ * to adding support for some other larger IO tasks (in the test-suite,
+ * or even the QCVM we'll need it). There is also a third possibility of
+ * building .dat files directly from zip files (which would be very cool
+ * at least I think so).  
+ */
+#ifdef _MSC_VER
+/* {{{ */
+    /*
+     * Visual Studio has security CRT features which I actually want to support
+     * if we ever port to Windows 8, and want GMQCC to be API safe.
+     *
+     * We handle them here, for all file-operations. 
+     */
+
+    static void file_exception (
+        const wchar_t *expression,
+        const wchar_t *function,
+        const wchar_t *file,
+        unsigned int   line,
+        uintptr_t      reserved
+    ) {
+        wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression);
+        wprintf(L"Aborting ...\n");
+        abort();
+    }
+
+    static void file_init() {
+        static bool init = false;
+
+        if (init)
+            return;
+
+        _set_invalid_parameter_handler(&file_exception);
+
+        /*
+         * Turnoff the message box for CRT asserations otherwise
+         * we don't get the error reported to the console as we should
+         * otherwise get.
+         */
+        _CrtSetReportMode(_CRT_ASSERT, 0);
+        init = !init;
+    }
+
+
+    FILE *fs_file_open(const char *filename, const char *mode) {
+        FILE *handle = NULL;
+        file_init();
+
+        return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
+    }
+
+    size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
+        file_init();
+        return fread_s(buffer, size*count, size, count, fp);
+    }
+
+    int fs_file_printf(FILE *fp, const char *format, ...) {
+        int      rt;
+        va_list  va;
+        va_start(va, format);
+
+        file_init();
+        rt = vfprintf_s(fp, format, va);
+        va_end  (va);
+
+        return rt;
+    }
+
+/* }}} */
+#else
+/* {{{ */
+    /*
+     * All other compilers/platforms that don't restrict insane policies on
+     * IO for no aparent reason.
+     */
+    FILE *fs_file_open(const char *filename, const char *mode) {
+        return fopen(filename, mode);
+    }
+
+    size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
+        return fread(buffer, size, count, fp);
+    }
+
+    int fs_file_printf(FILE *fp, const char *format, ...) {
+        int      rt;
+        va_list  va;
+        va_start(va, format);
+        rt = vfprintf(fp, format, va);
+        va_end  (va);
+
+        return rt;
+    }
+
+/* }}} */
+#endif
+
+/*
+ * These are implemented as just generic wrappers to keep consistency in
+ * the API.  Not as macros though  
+ */
+void fs_file_close(FILE *fp) {
+    /* Invokes file_exception on windows if fp is null */
+    fclose (fp);
+}
+
+size_t  fs_file_write (
+    const void    *buffer,
+    size_t         size,
+    size_t         count,
+    FILE          *fp
+) {
+    /* Invokes file_exception on windows if fp is null */
+    return fwrite(buffer, size, count, fp);
+}
+
+int fs_file_error(FILE *fp) {
+    /* Invokes file_exception on windows if fp is null */
+    return ferror(fp);
+}
+
+int fs_file_getc(FILE *fp) {
+    /* Invokes file_exception on windows if fp is null */
+    return fgetc(fp);
+}
+
+int fs_file_puts(FILE *fp, const char *str) {
+    /* Invokes file_exception on windows if fp is null */
+    return fputs(str, fp);
+}
+
+int fs_file_seek(FILE *fp, long int off, int whence) {
+    /* Invokes file_exception on windows if fp is null */
+    return fseek(fp, off, whence);
+}
+
+int fs_file_putc(FILE *fp, int ch) {
+    /* Invokes file_exception on windows if fp is null */
+    return fputc(ch, fp);
+}
+
+int fs_file_flush(FILE *fp) {
+    /* Invokes file_exception on windows if fp is null */
+    return fflush(fp);
+}
+
+long int fs_file_tell(FILE *fp) {
+    /* Invokes file_exception on windows if fp is null */
+    return ftell(fp);
+}
+
+/*
+ * Implements libc getline for systems that don't have it, which is
+ * assmed all.  This works the same as getline().
+ */
+int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
+    int   chr;
+    int   ret;
+    char *pos;
+
+    if (!lineptr || !n || !stream)
+        return -1;
+    if (!*lineptr) {
+        if (!(*lineptr = (char*)mem_a((*n=64))))
+            return -1;
+    }
+
+    chr = *n;
+    pos = *lineptr;
+
+    for (;;) {
+        int c = fs_file_getc(stream);
+
+        if (chr < 2) {
+            *n += (*n > 16) ? *n : 64;
+            chr = *n + *lineptr - pos;
+            if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
+                return -1;
+            pos = *n - chr + *lineptr;
+        }
+
+        if (ferror(stream))
+            return -1;
+        if (c == EOF) {
+            if (pos == *lineptr)
+                return -1;
+            else
+                break;
+        }
+
+        *pos++ = c;
+        chr--;
+        if (c == '\n')
+            break;
+    }
+    *pos = '\0';
+    return (ret = pos - *lineptr);
+}
+
+/*
+ * Now we implement some directory functionality.  Windows lacks dirent.h
+ * this is such a pisss off, we implement it here.
+ */  
+#if defined(_WIN32) && !defined(__MINGW32__)
+    DIR *fs_dir_open(const char *name) {
+        DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(name));
+        if (!dir)
+            return NULL;
+
+        strcpy(dir->dd_name, name);
+        return dir;
+    }
+        
+    int fs_dir_close(DIR *dir) {
+        FindClose((HANDLE)dir->dd_handle);
+        mem_d ((void*)dir);
+        return 0;
+    }
+
+    struct dirent *fs_dir_read(DIR *dir) {
+        WIN32_FIND_DATA info;
+        struct dirent  *data;
+        int             rets;
+
+        if (!dir->dd_handle) {
+            char *dirname;
+            if (*dir->dd_name) {
+                size_t n = strlen(dir->dd_name);
+                if ((dirname  = (char*)mem_a(n + 5) /* 4 + 1 */)) {
+                    strcpy(dirname,     dir->dd_name);
+                    strcpy(dirname + n, "\\*.*");   /* 4 + 1 */
+                }
+            } else {
+                if (!(dirname = util_strdup("\\*.*")))
+                    return NULL;
+            }
+
+            dir->dd_handle = (long)FindFirstFile(dirname, &info);
+            mem_d(dirname);
+            rets = !(!dir->dd_handle);
+        } else if (dir->dd_handle != -11) {
+            rets = FindNextFile ((HANDLE)dir->dd_handle, &info);
+        } else {
+            rets = 0;
+        }
+
+        if (!rets)
+            return NULL;
+        
+        if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
+            strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
+            data->d_name[FILENAME_MAX - 1] = '\0'; /* terminate */
+            data->d_namlen                 = strlen(data->d_name);
+        }
+        return data;
+    }
+
+    int fs_dir_change(const char *path) {
+        return !SetCurrentDirectory(path);
+    }
+
+    int fs_dir_make(const char *path) {
+        return !CreateDirectory(path, NULL);
+    }
+
+    /*
+     * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well
+     * which is not hard at all.
+     */
+#   undef  S_ISDIR
+#   define S_ISDIR(X) ((X)&_S_IFDIR)
+#else
+#   if !defined(__MINGW32__)
+#       include <sys/stat.h> /* mkdir */
+#       include <unistd.h>   /* chdir */
+
+        int fs_dir_make(const char *path) {
+            return mkdir(path, 0700);
+        }
+#   else
+        int fs_dir_make(const char *path) {
+            return mkdir(path);
+        }
+#   endif /*! !defined(__MINGW32__) */
+
+DIR *fs_dir_open(const char *name) {
+    return opendir(name);
+}
+
+int fs_dir_close(DIR *dir) {
+    return closedir(dir);
+}
+
+struct dirent *fs_dir_read(DIR *dir) {
+    return readdir(dir);
+}
+
+int fs_dir_change(const char *path) {
+    return chdir(path);
+}
+
+#endif /*! defined(_WIN32) && !defined(__MINGW32__) */
diff --git a/ftepp.c b/ftepp.c
index 2ce9f4734fc7abd50357f5ad01bb59e040ab8988..68491ed6dd2af72e1c8e69035b6e48bce5384a35 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
@@ -124,7 +124,6 @@ char *ftepp_predef_line(lex_file *context) {
 char *ftepp_predef_file(lex_file *context) {
     size_t  length = strlen(context->name) + 3; /* two quotes and a terminator */
     char   *value  = (char*)mem_a(length);
-    memset (value, 0, length);
     sprintf(value, "\"%s\"", context->name);
 
     return value;
@@ -451,8 +450,12 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
                 ftepp->token = old;
             }
         }
-        else
-        {
+        else if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_COUNT__")) {
+            ftepp->token = TOKEN_VA_COUNT;
+            ptok         = pptoken_make(ftepp);
+            vec_push(macro->output, ptok);
+            ftepp_next(ftepp);
+        } else {
             ptok = pptoken_make(ftepp);
             vec_push(macro->output, ptok);
             ftepp_next(ftepp);
@@ -681,6 +684,7 @@ static void ftepp_param_out(ftepp_t *ftepp, macroparam *param)
 static bool ftepp_preprocess(ftepp_t *ftepp);
 static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *params, bool resetline)
 {
+    char     *buffer       = NULL;
     char     *old_string   = ftepp->output_string;
     char     *inner_string;
     lex_file *old_lexer    = ftepp->lex;
@@ -736,6 +740,12 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
                 ftepp_param_out(ftepp, &params[out->constval.i + vararg_start]);
                 break;
 
+            case TOKEN_VA_COUNT:
+                util_asprintf(&buffer, "%d", varargs);
+                ftepp_out(ftepp, buffer, false);
+                mem_d(buffer);
+                break;
+
             case TOKEN_IDENT:
             case TOKEN_TYPENAME:
             case TOKEN_KEYWORD:
@@ -1250,9 +1260,9 @@ static char *ftepp_include_find_path(const char *file, const char *pathfile)
     memcpy(vec_add(filename, len+1), file, len);
     vec_last(filename) = 0;
 
-    fp = file_open(filename, "rb");
+    fp = fs_file_open(filename, "rb");
     if (fp) {
-        file_close(fp);
+        fs_file_close(fp);
         return filename;
     }
     vec_free(filename);
diff --git a/gmqcc.h b/gmqcc.h
index ae443014678ec7a4aed55688691b8c63952c9395..206688f4af0f87605d0b71b87c88094e783ef660 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -37,7 +37,7 @@
 #ifdef _MSC_VER
 #   pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */
 #   pragma warning(disable : 4018 ) /* signed/unsigned mismatch                                */
-#endif
+#endif /*! _MSC_VER */
 
 #define GMQCC_VERSION_MAJOR 0
 #define GMQCC_VERSION_MINOR 3
@@ -55,7 +55,7 @@
 #    define GMQCC_DEV_VERSION_STRING "development build\n"
 #else
 #    define GMQCC_DEV_VERSION_STRING
-#endif
+#endif /*! GMQCC_GITINGO */
 
 #define GMQCC_STRINGIFY(x) #x
 #define GMQCC_IND_STRING(x) GMQCC_STRINGIFY(x)
@@ -78,10 +78,10 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #ifndef __cplusplus
 #   ifdef  false
 #       undef  false
-#   endif /* !false */
+#   endif /*false */
 #   ifdef  true
 #       undef true
-#   endif /* !true  */
+#   endif /*true  */
 #   define false (0)
 #   define true  (1)
 #   ifdef __STDC_VERSION__
@@ -89,11 +89,11 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
             typedef int  bool;
 #       else
             typedef _Bool bool;
-#       endif
+#       endif /*! __STDC_VERSION__ < 199901L && __GNUC__ < 3 */
 #   else
         typedef int bool;
-#   endif /* !__STDC_VERSION__ */
-#endif    /* !__cplusplus      */
+#   endif /*__STDC_VERSION__ */
+#endif /*! __cplusplus      */
 
 /*
  * Of some functions which are generated we want to make sure
@@ -106,7 +106,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #else
 #   define GMQCC_WARN
 #   define GMQCC_USED
-#endif
+#endif /*! defined(__GNUC__) || defined (__CLANG__) */
 /*
  * This is a hack to silent clang regarding empty
  * body if statements.
@@ -125,13 +125,13 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #               define GMQCC_INLINE
 #           else
 #               define GMQCC_INLINE __attribute__ ((always_inline))
-#           endif
+#           endif /*! __GNUC__ < 2 */
 #       else
 #           define GMQCC_INLINE
-#       endif
+#       endif /*! defined(__GNUC__) || defined (__CLANG__) */
 #    else
 #       define GMQCC_INLINE inline
-#    endif
+#    endif /*! __STDC_VERSION < 199901L */
 /*
  * Visual studio has __forcinline we can use.  So lets use that
  * I suspect it also has just __inline of some sort, but our use
@@ -141,7 +141,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #    define GMQCC_INLINE __forceinline
 #else
 #    define GMQCC_INLINE
-#endif /* !__STDC_VERSION__ */
+#endif /*__STDC_VERSION__ */
 
 /*
  * noreturn is present in GCC and clang
@@ -153,7 +153,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #    define GMQCC_NORETURN __attribute__ ((noreturn))
 #else
 #    define GMQCC_NORETURN
-#endif
+#endif /*! (defined(__GNUC__) && __GNUC__ >= 2) || defined (__CLANG__) */
 
 #ifndef _MSC_VER
 #   include <stdint.h>
@@ -166,7 +166,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
     typedef __int16          int16_t;
     typedef __int32          int32_t;
     typedef __int64          int64_t;
-#endif
+#endif /*! _MSC_VER */
 
 /* 
  *windows makes these prefixed because they're C99
@@ -177,7 +177,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #    define snprintf(X, Y, Z, ...) _snprintf(X, Y, Z, __VA_ARGS__)
     /* strtof doesn't exist -> strtod does though :) */
 #    define strtof(X, Y)          (float)(strtod(X, Y))
-#endif
+#endif /*! _MSC_VER */
 
 /*
  * Very roboust way at determining endianess at compile time: this handles
@@ -197,14 +197,14 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #           define BIG_ENDIAN
 #       elif defined (__LITTLE_ENDIAN__) && !defined (LITTLE_ENDIAN)
 #           define LITTLE_ENDIAN
-#       endif
+#       endif /*! defined (__BIG_ENDIAN__) && !defined(BIG_ENDIAN) */
 #   elif !defined (__MINGW32__)
 #       include <endian.h>
 #       if !defined (__BEOS__)
 #           include <byteswap.h>
-#       endif
-#   endif
-#endif
+#       endif /*! !definde (__BEOS__) */
+#   endif /*! defined (__FreeBSD__) || defined (__OpenBSD__) */
+#endif /*! defined (__GNUC__) || defined (__GNU_LIBRARY__) */
 #if !defined(PLATFORM_BYTE_ORDER)
 #   if defined (LITTLE_ENDIAN) || defined (BIG_ENDIAN)
 #       if defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
@@ -215,7 +215,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
 #       elif defined (BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
-#       endif
+#       endif /*! defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN) */
 #   elif defined (_LITTLE_ENDIAN) || defined (_BIG_ENDIAN)
 #       if defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
@@ -225,7 +225,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
 #       elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
-#       endif
+#       endif /*! defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) */
 #   elif defined (__LITTLE_ENDIAN__) || defined (__BIG_ENDIAN__)
 #       if defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__)
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
@@ -235,9 +235,9 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
 #       elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)
 #           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
-#       endif
-#   endif
-#endif
+#       endif /*! defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__) */
+#   endif /*! defined(LITTLE_ENDIAN) || defined (BIG_ENDIAN) */
+#endif /*! !defined(PLATFORM_BYTE_ORDER) */
 #if !defined (PLATFORM_BYTE_ORDER)
 #   if   defined (__alpha__) || defined (__alpha)    || defined (i386)       || \
          defined (__i386__)  || defined (_M_I86)     || defined (_M_IX86)    || \
@@ -257,8 +257,36 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #   else
 #       define PLATFORM_BYTE_ORDER -1
 #   endif
-#endif
+#endif /*! !defined (PLATFORM_BYTE_ORDER) */
 
+/*
+ * On windows systems where we're not compiling with MING32 we need a
+ * little extra help on dependinces for implementing our own dirent.h
+ * in fs.c.
+ */   
+#if defined(_WIN32) && !defined(__MINGW32__)
+#   define _WIN32_LEAN_AND_MEAN
+#   include <windows.h>
+#   include <io.h>
+#   include <fcntl.h>
+
+    struct dirent {
+        long d_ino;
+        unsigned short     d_reclen;
+        unsigned short     d_namlen;
+        char               d_name[FILENAME_MAX];
+    }
+
+    typedef struct {
+        struct _finddata_t dd_dta;
+        struct dirent      dd_dir;
+        long               dd_handle;
+        int                dd_stat;
+        char               dd_name[1];
+    } DIR;
+#else
+#   include <dirent.h>
+#endif /*! _WIN32 && !defined(__MINGW32__) */
 
 
 /*===================================================================*/
@@ -296,7 +324,7 @@ int util_asprintf (char **ret, const char *fmt, ...);
 #    define mem_a(x)    util_memory_a((x), __LINE__, __FILE__)
 #    define mem_d(x)    util_memory_d((void*)(x))
 #    define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__)
-#endif
+#endif /*! NOTRACK */
 
 /*
  * A flexible vector implementation: all vector pointers contain some
@@ -434,19 +462,29 @@ void        util_hsdel(hash_set_t *);
 /*===================================================================*/
 /*============================ file.c ===============================*/
 /*===================================================================*/
-GMQCC_INLINE void    file_close  (FILE *);
-GMQCC_INLINE int     file_error  (FILE *);
-GMQCC_INLINE int     file_getc   (FILE *);
-GMQCC_INLINE int     file_printf (FILE *, const char *, ...);
-GMQCC_INLINE int     file_puts   (FILE *, const char *);
-GMQCC_INLINE int     file_putc   (FILE *, int);
-GMQCC_INLINE int     file_seek   (FILE *, long int, int);
-
-GMQCC_INLINE size_t  file_read   (void *,        size_t, size_t, FILE *);
-GMQCC_INLINE size_t  file_write  (const void *,  size_t, size_t, FILE *);
-
-GMQCC_INLINE FILE   *file_open   (const char *, const char *);
-/*NOINLINE*/ int     file_getline(char  **, size_t *, FILE *);
+/* file handling */
+void           fs_file_close  (FILE *);
+int            fs_file_error  (FILE *);
+int            fs_file_getc   (FILE *);
+int            fs_file_flush  (FILE *);
+int            fs_file_printf (FILE *, const char *, ...);
+int            fs_file_puts   (FILE *, const char *);
+int            fs_file_putc   (FILE *, int);
+int            fs_file_seek   (FILE *, long int, int);
+long int       fs_file_tell   (FILE *); 
+
+size_t         fs_file_read   (void *,        size_t, size_t, FILE *);
+size_t         fs_file_write  (const void *,  size_t, size_t, FILE *);
+
+FILE          *fs_file_open   (const char *, const char *);
+int            fs_file_getline(char  **, size_t *, FILE *);
+
+/* directory handling */
+DIR           *fs_dir_open    (const char *);
+int            fs_dir_close   (DIR *);
+struct dirent *fs_dir_read    (DIR *);
+int            fs_dir_make    (const char *);
+int            fs_dir_change  (const char *);
 
 
 /*===================================================================*/
@@ -1168,4 +1206,4 @@ extern opts_cmd_t opts;
 #define OPTS_OPTION_U32(X)  (opts.options[X].U32)
 #define OPTS_OPTION_STR(X)  (opts.options[X].STR)
 
-#endif
+#endif /*! GMQCC_HDR */
diff --git a/lexer.c b/lexer.c
index d205e163f11091f05fdfd786684e83eed8dcafcb..5f23952615ce6c1aa8d3f89607aa1c75821d7c11 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -184,7 +184,7 @@ static void lex_token_new(lex_file *lex)
 lex_file* lex_open(const char *file)
 {
     lex_file *lex;
-    FILE *in = file_open(file, "rb");
+    FILE *in = fs_file_open(file, "rb");
 
     if (!in) {
         lexerror(NULL, "open failed: '%s'\n", file);
@@ -193,7 +193,7 @@ lex_file* lex_open(const char *file)
 
     lex = (lex_file*)mem_a(sizeof(*lex));
     if (!lex) {
-        file_close(in);
+        fs_file_close(in);
         lexerror(NULL, "out of memory\n");
         return NULL;
     }
@@ -258,7 +258,7 @@ void lex_close(lex_file *lex)
         vec_free(lex->modelname);
 
     if (lex->file)
-        file_close(lex->file);
+        fs_file_close(lex->file);
 #if 0
     if (lex->tok)
         token_delete(lex->tok);
@@ -1291,15 +1291,22 @@ int lex_do(lex_file *lex)
 
     if (ch == '+' || ch == '-' || /* ++, --, +=, -=  and -> as well! */
         ch == '>' || ch == '<' || /* <<, >>, <=, >=                  */
-        ch == '=' || ch == '!' || /* ==, !=                          */
+        ch == '=' || ch == '!' || /* <=>, ==, !=                     */
         ch == '&' || ch == '|' || /* &&, ||, &=, |=                  */
         ch == '~'                 /* ~=, ~                           */
     )  {
         lex_tokench(lex, ch);
 
         nextch = lex_getch(lex);
-        if (nextch == '=' || (nextch == ch && ch != '!')) {
+        if ((nextch == '=' && ch != '<') || (nextch == ch && ch != '!')) {
             lex_tokench(lex, nextch);
+        } else if (ch == '<' && nextch == '=') {
+            lex_tokench(lex, nextch);
+            if ((thirdch = lex_getch(lex)) == '>')
+                lex_tokench(lex, thirdch);
+            else
+                lex_ungetch(lex, thirdch);
+
         } else if (ch == '-' && nextch == '>') {
             lex_tokench(lex, nextch);
         } else if (ch == '&' && nextch == '~') {
@@ -1323,8 +1330,9 @@ int lex_do(lex_file *lex)
                 lex->tok.constval.f = -lex->tok.constval.f;
             lex_endtoken(lex);
             return lex->tok.ttype;
-        } else
+        } else {
             lex_ungetch(lex, nextch);
+        }
 
         lex_endtoken(lex);
         return (lex->tok.ttype = TOKEN_OPERATOR);
diff --git a/lexer.h b/lexer.h
index 75fb83e9320fc159d432819c408b3abf339270c7..9724a7b90d97c386e1de013a97e08d654e05d280 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -76,6 +76,7 @@ enum {
 
     TOKEN_VA_ARGS, /* for the ftepp only */
     TOKEN_VA_ARGS_ARRAY, /* for the ftepp only */
+    TOKEN_VA_COUNT,     /* to get the count of vaargs */
 
     TOKEN_STRINGCONST, /* not the typename but an actual "string" */
     TOKEN_CHARCONST,
@@ -191,6 +192,7 @@ static const oper_info c_operators[] = {
 
     { "<",   2, opid1('<'),         ASSOC_LEFT,  10, 0 },
     { ">",   2, opid1('>'),         ASSOC_LEFT,  10, 0 },
+    { "<=>", 2, opid3('<','=','>'), ASSOC_LEFT,  10, 0 },
     { "<=",  2, opid2('<','='),     ASSOC_LEFT,  10, 0 },
     { ">=",  2, opid2('>','='),     ASSOC_LEFT,  10, 0 },
 
diff --git a/main.c b/main.c
index 5e4e8c16430ab6884c3566e8a77c65db802a961a..e801aaff7ea7d840a658e504273c4b0b99ed2f81 100644 (file)
--- a/main.c
+++ b/main.c
@@ -522,7 +522,7 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) {
     char  *end;
 
     line = *out;
-    len  = file_getline(&line, alen, src);
+    len  = fs_file_getline(&line, alen, src);
     if (len == -1)
         return false;
 
@@ -608,7 +608,7 @@ int main(int argc, char **argv) {
 
     if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
         if (opts_output_wasset) {
-            outfile = file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
+            outfile = fs_file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
             if (!outfile) {
                 con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT));
                 retval = 1;
@@ -660,7 +660,7 @@ int main(int argc, char **argv) {
 
         progs_src = true;
 
-        src = file_open("progs.src", "rb");
+        src = fs_file_open("progs.src", "rb");
         if (!src) {
             con_err("failed to open `progs.src` for reading\n");
             retval = 1;
@@ -689,7 +689,7 @@ int main(int argc, char **argv) {
         }
 
 srcdone:
-        file_close(src);
+        fs_file_close(src);
         mem_d(line);
     }
 
@@ -723,7 +723,7 @@ srcdone:
                 }
                 out = ftepp_get();
                 if (out)
-                    file_printf(outfile, "%s", out);
+                    fs_file_printf(outfile, "%s", out);
                 ftepp_flush();
             }
             else {
diff --git a/opts.c b/opts.c
index c669ee73b670c6bbc053d0eaa72c3d861c4e70b3..aa923bdeafebd93d42261f4f97e183a89e71f6e6 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -190,7 +190,7 @@ static size_t opts_ini_parse (
     char *read_name;
     char *read_value;
 
-    while (file_getline(&line, &linesize, filehandle) != EOF) {
+    while (fs_file_getline(&line, &linesize, filehandle) != EOF) {
         parse_beg = line;
 
         /* handle BOM */
@@ -345,11 +345,11 @@ void opts_ini_init(const char *file) {
     
     if (!file) {
         /* try ini */
-        if (!(ini = file_open((file = "gmqcc.ini"), "r")))
+        if (!(ini = fs_file_open((file = "gmqcc.ini"), "r")))
             /* try cfg */
-            if (!(ini = file_open((file = "gmqcc.cfg"), "r")))
+            if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r")))
                 return;
-    } else if (!(ini = file_open(file, "r")))
+    } else if (!(ini = fs_file_open(file, "r")))
         return;
 
     con_out("found ini file `%s`\n", file);
@@ -360,5 +360,5 @@ void opts_ini_init(const char *file) {
         vec_free(error);
     }
 
-    file_close(ini);
+    fs_file_close(ini);
 }  
diff --git a/pak.c b/pak.c
new file mode 100644 (file)
index 0000000..043ef89
--- /dev/null
+++ b/pak.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2013
+ *     Dale Weiler 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "gmqcc.h"
+
+/*
+ * The PAK format uses a FOURCC concept for storing the magic ident within
+ * the header as a uint32_t.
+ */  
+#define PAK_FOURCC ((uint32_t)(('P' | ('A' << 8) | ('C' << 16) | ('K' << 24))))
+
+typedef struct {
+    uint32_t magic;  /* "PACK" */
+
+    /*
+     * Offset to first directory entry in PAK file.  It's often
+     * best to store the directories at the end of the file opposed
+     * to the front, since it allows easy insertion without having
+     * to load the entire file into memory again.
+     */     
+    uint32_t diroff;
+    uint32_t dirlen;
+} pak_header_t;
+
+/*
+ * A directory, is sort of a "file entry".  The concept of
+ * a directory in Quake world is a "file entry/record". This
+ * describes a file (with directories/nested ones too in it's
+ * file name).  Hence it can be a file, file with directory, or
+ * file with directories.
+ */ 
+typedef struct {
+    char     name[56];
+    uint32_t pos;
+    uint32_t len;
+} pak_directory_t;
+
+/*
+ * Used to get the next token from a string, where the
+ * strings themselfs are seperated by chracters from
+ * `sep`.  This is essentially strsep.
+ */   
+static char *pak_tree_sep(char **str, const char *sep) {
+    char *beg = *str;
+    char *end;
+
+    if (!beg)
+        return NULL;
+
+    if (*(end = beg + strcspn(beg, sep)))
+        * end++ = '\0'; /* null terminate */
+    else
+          end   = 0;
+
+    *str = end;
+    return beg;
+}
+
+/*
+ * When given a string like "a/b/c/d/e/file"
+ * this function will handle the creation of
+ * the directory structure, included nested
+ * directories.
+ */
+static void pak_tree_build(const char *entry) {
+    char *directory;
+    char *elements[28];
+    char *pathsplit;
+    char *token;
+
+    size_t itr;
+    size_t jtr;
+
+    pathsplit = (char *)mem_a(56);
+    directory = (char *)mem_a(56);
+
+    memset(pathsplit, 0, 56);
+
+    strncpy(directory, entry, 56);
+    for (itr = 0; (token = pak_tree_sep(&directory, "/")) != NULL; itr++) {
+        elements[itr] = token;
+    }
+
+    for (jtr = 0; jtr < itr - 1; jtr++) {
+        strcat(pathsplit, elements[jtr]);
+        strcat(pathsplit, "/");
+
+        if (fs_dir_make(pathsplit)) {
+            mem_d(pathsplit);
+            mem_d(directory);
+
+            /* TODO: undo on fail */
+
+            return;
+        }
+    }
+
+    mem_d(pathsplit);
+    mem_d(directory);
+}
+
+typedef struct {
+    pak_directory_t *directories;
+    pak_header_t     header;
+    FILE            *handle;
+    bool             insert;
+} pak_file_t;
+
+static pak_file_t *pak_open_read(const char *file) {
+    pak_file_t *pak;
+    size_t      itr;
+
+    if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t))))
+        return NULL;
+
+    if (!(pak->handle = fs_file_open(file, "rb"))) {
+        mem_d(pak);
+        return NULL;
+    }
+
+    pak->directories = NULL;
+    pak->insert      = false; /* read doesn't allow insert */
+
+    memset         (&pak->header, 0, sizeof(pak_header_t));
+    fs_file_read   (&pak->header,    sizeof(pak_header_t), 1, pak->handle);
+    util_endianswap(&pak->header, 1, sizeof(pak_header_t));
+
+    /*
+     * Every PAK file has "PACK" stored as FOURCC data in the
+     * header.  If this data cannot compare (as checked here), it's
+     * probably not a PAK file.
+     */
+    if (pak->header.magic != PAK_FOURCC) {
+        fs_file_close(pak->handle);
+        mem_d        (pak);
+        return NULL;
+    }
+
+    /*
+     * Time to read in the directory handles and prepare the directories
+     * vector.  We're going to be reading some the file inwards soon.
+     */      
+    fs_file_seek(pak->handle, pak->header.diroff, SEEK_SET);
+
+    /*
+     * Read in all directories from the PAK file. These are considered
+     * to be the "file entries".
+     */   
+    for (itr = 0; itr < pak->header.dirlen / 64; itr++) {
+        pak_directory_t dir;
+        fs_file_read   (&dir,    sizeof(pak_directory_t), 1, pak->handle);
+        util_endianswap(&dir, 1, sizeof(pak_directory_t));
+
+        vec_push(pak->directories, dir);
+    }
+    return pak;
+}
+
+static pak_file_t *pak_open_write(const char *file) {
+    pak_file_t *pak;
+
+    if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t))))
+        return NULL;
+
+    /*
+     * Generate the required directory structure / tree for
+     * writing this PAK file too.
+     */   
+    pak_tree_build(file);
+
+    if (!(pak->handle = fs_file_open(file, "wb"))) {
+        /*
+         * The directory tree that was created, needs to be
+         * removed entierly if we failed to open a file.
+         */   
+        /* TODO backup directory clean */
+
+        mem_d(pak);
+        return NULL;
+    }
+
+    memset(&(pak->header), 0, sizeof(pak_header_t));
+
+    /*
+     * We're in "insert" mode, we need to do things like header
+     * "patching" and writing the directories at the end of the
+     * file.
+     */
+    pak->insert       = true;
+    pak->header.magic = PAK_FOURCC;
+
+    /* on BE systems we need to swap the byte order of the FOURCC */
+    util_endianswap(&pak->header.magic, 1, sizeof(uint32_t));
+
+    /*
+     * We need to write out the header since files will be wrote out to
+     * this even with directory entries, and that not wrote.  The header
+     * will need to be patched in later with a file_seek, and overwrite,
+     * we could use offsets and other trickery.  This is just easier.
+     */
+    fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
+
+    return pak;
+}
+
+pak_file_t *pak_open(const char *file, const char *mode) {
+    if (!file || !mode)
+        return NULL;
+
+    switch (*mode) {
+        case 'r': return pak_open_read (file);
+        case 'w': return pak_open_write(file);
+    }
+
+    return NULL;
+}
+
+bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) {
+    size_t itr;
+
+    if (!pak || !file)
+        return false;
+  
+    for (itr = 0; itr < vec_size(pak->directories); itr++) {
+        if (!strcmp(pak->directories[itr].name, file)) {
+            /*
+             * Store back a pointer to the directory that matches
+             * the request if requested (NULL is not allowed).
+             */   
+            if (dir) {
+                *dir = &(pak->directories[itr]);
+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/*
+ * Extraction abilities.  These work as you expect them to.
+ */ 
+bool pak_extract_one(pak_file_t *pak, const char *file) {
+    pak_directory_t *dir = NULL;
+    unsigned char   *dat = NULL;
+    FILE            *out;
+
+    if (!pak_exists(pak, file, &dir)) {
+        return false;
+    }
+
+    if (!(dat = (unsigned char *)mem_a(dir->len))) {
+        return false;
+    }
+
+    /*
+     * Generate the directory structure / tree that will be required
+     * to store the extracted file.
+     */   
+    pak_tree_build(file);
+
+    /*
+     * Now create the file, if this operation fails.  Then abort
+     * It shouldn't fail though.
+     */   
+    if (!(out = fs_file_open(file, "wb"))) {
+        mem_d(dat);
+        return false;
+    }
+
+
+    /* read */
+    fs_file_seek (pak->handle, dir->pos, SEEK_SET);
+    fs_file_read (dat, 1, dir->len, pak->handle);
+
+    /* write */
+    fs_file_write(dat, 1, dir->len, out);
+
+    /* close */
+    fs_file_close(out);
+
+    /* free */
+    mem_d(dat);
+
+    return true;
+}
+
+bool pak_extract_all(pak_file_t *pak, const char *dir) {
+    size_t itr;
+
+    if (!fs_dir_make(dir))
+        return false;
+
+    if (fs_dir_change(dir))
+        return false;
+
+    for (itr = 0; itr < vec_size(pak->directories); itr++) {
+        if (!pak_extract_one(pak, pak->directories[itr].name))
+            return false;
+    }
+
+    return true;
+}
+
+/*
+ * Insertion functions (the opposite of extraction).  Yes for generating
+ * PAKs.
+ */
+bool pak_insert_one(pak_file_t *pak, const char *file) {
+    pak_directory_t dir;
+    unsigned char  *dat;
+    FILE           *fp;
+
+    /*
+     * We don't allow insertion on files that already exist within the
+     * pak file.  Weird shit can happen if we allow that ;). We also
+     * don't allow insertion if the pak isn't opened in write mode.  
+     */ 
+    if (!pak || !file || !pak->insert || pak_exists(pak, file, NULL))
+        return false;
+
+    if (!(fp = fs_file_open(file, "rb")))
+        return false;
+
+    /*
+     * Calculate the total file length, since it will be wrote to
+     * the directory entry, and the actual contents of the file
+     * to the PAK file itself.
+     */
+    fs_file_seek(fp, 0, SEEK_END);
+    dir.len = fs_file_tell(fp);
+    fs_file_seek(fp, 0, SEEK_SET);
+
+    dir.pos = fs_file_tell(pak->handle);
+
+    /*
+     * We're limited to 56 bytes for a file name string, that INCLUDES
+     * the directory and '/' seperators.
+     */   
+    if (strlen(file) >= 56) {
+        fs_file_close(fp);
+        return false;
+    }
+
+    strcpy(dir.name, file);
+
+    /*
+     * Allocate some memory for loading in the data that will be
+     * redirected into the PAK file.
+     */   
+    if (!(dat = (unsigned char *)mem_a(dir.len))) {
+        fs_file_close(fp);
+        return false;
+    }
+
+    fs_file_read (dat, dir.len, 1, fp);
+    fs_file_close(fp);
+    fs_file_write(dat, dir.len, 1, pak->handle);
+
+    /*
+     * Now add the directory to the directories vector, so pak_close
+     * can actually write it.
+     */
+    vec_push(pak->directories, dir);
+
+    return true;
+}
+
+/*
+ * Like pak_insert_one, except this collects files in all directories
+ * from a root directory, and inserts them all.
+ */  
+bool pak_insert_all(pak_file_t *pak, const char *dir) {
+    DIR           *dp;
+    struct dirent *dirp;
+
+    if (!(pak->insert))
+        return false;
+
+    if (!(dp = fs_dir_open(dir)))
+        return false;
+
+    while ((dirp = fs_dir_read(dp))) {
+        if (!(pak_insert_one(pak, dirp->d_name))) {
+            fs_dir_close(dp);
+            return false;
+        }
+    }
+
+    fs_dir_close(dp);
+    return true;
+}
+
+bool pak_close(pak_file_t *pak) {
+    size_t itr;
+
+    if (!pak)
+        return false;
+
+    /*
+     * In insert mode we need to patch the header, and write
+     * our directory entries at the end of the file.
+     */  
+    if (pak->insert) {
+        pak->header.dirlen = vec_size(pak->directories) * 64;
+        pak->header.diroff = ftell(pak->handle);
+
+        /* patch header */ 
+        fs_file_seek (pak->handle, 0, SEEK_SET);
+        fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
+
+        /* write directories */
+        fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET);
+
+        for (itr = 0; itr < vec_size(pak->directories); itr++) {
+            fs_file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle);
+        }
+    }
+
+    vec_free     (pak->directories);
+    fs_file_close(pak->handle);
+    mem_d        (pak);
+
+    return true;
+}
+
+/*
+ * Fancy GCC-like LONG parsing allows things like --opt=param with
+ * assignment operator.  This is used for redirecting stdout/stderr
+ * console to specific files of your choice.
+ */
+static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out, int ds, bool split) {
+    int  argc   = *argc_;
+    char **argv = *argv_;
+
+    size_t len = strlen(optname);
+
+    if (strncmp(argv[0]+ds, optname, len))
+        return false;
+
+    /* it's --optname, check how the parameter is supplied */
+    if (argv[0][ds+len] == '=') {
+        *out = argv[0]+ds+len+1;
+        return true;
+    }
+
+    if (!split || argc < ds) /* no parameter was provided, or only single-arg form accepted */
+        return false;
+
+    /* using --opt param */
+    *out = argv[1];
+    --*argc_;
+    ++*argv_;
+    return true;
+}
+
+int main(int argc, char **argv) {
+    bool          extract   = true;
+    char         *redirout  = (char*)stdout;
+    char         *redirerr  = (char*)stderr;
+    char         *directory = NULL;
+    char         *file      = NULL;
+    char        **files     = NULL;
+    pak_file_t   *pak       = NULL;
+    size_t        iter      = 0;
+
+    con_init();
+
+    /*
+     * Command line option parsing commences now We only need to support
+     * a few things in the test suite.
+     */
+    while (argc > 1) {
+        ++argv;
+        --argc;
+
+        if (argv[0][0] == '-') {
+            if (parsecmd("redirout",  &argc, &argv, &redirout,  1, false))
+                continue;
+            if (parsecmd("redirerr",  &argc, &argv, &redirerr,  1, false))
+                continue;
+            if (parsecmd("directory", &argc, &argv, &directory, 1, false))
+                continue;
+            if (parsecmd("file",      &argc, &argv, &file,      1, false))
+                continue;
+
+            con_change(redirout, redirerr);
+
+            switch (argv[0][1]) {
+                case 'e': extract = true;  continue;
+                case 'c': extract = false; continue;
+            }
+
+            if (!strcmp(argv[0]+1, "debug")) {
+                OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
+                continue;
+            }
+            if (!strcmp(argv[0]+1, "memchk")) {
+                OPTS_OPTION_BOOL(OPTION_MEMCHK) = true;
+                continue;
+            }
+            if (!strcmp(argv[0]+1, "nocolor")) {
+                con_color(0);
+                continue;
+            }
+        }
+
+        vec_push(files, argv[0]);
+    }
+    con_change(redirout, redirerr);
+
+
+    if (!file) {
+        con_err("-file must be specified for output/input PAK file\n");
+        vec_free(files);
+        return EXIT_FAILURE;
+    }
+
+    if (extract) {
+        if (!(pak = pak_open(file, "r"))) {
+            con_err("failed to open PAK file %s\n", file);
+            vec_free(files);
+            return EXIT_FAILURE;
+        }
+
+        if (!pak_extract_all(pak, (directory) ? directory : "./")) {
+            con_err("failed to extract PAK %s (files may be missing)\n", file);
+            pak_close(pak);
+            vec_free(files);
+            return EXIT_FAILURE;
+        }
+
+        /* not possible */
+        pak_close(pak);
+        vec_free(files);
+        util_meminfo();
+        return EXIT_SUCCESS;
+    }
+
+    if (!(pak = pak_open(file, "w"))) {
+        con_err("failed to open PAK %s for writing\n", file);
+        vec_free(files);
+        return EXIT_FAILURE;
+    }
+
+    if (directory && !fs_dir_change(directory)) {
+        con_err("failed to change directory %s\n", directory);
+        pak_close(pak);
+        vec_free(files);
+        return EXIT_FAILURE;
+    }
+
+    for (iter = 0; iter < vec_size(files); iter++) {
+        if (!(pak_insert_one(pak, files[iter]))) {
+            con_err("failed inserting %s for PAK %s\n", files[iter], file);
+            pak_close(pak);
+            vec_free(files);
+            return EXIT_FAILURE;
+        }
+    }
+
+    /* not possible */
+    pak_close(pak);
+    vec_free(files);
+
+
+    util_meminfo();
+    return EXIT_SUCCESS;
+}
index 3375accf1864cf203631bd79df9a4acbef6da04a..681207c192c01d55b74f565856ae537d78b6fdaa 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -62,6 +62,7 @@ typedef struct {
     size_t crc_fields;
 
     ast_function *function;
+    ht            aliases;
 
     /* All the labels the function defined...
      * Should they be in ast_function instead?
@@ -318,6 +319,9 @@ static ast_expression* parser_find_label(parser_t *parser, const char *name)
 
 static ast_expression* parser_find_global(parser_t *parser, const char *name)
 {
+    ast_expression *var = (ast_expression*)util_htget(parser->aliases, parser_tokval(parser));
+    if (var)
+        return var;
     return (ast_expression*)util_htget(parser->htglobals, name);
 }
 
@@ -671,8 +675,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                     return false;
                 }
             }
-            if (!ast_block_set_type(blocks[0], exprs[1]))
-                return false;
+            ast_block_set_type(blocks[0], exprs[1]);
 
             vec_push(sy->out, syblock(ctx, blocks[0]));
             return true;
@@ -1068,6 +1071,49 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                 out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]);
             break;
 
+        case opid3('<','=','>'): /* -1, 0, or 1 */
+            if (NotSameType(TYPE_FLOAT)) {
+                ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+                ast_type_to_string(exprs[1], ty2, sizeof(ty2));
+                compile_error(ctx, "invalid types used in comparision: %s and %s",
+                    ty1, ty2);
+
+                return false;
+            }
+
+            if (CanConstFold(exprs[0], exprs[1])) {
+                if (ConstF(0) < ConstF(1))
+                    out = (ast_expression*)parser_const_float_neg1(parser);
+                else if (ConstF(0) == ConstF(1))
+                    out = (ast_expression*)parser_const_float_0(parser);
+                else if (ConstF(0) > ConstF(1))
+                    out = (ast_expression*)parser_const_float_1(parser);
+            } else {
+                ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]);
+
+                eq->refs = (ast_binary_ref)false; /* references nothing */
+
+                    /* if (lt) { */
+                out = (ast_expression*)ast_ternary_new(ctx,
+                        (ast_expression*)ast_binary_new(ctx, INSTR_LT, exprs[0], exprs[1]),
+                        /* out = -1 */
+                        (ast_expression*)parser_const_float_neg1(parser),
+                    /* } else { */
+                        /* if (eq) { */
+                        (ast_expression*)ast_ternary_new(ctx, (ast_expression*)eq,
+                            /* out = 0 */
+                            (ast_expression*)parser_const_float_0(parser),
+                        /* } else { */
+                            /* out = 1 */
+                            (ast_expression*)parser_const_float_1(parser)
+                        /* } */
+                        )
+                    /* } */
+                    );
+
+            }
+            break;
+
         case opid1('>'):
             generated_op += 1; /* INSTR_GT */
         case opid1('<'):
@@ -1372,7 +1418,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             else
                 out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]);
             break;
-            
     }
 #undef NotSameType
 
@@ -1785,8 +1830,8 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
             if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) {
                 var = (ast_expression*)intrinsic_debug_typestring;
             }
-            else
-            {
+                
+            if (!var) {
                 char *correct = NULL;
                 size_t i;
 
@@ -1898,8 +1943,8 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
                 }
             }
             if (o == operator_count) {
-                /* no operator found... must be the end of the statement */
-                break;
+                compile_error(parser_ctx(parser), "unknown operator: %s", parser_tokval(parser));
+                goto onerr;
             }
             /* found an operator */
             op = &operators[o];
@@ -2891,8 +2936,44 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *
                     return false;
                 }
             }
+            else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) {
+                flags   |= AST_FLAG_ALIAS;
+                *message = NULL;
+
+                if (!parser_next(parser)) {
+                    parseerror(parser, "parse error in attribute");
+                    goto argerr;
+                }
+
+                if (parser->tok == '(') {
+                    if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) {
+                        parseerror(parser, "`alias` attribute missing parameter");
+                        goto argerr;
+                    }
+
+                    *message = util_strdup(parser_tokval(parser));
+
+                    if (!parser_next(parser)) {
+                        parseerror(parser, "parse error in attribute");
+                        goto argerr;
+                    }
+
+                    if (parser->tok != ')') {
+                        parseerror(parser, "`alias` attribute expected `)` after parameter");
+                        goto argerr;
+                    }
 
+                    if (!parser_next(parser)) {
+                        parseerror(parser, "parse error in attribute");
+                        goto argerr;
+                    }
+                }
 
+                if (parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+                    parseerror(parser, "`alias` attribute expected `]]`");
+                    goto argerr;
+                }
+            }
             else if (!strcmp(parser_tokval(parser), "deprecated") && !(flags & AST_FLAG_DEPRECATED)) {
                 flags   |= AST_FLAG_DEPRECATED;
                 *message = NULL;
@@ -3779,6 +3860,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
     has_frame_think = false;
     old = parser->function;
 
+    if (var->expression.flags & AST_FLAG_ALIAS) {
+        parseerror(parser, "function aliases cannot have bodies");
+        return false;
+    }
+
     if (vec_size(parser->gotos) || vec_size(parser->labels)) {
         parseerror(parser, "gotos/labels leaking");
         return false;
@@ -3851,11 +3937,12 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
             ast_expression *functype = fld_think->expression.next;
 
             thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype);
-            if (!thinkfunc || !ast_type_adopt(thinkfunc, functype)) {
+            if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/
                 ast_unref(framenum);
                 parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser));
                 return false;
             }
+            ast_type_adopt(thinkfunc, functype);
 
             if (!parser_next(parser)) {
                 ast_unref(framenum);
@@ -4970,7 +5057,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
 
         var->cvq = qualifier;
         var->expression.flags |= qflags;
-        if (var->expression.flags & AST_FLAG_DEPRECATED)
+
+        /*
+         * store the vstring back to var for alias and
+         * deprecation messages.
+         */   
+        if (var->expression.flags & AST_FLAG_DEPRECATED ||
+            var->expression.flags & AST_FLAG_ALIAS)
             var->desc = vstring;
 
         /* Part 1:
@@ -5175,10 +5268,85 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                     }
                 }
                 else {
-                    parser_addglobal(parser, var->name, (ast_expression*)var);
-                    if (isvector) {
-                        for (i = 0; i < 3; ++i) {
-                            parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]);
+                    if (!(var->expression.flags & AST_FLAG_ALIAS)) {
+                        parser_addglobal(parser, var->name, (ast_expression*)var);
+                        if (isvector) {
+                            for (i = 0; i < 3; ++i) {
+                                parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]);
+                            }
+                        }
+                    } else {
+                        ast_expression *find  = parser_find_global(parser, var->desc);
+
+                        if (!find) {
+                            compile_error(parser_ctx(parser), "undeclared variable `%s` for alias `%s`", var->desc, var->name);
+                            return false;
+                        }
+
+                        if (var->expression.vtype != find->expression.vtype) {
+                            char ty1[1024];
+                            char ty2[1024];
+
+                            ast_type_to_string(find,                  ty1, sizeof(ty1));
+                            ast_type_to_string((ast_expression*)var,  ty2, sizeof(ty2));
+
+                            compile_error(parser_ctx(parser), "incompatible types `%s` and `%s` for alias `%s`",
+                                ty1, ty2, var->name
+                            );
+                            return false;
+                        }
+
+                        /*
+                         * add alias to aliases table and to corrector
+                         * so corrections can apply for aliases as well.
+                         */  
+                        util_htset(parser->aliases, var->name, find);
+
+                        /*
+                         * add to corrector so corrections can work
+                         * even for aliases too.
+                         */ 
+                        correct_add (
+                             vec_last(parser->correct_variables),
+                            &vec_last(parser->correct_variables_score),
+                            var->name
+                        );
+
+                        /* generate aliases for vector components */
+                        if (isvector) {
+                            char *buffer[3];
+
+                            util_asprintf(&buffer[0], "%s_x", var->desc);
+                            util_asprintf(&buffer[1], "%s_y", var->desc);
+                            util_asprintf(&buffer[2], "%s_z", var->desc);
+
+                            util_htset(parser->aliases, me[0]->name, parser_find_global(parser, buffer[0]));
+                            util_htset(parser->aliases, me[1]->name, parser_find_global(parser, buffer[1]));
+                            util_htset(parser->aliases, me[2]->name, parser_find_global(parser, buffer[2]));
+
+                            mem_d(buffer[0]);
+                            mem_d(buffer[1]);
+                            mem_d(buffer[2]);
+
+                            /*
+                             * add to corrector so corrections can work
+                             * even for aliases too.
+                             */  
+                            correct_add (
+                                 vec_last(parser->correct_variables),
+                                &vec_last(parser->correct_variables_score),
+                                me[0]->name
+                            );
+                            correct_add (
+                                 vec_last(parser->correct_variables),
+                                &vec_last(parser->correct_variables_score),
+                                me[1]->name
+                            );
+                            correct_add (
+                                 vec_last(parser->correct_variables),
+                                &vec_last(parser->correct_variables_score),
+                                me[2]->name
+                            );
                         }
                     }
                 }
@@ -5676,6 +5844,8 @@ bool parser_init()
     vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE));
     vec_push(parser->_blocktypedefs, 0);
 
+    parser->aliases = util_htnew(PARSER_HT_SIZE);
+
     /* corrector */
     vec_push(parser->correct_variables, correct_trie_new());
     vec_push(parser->correct_variables_score, NULL);
@@ -5826,6 +5996,8 @@ void parser_cleanup()
     ast_value_delete(parser->const_vec[1]);
     ast_value_delete(parser->const_vec[2]);
 
+    util_htdel(parser->aliases);
+
     mem_d(parser);
 }
 
diff --git a/test.c b/test.c
index 5e99df404063de4b7d638cd3e6217107414f5f36..0ddb75a70cbd021bec1c17629f390416f59ad75d 100644 (file)
--- a/test.c
+++ b/test.c
@@ -26,7 +26,7 @@
 
 opts_cmd_t opts;
 
-char *task_bins[] = {
+const char *task_bins[] = {
     "./gmqcc",
     "./qcvm"
 };
@@ -66,7 +66,7 @@ FILE ** task_popen(const char *command, const char *mode) {
     int     errhandle [2];
     int     trypipe;
 
-    popen_t *data = mem_a(sizeof(popen_t));
+    popen_t *data = (popen_t*)mem_a(sizeof(popen_t));
 
     /*
      * Parse the command now into a list for execv, this is a pain
@@ -152,17 +152,10 @@ int task_pclose(FILE **handles) {
     return status;
 }
 #else
-#    define _WIN32_LEAN_AND_MEAN
-#    define popen  _popen
-#    define pclose _pclose
-#    include <windows.h>
-#    include <io.h>
-#    include <fcntl.h>
     /*
      * Bidirectional piping implementation for windows using CreatePipe and DuplicateHandle +
      * other hacks.
      */
-
     typedef struct {
         int __dummy;
         /* TODO: implement */
@@ -181,96 +174,10 @@ int task_pclose(FILE **handles) {
         (void)files;
         return;
     }
-
-#    ifdef __MINGW32__
-        /* mingw32 has dirent.h */
-#        include <dirent.h>
-#    elif defined (_WIN32)
-        /* 
-         * visual studio lacks dirent.h it's a posix thing
-         * so we emulate it with the WinAPI.
-         */
-
-        struct dirent {
-            long           d_ino;
-            unsigned short d_reclen;
-            unsigned short d_namlen;
-            char           d_name[FILENAME_MAX];
-        };
-
-        typedef struct {
-            struct _finddata_t dd_dta;
-            struct dirent      dd_dir;
-            long               dd_handle;
-            int                dd_stat;
-            char               dd_name[1];
-        } DIR;
-
-        DIR *opendir(const char *name) {
-            DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(name));
-            if (!dir)
-                return NULL;
-
-            strcpy(dir->dd_name, name);
-            return dir;
-        }
-            
-        int closedir(DIR *dir) {
-            FindClose((HANDLE)dir->dd_handle);
-            mem_d ((void*)dir);
-            return 0;
-        }
-
-        struct dirent *readdir(DIR *dir) {
-            WIN32_FIND_DATA info;
-            struct dirent  *data;
-            int             rets;
-
-            if (!dir->dd_handle) {
-                char *dirname;
-                if (*dir->dd_name) {
-                    size_t n = strlen(dir->dd_name);
-                    if ((dirname  = (char*)mem_a(n + 5) /* 4 + 1 */)) {
-                        strcpy(dirname,     dir->dd_name);
-                        strcpy(dirname + n, "\\*.*");   /* 4 + 1 */
-                    }
-                } else {
-                    if (!(dirname = util_strdup("\\*.*")))
-                        return NULL;
-                }
-
-                dir->dd_handle = (long)FindFirstFile(dirname, &info);
-                mem_d(dirname);
-                rets = !(!dir->dd_handle);
-            } else if (dir->dd_handle != -11) {
-                rets = FindNextFile ((HANDLE)dir->dd_handle, &info);
-            } else {
-                rets = 0;
-            }
-
-            if (!rets)
-                return NULL;
-            
-            if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
-                strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
-                data->d_name[FILENAME_MAX - 1] = '\0'; /* terminate */
-                data->d_namlen                 = strlen(data->d_name);
-            }
-            return data;
-        }
-
-        /*
-         * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well
-         * which is not hard at all.
-         */
-#        undef  S_ISDIR /* undef just incase */
-#        define S_ISDIR(X) ((X)&_S_IFDIR)
-#    endif
-#endif
+#endif /*! _WIN32 */
 
 #define TASK_COMPILE 0
 #define TASK_EXECUTE 1
-
 /*
  * Task template system:
  *  templates are rules for a specific test, used to create a "task" that
@@ -360,20 +267,20 @@ typedef struct {
  * This is very much like a compiler code generator :-).  This generates
  * a value from some data observed from the compiler.
  */
-bool task_template_generate(task_template_t *template, char tag, const char *file, size_t line, const char *value, size_t *pad) {
+bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) {
     size_t desclen = 0;
     char **destval = NULL;
 
-    if (!template)
+    if (!tmpl)
         return false;
 
     switch(tag) {
-        case 'D': destval = &template->description;    break;
-        case 'T': destval = &template->proceduretype;  break;
-        case 'C': destval = &template->compileflags;   break;
-        case 'E': destval = &template->executeflags;   break;
-        case 'I': destval = &template->sourcefile;     break;
-        case 'F': destval = &template->testflags;      break;
+        case 'D': destval = &tmpl->description;    break;
+        case 'T': destval = &tmpl->proceduretype;  break;
+        case 'C': destval = &tmpl->compileflags;   break;
+        case 'E': destval = &tmpl->executeflags;   break;
+        case 'I': destval = &tmpl->sourcefile;     break;
+        case 'F': destval = &tmpl->testflags;      break;
         default:
             con_printmsg(LVL_ERROR, __FILE__, __LINE__, "internal error",
                 "invalid tag `%c:` during code generation\n",
@@ -417,29 +324,29 @@ bool task_template_generate(task_template_t *template, char tag, const char *fil
     *destval = util_strdup(value);
 
 
-    if (*destval == template->description) {
+    if (*destval == tmpl->description) {
         /*
          * Create some padding for the description to align the
          * printing of the rules file.
          */  
-        if ((desclen = strlen(template->description)) > pad[0])
+        if ((desclen = strlen(tmpl->description)) > pad[0])
             pad[0] = desclen;
     }
 
     return true;
 }
 
-bool task_template_parse(const char *file, task_template_t *template, FILE *fp, size_t *pad) {
+bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) {
     char  *data = NULL;
     char  *back = NULL;
     size_t size = 0;
     size_t line = 1;
 
-    if (!template)
+    if (!tmpl)
         return false;
 
     /* top down parsing */
-    while (file_getline(&back, &size, fp) != EOF) {
+    while (fs_file_getline(&back, &size, fp) != EOF) {
         /* skip whitespace */
         data = back;
         if (*data && (*data == ' ' || *data == '\t'))
@@ -447,12 +354,12 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp,
 
         switch (*data) {
             /*
-             * Handle comments inside task template files.  We're strict
+             * Handle comments inside task tmpl files.  We're strict
              * about the language for fun :-)
              */
             case '/':
                 if (data[1] != '/') {
-                    con_printmsg(LVL_ERROR, file, line, "template parse error",
+                    con_printmsg(LVL_ERROR, file, line, "tmpl parse error",
                         "invalid character `/`, perhaps you meant `//` ?");
 
                     mem_d(back);
@@ -482,14 +389,14 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp,
             case 'I':
             case 'F':
                 if (data[1] != ':') {
-                    con_printmsg(LVL_ERROR, file, line, "template parse error",
+                    con_printmsg(LVL_ERROR, file, line, "tmpl parse error",
                         "expected `:` after `%c`",
                         *data
                     );
                     goto failure;
                 }
-                if (!task_template_generate(template, *data, file, line, &data[3], pad)) {
-                    con_printmsg(LVL_ERROR, file, line, "template compile error",
+                if (!task_template_generate(tmpl, *data, file, line, &data[3], pad)) {
+                    con_printmsg(LVL_ERROR, file, line, "tmpl compile error",
                         "failed to generate for given task\n"
                     );
                     goto failure;
@@ -504,7 +411,7 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp,
             {
                 char *value = &data[3];
                 if (data[1] != ':') {
-                    con_printmsg(LVL_ERROR, file, line, "template parse error",
+                    con_printmsg(LVL_ERROR, file, line, "tmpl parse error",
                         "expected `:` after `%c`",
                         *data
                     );
@@ -523,13 +430,13 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp,
                 else /* cppcheck: possible null pointer dereference */
                     abort();
 
-                vec_push(template->comparematch, util_strdup(value));
+                vec_push(tmpl->comparematch, util_strdup(value));
 
                 break;
             }
 
             default:
-                con_printmsg(LVL_ERROR, file, line, "template parse error",
+                con_printmsg(LVL_ERROR, file, line, "tmpl parse error",
                     "invalid tag `%c`", *data
                 );
                 goto failure;
@@ -555,19 +462,19 @@ failure:
  * Nullifies the template data: used during initialization of a new
  * template and free.
  */
-void task_template_nullify(task_template_t *template) {
-    if (!template)
+void task_template_nullify(task_template_t *tmpl) {
+    if (!tmpl)
         return;
 
-    template->description    = NULL;
-    template->proceduretype  = NULL;
-    template->compileflags   = NULL;
-    template->executeflags   = NULL;
-    template->comparematch   = NULL;
-    template->sourcefile     = NULL;
-    template->tempfilename   = NULL;
-    template->rulesfile      = NULL;
-    template->testflags      = NULL;
+    tmpl->description    = NULL;
+    tmpl->proceduretype  = NULL;
+    tmpl->compileflags   = NULL;
+    tmpl->executeflags   = NULL;
+    tmpl->comparematch   = NULL;
+    tmpl->sourcefile     = NULL;
+    tmpl->tempfilename   = NULL;
+    tmpl->rulesfile      = NULL;
+    tmpl->testflags      = NULL;
 }
 
 task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) {
@@ -575,14 +482,13 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
     char             fullfile[4096];
     size_t           filepadd = 0;
     FILE            *tempfile = NULL;
-    task_template_t *template = NULL;
+    task_template_t *tmpl     = NULL;
 
-    memset  (fullfile, 0, sizeof(fullfile));
     snprintf(fullfile,    sizeof(fullfile), "%s/%s", dir, file);
 
-    tempfile            = file_open(fullfile, "r");
-    template            = mem_a(sizeof(task_template_t));
-    task_template_nullify(template);
+    tempfile = fs_file_open(fullfile, "r");
+    tmpl     = (task_template_t*)mem_a(sizeof(task_template_t));
+    task_template_nullify(tmpl);
 
     /*
      * Create some padding for the printing to align the
@@ -591,7 +497,7 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
     if ((filepadd = strlen(fullfile)) > pad[1])
         pad[1] = filepadd;
 
-    template->rulesfile = util_strdup(fullfile);
+    tmpl->rulesfile = util_strdup(fullfile);
 
     /*
      * Esnure the file even exists for the task, this is pretty useless
@@ -604,7 +510,7 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
         goto failure;
     }
 
-    if (!task_template_parse(file, template, tempfile, pad)) {
+    if (!task_template_parse(file, tmpl, tempfile, pad)) {
         con_err("template parse error: error during parsing\n");
         goto failure;
     }
@@ -616,19 +522,19 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
      *  C
      *  I
      */
-    if (!template->description) {
+    if (!tmpl->description) {
         con_err("template compile error: %s missing `D:` tag\n", file);
         goto failure;
     }
-    if (!template->proceduretype) {
+    if (!tmpl->proceduretype) {
         con_err("template compile error: %s missing `T:` tag\n", file);
         goto failure;
     }
-    if (!template->compileflags) {
+    if (!tmpl->compileflags) {
         con_err("template compile error: %s missing `C:` tag\n", file);
         goto failure;
     }
-    if (!template->sourcefile) {
+    if (!tmpl->sourcefile) {
         con_err("template compile error: %s missing `I:` tag\n", file);
         goto failure;
     }
@@ -637,35 +543,35 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
      * Now lets compile the template, compilation is really just
      * the process of validating the input.
      */
-    if (!strcmp(template->proceduretype, "-compile")) {
-        if (template->executeflags)
+    if (!strcmp(tmpl->proceduretype, "-compile")) {
+        if (tmpl->executeflags)
             con_err("template compile warning: %s erroneous tag `E:` when only compiling\n", file);
-        if (template->comparematch)
+        if (tmpl->comparematch)
             con_err("template compile warning: %s erroneous tag `M:` when only compiling\n", file);
         goto success;
-    } else if (!strcmp(template->proceduretype, "-execute")) {
-        if (!template->executeflags) {
+    } else if (!strcmp(tmpl->proceduretype, "-execute")) {
+        if (!tmpl->executeflags) {
             /* default to $null */
-            template->executeflags = util_strdup("$null");
+            tmpl->executeflags = util_strdup("$null");
         }
-        if (!template->comparematch) {
+        if (!tmpl->comparematch) {
             con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file);
             goto failure;
         }
-    } else if (!strcmp(template->proceduretype, "-fail")) {
-        if (template->executeflags)
+    } else if (!strcmp(tmpl->proceduretype, "-fail")) {
+        if (tmpl->executeflags)
             con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file);
-        if (template->comparematch)
+        if (tmpl->comparematch)
             con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file);
         goto success;
     } else {
-        con_err("template compile error: %s invalid procedure type: %s\n", file, template->proceduretype);
+        con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype);
         goto failure;
     }
 
 success:
-    file_close(tempfile);
-    return template;
+    fs_file_close(tempfile);
+    return tmpl;
 
 failure:
     /*
@@ -673,41 +579,41 @@ failure:
      * so the check to see if it's not null here is required.
      */
     if (tempfile)
-        file_close(tempfile);
-    mem_d (template);
+        fs_file_close(tempfile);
+    mem_d (tmpl);
 
     return NULL;
 }
 
-void task_template_destroy(task_template_t **template) {
-    if (!template)
+void task_template_destroy(task_template_t **tmpl) {
+    if (!tmpl)
         return;
 
-    if ((*template)->description)    mem_d((*template)->description);
-    if ((*template)->proceduretype)  mem_d((*template)->proceduretype);
-    if ((*template)->compileflags)   mem_d((*template)->compileflags);
-    if ((*template)->executeflags)   mem_d((*template)->executeflags);
-    if ((*template)->sourcefile)     mem_d((*template)->sourcefile);
-    if ((*template)->rulesfile)      mem_d((*template)->rulesfile);
-    if ((*template)->testflags)      mem_d((*template)->testflags);
+    if ((*tmpl)->description)    mem_d((*tmpl)->description);
+    if ((*tmpl)->proceduretype)  mem_d((*tmpl)->proceduretype);
+    if ((*tmpl)->compileflags)   mem_d((*tmpl)->compileflags);
+    if ((*tmpl)->executeflags)   mem_d((*tmpl)->executeflags);
+    if ((*tmpl)->sourcefile)     mem_d((*tmpl)->sourcefile);
+    if ((*tmpl)->rulesfile)      mem_d((*tmpl)->rulesfile);
+    if ((*tmpl)->testflags)      mem_d((*tmpl)->testflags);
 
     /*
-     * Delete all allocated string for task template then destroy the
+     * Delete all allocated string for task tmpl then destroy the
      * main vector.
      */
     {
         size_t i = 0;
-        for (; i < vec_size((*template)->comparematch); i++)
-            mem_d((*template)->comparematch[i]);
+        for (; i < vec_size((*tmpl)->comparematch); i++)
+            mem_d((*tmpl)->comparematch[i]);
 
-        vec_free((*template)->comparematch);
+        vec_free((*tmpl)->comparematch);
     }
 
     /*
      * Nullify all the template members otherwise NULL comparision
-     * checks will fail if template pointer is reused.
+     * checks will fail if tmpl pointer is reused.
      */
-    mem_d(*template);
+    mem_d(*tmpl);
 }
 
 /*
@@ -715,7 +621,7 @@ void task_template_destroy(task_template_t **template) {
  * of a task list.  This is the executor of the tasks essentially as well.
  */
 typedef struct {
-    task_template_t *template;
+    task_template_t *tmpl;
     FILE           **runhandles;
     FILE            *stderrlog;
     FILE            *stdoutlog;
@@ -741,7 +647,6 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
     dir = opendir(curdir);
 
     while ((files = readdir(dir))) {
-        memset  (buffer, 0,sizeof(buffer));
         snprintf(buffer,   sizeof(buffer), "%s/%s", curdir, files->d_name);
 
         if (stat(buffer, &directory) == -1) {
@@ -758,14 +663,14 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
          * actually a directory, so it must be a file :)
          */
         if (strcmp(files->d_name + strlen(files->d_name) - 5, ".tmpl") == 0) {
-            task_template_t *template = task_template_compile(files->d_name, curdir, pad);
+            task_template_t *tmpl = task_template_compile(files->d_name, curdir, pad);
             char             buf[4096]; /* one page should be enough */
             char            *qcflags = NULL;
             task_t           task;
 
             util_debug("TEST", "compiling task template: %s/%s\n", curdir, files->d_name);
             found ++;
-            if (!template) {
+            if (!tmpl) {
                 con_err("error compiling task template: %s\n", files->d_name);
                 success = false;
                 continue;
@@ -774,7 +679,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
              * Generate a temportary file name for the output binary
              * so we don't trample over an existing one.
              */
-            template->tempfilename = tempnam(curdir, "TMPDAT");
+            tmpl->tempfilename = tempnam(curdir, "TMPDAT");
 
             /*
              * Additional QCFLAGS enviroment variable may be used
@@ -788,16 +693,15 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
              * which will be refered to with a handle in the task for
              * reading the data from the pipe.
              */
-            memset (buf,0,sizeof(buf));
             if (qcflags) {
-                if (template->testflags && !strcmp(template->testflags, "-no-defs")) {
+                if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
                     snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
                         task_bins[TASK_COMPILE],
                         curdir,
-                        template->sourcefile,
+                        tmpl->sourcefile,
                         qcflags,
-                        template->compileflags,
-                        template->tempfilename
+                        tmpl->compileflags,
+                        tmpl->tempfilename
                     );
                 } else {
                     snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s",
@@ -805,20 +709,20 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
                         curdir,
                         defs,
                         curdir,
-                        template->sourcefile,
+                        tmpl->sourcefile,
                         qcflags,
-                        template->compileflags,
-                        template->tempfilename
+                        tmpl->compileflags,
+                        tmpl->tempfilename
                     );
                 }
             } else {
-                if (template->testflags && !strcmp(template->testflags, "-no-defs")) {
+                if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
                     snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
                         task_bins[TASK_COMPILE],
                         curdir,
-                        template->sourcefile,
-                        template->compileflags,
-                        template->tempfilename
+                        tmpl->sourcefile,
+                        tmpl->compileflags,
+                        tmpl->tempfilename
                     );
                 } else {
                     snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s",
@@ -826,9 +730,9 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
                         curdir,
                         defs,
                         curdir,
-                        template->sourcefile,
-                        template->compileflags,
-                        template->tempfilename
+                        tmpl->sourcefile,
+                        tmpl->compileflags,
+                        tmpl->tempfilename
                     );
                 }
             }
@@ -837,31 +741,29 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
              * The task template was compiled, now lets create a task from
              * the template data which has now been propagated.
              */
-            task.template = template;
+            task.tmpl = tmpl;
             if (!(task.runhandles = task_popen(buf, "r"))) {
-                con_err("error opening pipe to process for test: %s\n", template->description);
+                con_err("error opening pipe to process for test: %s\n", tmpl->description);
                 success = false;
                 continue;
             }
 
-            util_debug("TEST", "executing test: `%s` [%s]\n", template->description, buf);
+            util_debug("TEST", "executing test: `%s` [%s]\n", tmpl->description, buf);
 
             /*
              * Open up some file desciptors for logging the stdout/stderr
              * to our own.
              */
-            memset  (buf,0,sizeof(buf));
-            snprintf(buf,  sizeof(buf), "%s.stdout", template->tempfilename);
+            snprintf(buf,  sizeof(buf), "%s.stdout", tmpl->tempfilename);
             task.stdoutlogfile = util_strdup(buf);
-            if (!(task.stdoutlog     = file_open(buf, "w"))) {
+            if (!(task.stdoutlog     = fs_file_open(buf, "w"))) {
                 con_err("error opening %s for stdout\n", buf);
                 continue;
             }
 
-            memset  (buf,0,sizeof(buf));
-            snprintf(buf,  sizeof(buf), "%s.stderr", template->tempfilename);
+            snprintf(buf,  sizeof(buf), "%s.stderr", tmpl->tempfilename);
             task.stderrlogfile = util_strdup(buf);
-            if (!(task.stderrlog     = file_open(buf, "w"))) {
+            if (!(task.stderrlog = fs_file_open(buf, "w"))) {
                 con_err("error opening %s for stderr\n", buf);
                 continue;
             }
@@ -891,7 +793,6 @@ void task_precleanup(const char *curdir) {
     dir = opendir(curdir);
 
     while ((files = readdir(dir))) {
-        memset(buffer, 0, sizeof(buffer));
         if (strstr(files->d_name, "TMP")     ||
             strstr(files->d_name, ".stdout") ||
             strstr(files->d_name, ".stderr"))
@@ -920,15 +821,15 @@ void task_destroy(void) {
          * annoying to have to do all this cleanup work.
          */
         if (task_tasks[i].runhandles) task_pclose(task_tasks[i].runhandles);
-        if (task_tasks[i].stdoutlog)  file_close (task_tasks[i].stdoutlog);
-        if (task_tasks[i].stderrlog)  file_close (task_tasks[i].stderrlog);
+        if (task_tasks[i].stdoutlog)  fs_file_close (task_tasks[i].stdoutlog);
+        if (task_tasks[i].stderrlog)  fs_file_close (task_tasks[i].stderrlog);
 
         /*
          * Only remove the log files if the test actually compiled otherwise
          * forget about it (or if it didn't compile, and the procedure type
          * was set to -fail (meaning it shouldn't compile) .. stil remove) 
          */
-        if (task_tasks[i].compiled || !strcmp(task_tasks[i].template->proceduretype, "-fail")) {
+        if (task_tasks[i].compiled || !strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
             if (remove(task_tasks[i].stdoutlogfile))
                 con_err("error removing stdout log file: %s\n", task_tasks[i].stdoutlogfile);
             else
@@ -938,14 +839,14 @@ void task_destroy(void) {
             else
                 util_debug("TEST", "removed stderr log file: %s\n", task_tasks[i].stderrlogfile);
 
-            remove(task_tasks[i].template->tempfilename);
+            remove(task_tasks[i].tmpl->tempfilename);
         }
 
         /* free util_strdup data for log files */
         mem_d(task_tasks[i].stdoutlogfile);
         mem_d(task_tasks[i].stderrlogfile);
 
-        task_template_destroy(&task_tasks[i].template);
+        task_template_destroy(&task_tasks[i].tmpl);
     }
     vec_free(task_tasks);
 }
@@ -955,7 +856,7 @@ void task_destroy(void) {
  * using the template passed into it for call-flags and user defined
  * messages.
  */
-bool task_execute(task_template_t *template, char ***line) {
+bool task_execute(task_template_t *tmpl, char ***line) {
     bool     success = true;
     FILE    *execute;
     char     buffer[4096];
@@ -965,21 +866,21 @@ bool task_execute(task_template_t *template, char ***line) {
      * Drop the execution flags for the QCVM if none where
      * actually specified.
      */
-    if (!strcmp(template->executeflags, "$null")) {
+    if (!strcmp(tmpl->executeflags, "$null")) {
         snprintf(buffer,  sizeof(buffer), "%s %s",
             task_bins[TASK_EXECUTE],
-            template->tempfilename
+            tmpl->tempfilename
         );
     } else {
         snprintf(buffer,  sizeof(buffer), "%s %s %s",
             task_bins[TASK_EXECUTE],
-            template->executeflags,
-            template->tempfilename
+            tmpl->executeflags,
+            tmpl->tempfilename
         );
     }
 
     util_debug("TEST", "executing qcvm: `%s` [%s]\n",
-        template->description,
+        tmpl->description,
         buffer
     );
 
@@ -995,11 +896,11 @@ bool task_execute(task_template_t *template, char ***line) {
         char  *data    = NULL;
         size_t size    = 0;
         size_t compare = 0;
-        while (file_getline(&data, &size, execute) != EOF) {
+        while (fs_file_getline(&data, &size, execute) != EOF) {
             if (!strcmp(data, "No main function found\n")) {
                 con_err("test failure: `%s` (No main function found) [%s]\n",
-                    template->description,
-                    template->rulesfile
+                    tmpl->description,
+                    tmpl->rulesfile
                 );
                 pclose(execute);
                 return false;
@@ -1012,8 +913,8 @@ bool task_execute(task_template_t *template, char ***line) {
             if  (strrchr(data, '\n'))
                 *strrchr(data, '\n') = '\0';
 
-            if (vec_size(template->comparematch) > compare) {
-                if (strcmp(data, template->comparematch[compare++]))
+            if (vec_size(tmpl->comparematch) > compare) {
+                if (strcmp(data, tmpl->comparematch[compare++]))
                     success = false;
             } else {
                     success = false;
@@ -1053,12 +954,12 @@ void task_schedualize(size_t *pad) {
     util_debug("TEST", "found %d tasks, preparing to execute\n", vec_size(task_tasks));
 
     for (i = 0; i < vec_size(task_tasks); i++) {
-        util_debug("TEST", "executing task: %d: %s\n", i, task_tasks[i].template->description);
+        util_debug("TEST", "executing task: %d: %s\n", i, task_tasks[i].tmpl->description);
         /*
          * Generate a task from thin air if it requires execution in
          * the QCVM.
          */
-        execute = !!(!strcmp(task_tasks[i].template->proceduretype, "-execute"));
+        execute = !!(!strcmp(task_tasks[i].tmpl->proceduretype, "-execute"));
 
         /*
          * We assume it compiled before we actually compiled :).  On error
@@ -1070,17 +971,17 @@ void task_schedualize(size_t *pad) {
          * Read data from stdout first and pipe that stuff into a log file
          * then we do the same for stderr.
          */
-        while (file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
-            file_puts(task_tasks[i].stdoutlog, data);
+        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
+            fs_file_puts(task_tasks[i].stdoutlog, data);
 
             if (strstr(data, "failed to open file")) {
                 task_tasks[i].compiled = false;
                 execute                = false;
             }
 
-            fflush(task_tasks[i].stdoutlog);
+            fs_file_flush(task_tasks[i].stdoutlog);
         }
-        while (file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
+        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
             /*
              * If a string contains an error we just dissalow execution
              * of it in the vm.
@@ -1094,26 +995,26 @@ void task_schedualize(size_t *pad) {
                 task_tasks[i].compiled = false;
             }
 
-            file_puts(task_tasks[i].stderrlog, data);
-            fflush(task_tasks[i].stdoutlog);
+            fs_file_puts (task_tasks[i].stderrlog, data);
+            fs_file_flush(task_tasks[i].stdoutlog);
         }
 
-        if (!task_tasks[i].compiled && strcmp(task_tasks[i].template->proceduretype, "-fail")) {
+        if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
             con_err("test failure: `%s` (failed to compile) see %s.stdout and %s.stderr [%s]\n",
-                task_tasks[i].template->description,
-                task_tasks[i].template->tempfilename,
-                task_tasks[i].template->tempfilename,
-                task_tasks[i].template->rulesfile
+                task_tasks[i].tmpl->description,
+                task_tasks[i].tmpl->tempfilename,
+                task_tasks[i].tmpl->tempfilename,
+                task_tasks[i].tmpl->rulesfile
             );
             continue;
         }
 
         if (!execute) {
             con_out("test succeeded: `%s` %*s\n",
-                task_tasks[i].template->description,
-                (pad[0] + pad[1] - strlen(task_tasks[i].template->description)) +
-                (strlen(task_tasks[i].template->rulesfile) - pad[1]),
-                task_tasks[i].template->rulesfile
+                task_tasks[i].tmpl->description,
+                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
+                (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
+                task_tasks[i].tmpl->rulesfile
                 
             );
             continue;
@@ -1123,12 +1024,12 @@ void task_schedualize(size_t *pad) {
          * If we made it here that concludes the task is to be executed
          * in the virtual machine.
          */
-        if (!task_execute(task_tasks[i].template, &match)) {
+        if (!task_execute(task_tasks[i].tmpl, &match)) {
             size_t d = 0;
 
             con_err("test failure: `%s` (invalid results from execution) [%s]\n",
-                task_tasks[i].template->description,
-                task_tasks[i].template->rulesfile
+                task_tasks[i].tmpl->description,
+                task_tasks[i].tmpl->rulesfile
             );
 
             /*
@@ -1137,11 +1038,11 @@ void task_schedualize(size_t *pad) {
              * what was actually returned from executing.
              */
             con_err("    Expected From %u Matches: (got %u Matches)\n",
-                vec_size(task_tasks[i].template->comparematch),
+                vec_size(task_tasks[i].tmpl->comparematch),
                 vec_size(match)
             );
-            for (; d < vec_size(task_tasks[i].template->comparematch); d++) {
-                char  *select = task_tasks[i].template->comparematch[d];
+            for (; d < vec_size(task_tasks[i].tmpl->comparematch); d++) {
+                char  *select = task_tasks[i].tmpl->comparematch[d];
                 size_t length = 40 - strlen(select);
 
                 con_err("        Expected: \"%s\"", select);
@@ -1155,10 +1056,10 @@ void task_schedualize(size_t *pad) {
              * This will help track down bugs in template files that fail to match
              * something.
              */  
-            if (vec_size(match) > vec_size(task_tasks[i].template->comparematch)) {
-                for (d = 0; d < vec_size(match) - vec_size(task_tasks[i].template->comparematch); d++) {
+            if (vec_size(match) > vec_size(task_tasks[i].tmpl->comparematch)) {
+                for (d = 0; d < vec_size(match) - vec_size(task_tasks[i].tmpl->comparematch); d++) {
                     con_err("        Expected: Nothing                                   | Got: \"%s\"\n",
-                        match[d + vec_size(task_tasks[i].template->comparematch)]
+                        match[d + vec_size(task_tasks[i].tmpl->comparematch)]
                     );
                 }
             }
@@ -1174,10 +1075,10 @@ void task_schedualize(size_t *pad) {
         vec_free(match);
 
         con_out("test succeeded: `%s` %*s\n",
-            task_tasks[i].template->description,
-            (pad[0] + pad[1] - strlen(task_tasks[i].template->description)) +
-            (strlen(task_tasks[i].template->rulesfile) - pad[1]),
-            task_tasks[i].template->rulesfile
+            task_tasks[i].tmpl->description,
+            (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
+            (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
+            task_tasks[i].tmpl->rulesfile
             
         );
     }
diff --git a/tests/aliases.qc b/tests/aliases.qc
new file mode 100644 (file)
index 0000000..0bf347b
--- /dev/null
@@ -0,0 +1,34 @@
+float alias_1 = 3.14;
+void  alias_2() {
+    print("alias_2\n");
+}
+
+[[alias("alias_2")]] void  alias_2_aliased();
+[[alias("alias_1")]] float alias_1_aliased;
+
+
+// alias to an alias?
+vector alias_3;
+[[alias("alias_3")]] vector alias_3_aliased;
+
+// expected output
+// alias_2
+// 3.14
+void main() {
+    alias_2_aliased();
+
+    alias_3_aliased= '1 2 3';
+
+    print(
+        ftos(
+            alias_1_aliased
+        ),
+        "\n"
+    );
+
+    print(
+        "x ", ftos(alias_3_aliased_x), "\n",
+        "y ", ftos(alias_3_aliased_y), "\n",
+        "z ", ftos(alias_3_aliased_z), "\n"
+    );
+}
diff --git a/tests/aliases.tmpl b/tests/aliases.tmpl
new file mode 100644 (file)
index 0000000..8e414b0
--- /dev/null
@@ -0,0 +1,9 @@
+I: aliases.qc
+D: test aliases
+T: -execute
+C: -std=gmqcc
+M: alias_2
+M: 3.14
+M: x 1
+M: y 2
+M: z 3
diff --git a/tests/pops.qc b/tests/pops.qc
new file mode 100644 (file)
index 0000000..ee6631b
--- /dev/null
@@ -0,0 +1,19 @@
+void main() {
+    /* so far only one perl operator is implemented */
+    float x = 100;
+    float y = 200;
+    float z = 300;
+
+    /* to ensure runtime */
+    x += 1;
+    y += 1;
+    z += 1;
+
+    float test_x = (x <=> x + 1); // -1 less than
+    float test_y = (x <=> x);     //  0 equal
+    float test_z = (x <=> x - 1); //  1 greater than
+
+    print(ftos(test_x), "\n");
+    print(ftos(test_y), "\n");
+    print(ftos(test_z), "\n");
+}
diff --git a/tests/pops.tmpl b/tests/pops.tmpl
new file mode 100644 (file)
index 0000000..35b7d41
--- /dev/null
@@ -0,0 +1,7 @@
+I: pops.qc
+D: test perl operators
+T: -execute
+C: -std=gmqcc
+M: -1
+M: 0
+M: 1