]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'cooking' of git://github.com/graphitemaster/gmqcc into cooking
authorWolfgang Bumiller <wry.git@bumiller.com>
Fri, 11 Oct 2013 12:10:57 +0000 (14:10 +0200)
committerWolfgang Bumiller <wry.git@bumiller.com>
Fri, 11 Oct 2013 12:10:57 +0000 (14:10 +0200)
21 files changed:
Makefile
PORTING [new file with mode: 0644]
ansi.c [new file with mode: 0644]
code.c
conout.c
exec.c
fs.c
ftepp.c
gmqcc.h
include.mk
ir.c
lexer.c
lexer.h
main.c
msvc.c [new file with mode: 0644]
opts.c
pak.c
parser.c
platform.h [new file with mode: 0644]
test.c
util.c

index a89d8c28e1473869db2f1a21c8463318bf5029f3..bfc68c72cb8f38a9c381d6ce2f2f79fcf0065309 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -148,21 +148,22 @@ install-doc:
 
 # DO NOT DELETE
 
-util.o: gmqcc.h opts.def
-fs.o: gmqcc.h opts.def
-conout.o: gmqcc.h opts.def
-opts.o: gmqcc.h opts.def
-pak.o: gmqcc.h opts.def
+pak.o: gmqcc.h opts.def platform.h
+ansi.o: platform.h gmqcc.h opts.def
+util.o: gmqcc.h opts.def platform.h
 stat.o: gmqcc.h opts.def
-test.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def platform.h
+conout.o: gmqcc.h opts.def platform.h
+opts.o: gmqcc.h opts.def platform.h
+test.o: gmqcc.h opts.def platform.h
 main.o: gmqcc.h opts.def lexer.h
-lexer.o: gmqcc.h opts.def lexer.h
-parser.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h
+lexer.o: gmqcc.h opts.def lexer.h platform.h
+parser.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h platform.h
 code.o: gmqcc.h opts.def
-ast.o: gmqcc.h opts.def ast.h ir.h parser.h lexer.h
-ir.o: gmqcc.h opts.def ir.h
-ftepp.o: gmqcc.h opts.def lexer.h
+ast.o: gmqcc.h opts.def ast.h ir.h parser.h lexer.h platform.h
+ir.o: gmqcc.h opts.def ir.h platform.h
+ftepp.o: gmqcc.h opts.def lexer.h platform.h
 utf8.o: gmqcc.h opts.def
 correct.o: gmqcc.h opts.def
-fold.o: ast.h ir.h gmqcc.h opts.def parser.h lexer.h
-intrin.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h
+fold.o: ast.h ir.h gmqcc.h opts.def parser.h lexer.h platform.h
+intrin.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h platform.h
diff --git a/PORTING b/PORTING
new file mode 100644 (file)
index 0000000..bbdb274
--- /dev/null
+++ b/PORTING
@@ -0,0 +1,4 @@
+Porting gmqcc to a new platform is farily trivial, in most cases ansi.c
+will be sufficent enough to get it to run on your favorite platform. If
+however it isn't you can duplicate ansi.c and change it accordingly.
+Changes to platform.h may also be required.
diff --git a/ansi.c b/ansi.c
new file mode 100644 (file)
index 0000000..412e9a8
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+#define GMQCC_PLATFORM_HEADER
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "platform.h"
+#include "gmqcc.h"
+
+int platform_vsnprintf(char *buffer, size_t bytes, const char *format, va_list arg) {
+    return vsnprintf(buffer, bytes, format, arg);
+}
+
+int platform_vsscanf(const char *str, const char *format, va_list arg) {
+    return vsscanf(str, format, arg);
+}
+
+const struct tm *platform_localtime(const time_t *timer) {
+    return localtime(timer);
+}
+
+const char *platform_ctime(const time_t *timer) {
+    return ctime(timer);
+}
+
+char *platform_strncat(char *dest, const char *src, size_t num) {
+    return strncat(dest, src, num);
+}
+
+const char *platform_tmpnam(char *str) {
+    return tmpnam(str);
+}
+
+const char *platform_getenv(char *var) {
+    return getenv(var);
+}
+
+int platform_vasprintf(char **dat, const char *fmt, va_list args) {
+    int     ret;
+    int     len;
+    char   *tmp = NULL;
+    char    buf[128];
+    va_list cpy;
+
+    va_copy(cpy, args);
+    len = vsnprintf(buf, sizeof(buf), fmt, cpy);
+    va_end (cpy);
+
+    if (len < (int)sizeof(buf)) {
+        *dat = util_strdup(buf);
+        return len;
+    }
+
+    tmp = (char*)mem_a(len + 1);
+    if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
+        mem_d(tmp);
+        *dat = NULL;
+        return -1;
+    }
+
+    *dat = tmp;
+    return len;
+}
+
+char *platform_strcat(char *dest, const char *src) {
+    return strcat(dest, src);
+}
+
+char *platform_strncpy(char *dest, const char *src, size_t num) {
+    return strncpy(dest, src, num);
+}
+
+const char *platform_strerror(int err) {
+    return strerror(err);
+}
+
+FILE *platform_fopen(const char *filename, const char *mode) {
+    return fopen(filename, mode);
+}
+
+size_t platform_fread(void *ptr, size_t size, size_t count, FILE *stream) {
+    return fread(ptr, size, count, stream);
+}
+
+size_t platform_fwrite(const void *ptr, size_t size, size_t count, FILE *stream) {
+    return fwrite(ptr, size, count, stream);
+}
+
+int platform_fflush(FILE *stream) {
+    return fflush(stream);
+}
+
+int platform_vfprintf(FILE *stream, const char *format, va_list arg) {
+    return vfprintf(stream, format, arg);
+}
+
+int platform_fclose(FILE *stream) {
+    return fclose(stream);
+}
+
+int platform_ferror(FILE *stream) {
+    return ferror(stream);
+}
+
+int platform_fgetc(FILE *stream) {
+    return fgetc(stream);
+}
+
+int platform_fputs(const char *str, FILE *stream) {
+    return fputs(str, stream);
+}
+
+int platform_fseek(FILE *stream, long offset, int origin) {
+    return fseek(stream, offset, origin);
+}
+
+long platform_ftell(FILE *stream) {
+    return ftell(stream);
+}
+
+int platform_mkdir(const char *path, int mode) {
+    /*
+     * For some reason mingw32 just doesn't have a correct mkdir impl
+     * so we handle that here.
+     */
+#   ifdef _WIN32
+    (void)mode;
+    return mkdir(path);
+#   else
+    return mkdir(path, mode);
+#   endif /*!_WIN32*/
+}
+
+DIR *platform_opendir(const char *path) {
+    return opendir(path);
+}
+
+int platform_closedir(DIR *dir) {
+    return closedir(dir);
+}
+
+struct dirent *platform_readdir(DIR *dir) {
+    return readdir(dir);
+}
+
+int platform_isatty(int fd) {
+    return isatty(fd);
+}
diff --git a/code.c b/code.c
index 5703e5098b60131251ba96ec7d34df62efaa2e11..05ffe70ca3561a73fdb37645b042f04953ba86e4 100644 (file)
--- a/code.c
+++ b/code.c
@@ -401,7 +401,7 @@ static bool code_write_memory(code_t *code, uint8_t **datmem, size_t *sizedat, u
 
 bool code_write(code_t *code, const char *filename, const char *lnofile) {
     prog_header_t  code_header;
-    FILE          *fp = NULL;
+    fs_file_t     *fp = NULL;
 
     code_create_header(code, &code_header, filename, lnofile);
 
index 63391d6a86f541efe9ad9f3f0b20af4a5a3f910e..c22758be9c178a43a7ac61617405a7124fcd7b4f 100644 (file)
--- a/conout.c
+++ b/conout.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include <stdio.h>
 #include "gmqcc.h"
 
-/*
- * isatty/STDERR_FILENO/STDOUT_FILNO
- * + some other things likewise.
- */
-#ifndef _WIN32
-#   include <unistd.h>
-#else
-#   include <io.h>
-    /*
-     * Windows and it's posix underscore bullshit.  We simply fix this
-     * with yay, another macro :P
-     */
-#   define isatty _isatty
-#endif
-
-#define GMQCC_IS_STDOUT(X) ((FILE*)((void*)X) == stdout)
-#define GMQCC_IS_STDERR(X) ((FILE*)((void*)X) == stderr)
+#define GMQCC_IS_STDOUT(X) ((fs_file_t*)((void*)X) == (fs_file_t*)stdout)
+#define GMQCC_IS_STDERR(X) ((fs_file_t*)((void*)X) == (fs_file_t*)stderr)
 #define GMQCC_IS_DEFINE(X) (GMQCC_IS_STDERR(X) || GMQCC_IS_STDOUT(X))
 
 typedef struct {
-    FILE *handle_err;
-    FILE *handle_out;
-
-    int   color_err;
-    int   color_out;
+    fs_file_t *handle_err;
+    fs_file_t *handle_out;
+    int        color_err;
+    int        color_out;
 } con_t;
 
-/*
- * Doing colored output on windows is fucking stupid.  The linux way is
- * the real way. So we emulate it on windows :)
- */
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-/*
- * Windows doesn't have constants for FILENO, sadly but the docs tell
- * use the constant values.
- */
-#undef  STDERR_FILENO
-#undef  STDOUT_FILENO
-#define STDERR_FILENO 2
-#define STDOUT_FILENO 1
-
-enum {
-    RESET = 0,
-    BOLD  = 1,
-    BLACK = 30,
-    RED,
-    GREEN,
-    YELLOW,
-    BLUE,
-    MAGENTA,
-    CYAN,
-    GRAY,
-    WHITE = GRAY
-};
-
-enum {
-    WBLACK,
-    WBLUE,
-    WGREEN   = 2,
-    WRED     = 4,
-    WINTENSE = 8,
-    WCYAN    = WBLUE  | WGREEN,
-    WMAGENTA = WBLUE  | WRED,
-    WYELLOW  = WGREEN | WRED,
-    WWHITE   = WBLUE  | WGREEN | WRED
-};
-
-static const int ansi2win[] = {
-    WBLACK,
-    WRED,
-    WGREEN,
-    WYELLOW,
-    WBLUE,
-    WMAGENTA,
-    WCYAN,
-    WWHITE
-};
-
-static int win_fputs(FILE *h, const char *str) {
-    /* state for translate */
-    int acolor = 0;
-    int wcolor = 0;
-    int icolor = 0;
-    int state  = 0;
-
-    /* attributes */
-    int intense  =  -1;
-    int colors[] = {-1, -1 };
-    int colorpos = 1;
-    int length   = 0;
-    CONSOLE_SCREEN_BUFFER_INFO cinfo;
-    GetConsoleScreenBufferInfo (
-        (GMQCC_IS_STDOUT(h)) ?
-            GetStdHandle(STD_OUTPUT_HANDLE) :
-            GetStdHandle(STD_ERROR_HANDLE), &cinfo
-    );
-    icolor = cinfo.wAttributes;
-
-    while (*str) {
-        if (*str == '\x1B')
-            state = '\x1B';
-        else if (state == '\x1B' && *str == '[')
-            state = '[';
-        else if (state == '[') {
-            if (*str != 'm') {
-                colors[colorpos] = *str;
-                colorpos--;
-            } else {
-                int find;
-                int mult;
-                for (find = colorpos + 1, acolor = 0, mult = 1; find < 2; find++) {
-                    acolor += (colors[find] - 48) * mult;
-                    mult   *= 10;
-                }
-
-                /* convert to windows color */
-                if (acolor == BOLD)
-                    intense = WINTENSE;
-                else if (acolor == RESET) {
-                    intense = WBLACK;
-                    wcolor  = icolor;
-                }
-                else if (BLACK <= acolor && acolor <= WHITE)
-                    wcolor = ansi2win[acolor - 30];
-                else if (acolor == 90) {
-                    /* special gray really white man */
-                    wcolor  = WWHITE;
-                    intense = WBLACK;
-                }
-
-                SetConsoleTextAttribute (
-                    (GMQCC_IS_STDOUT(h)) ?
-                    GetStdHandle(STD_OUTPUT_HANDLE) :
-                    GetStdHandle(STD_ERROR_HANDLE),
-
-                    wcolor | intense | (icolor & 0xF0)
-                );
-                colorpos =  1;
-                state    = -1;
-            }
-        } else {
-            fs_file_write(str, 1, 1, stdout);
-            length ++;
-        }
-        str++;
-    }
-    /* restore */
-    SetConsoleTextAttribute(
-        (GMQCC_IS_STDOUT(h)) ?
-        GetStdHandle(STD_OUTPUT_HANDLE) :
-        GetStdHandle(STD_ERROR_HANDLE),
-        icolor
-    );
-    return length;
-}
-#endif
-
 /*
  * We use standard files as default. These can be changed at any time
  * with con_change(F, F)
@@ -197,10 +49,8 @@ static con_t console;
  * checks.
  */
 static void con_enablecolor(void) {
-    if (console.handle_err == stderr || console.handle_err == stdout)
-        console.color_err = !!(isatty(STDERR_FILENO));
-    if (console.handle_out == stderr || console.handle_out == stdout)
-        console.color_out = !!(isatty(STDOUT_FILENO));
+    console.color_err = util_isatty(console.handle_err);
+    console.color_out = util_isatty(console.handle_out);
 }
 
 /*
@@ -208,23 +58,8 @@ static void con_enablecolor(void) {
  * arguments.  This colorizes for windows as well via translate
  * step.
  */
-static int con_write(FILE *handle, const char *fmt, va_list va) {
-    int      ln;
-    #ifndef _WIN32
-    ln = vfprintf(handle, fmt, va);
-    #else
-    {
-        char data[4096];
-        memset(data, 0, sizeof(data));
-#ifdef _MSC_VER
-        vsnprintf_s(data, sizeof(data), sizeof(data), fmt, va);
-#else
-        vsnprintf(data, sizeof(data), fmt, va);
-#endif
-        ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(handle, data) : fs_file_puts(handle, data);
-    }
-    #endif
-    return ln;
+static int con_write(fs_file_t *handle, const char *fmt, va_list va) {
+    return vfprintf((FILE*)handle, fmt, va);
 }
 
 /**********************************************************************
@@ -248,8 +83,8 @@ void con_color(int state) {
 }
 
 void con_init() {
-    console.handle_err = stderr;
-    console.handle_out = stdout;
+    console.handle_err = (fs_file_t*)stderr;
+    console.handle_out = (fs_file_t*)stdout;
     con_enablecolor();
 }
 
@@ -271,16 +106,16 @@ void con_reset() {
 int con_change(const char *out, const char *err) {
     con_close();
 
-    if (!out) out = (const char *)((!console.handle_out) ? stdout : console.handle_out);
-    if (!err) err = (const char *)((!console.handle_err) ? stderr : console.handle_err);
+    if (!out) out = (const char *)((!console.handle_out) ? (fs_file_t*)stdout : console.handle_out);
+    if (!err) err = (const char *)((!console.handle_err) ? (fs_file_t*)stderr : console.handle_err);
 
     if (GMQCC_IS_DEFINE(out)) {
-        console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
+        console.handle_out = (fs_file_t*)(GMQCC_IS_STDOUT(out) ? stdout : stderr);
         con_enablecolor();
     } 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;
+        console.handle_err = (fs_file_t*)(GMQCC_IS_STDOUT(err) ? stdout : stderr);
         con_enablecolor();
     } else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
 
@@ -291,11 +126,11 @@ int con_change(const char *out, const char *err) {
  * Defaultizer because stdio.h shouldn't be used anywhere except here
  * and inside file.c To prevent mis-match of wrapper-interfaces.
  */
-FILE *con_default_out() {
-    return (console.handle_out = stdout);
+fs_file_t *con_default_out() {
+    return (fs_file_t*)(console.handle_out = (fs_file_t*)stdout);
 }
-FILE *con_default_err() {
-    return (console.handle_err = stderr);
+fs_file_t *con_default_err() {
+    return (fs_file_t*)(console.handle_err = (fs_file_t*)stderr);
 }
 
 int con_verr(const char *fmt, va_list va) {
@@ -339,10 +174,10 @@ static void con_vprintmsg_c(int level, const char *name, size_t line, size_t col
         CON_RED
     };
 
-    int  err                         = !!(level == LVL_ERROR);
-    int  color                       = (err) ? console.color_err : console.color_out;
-    int (*print) (const char *, ...)  = (err) ? &con_err          : &con_out;
-    int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout;
+    int  err                             = !!(level == LVL_ERROR);
+    int  color                           = (err) ? console.color_err : console.color_out;
+    int (*print) (const char *, ...)     = (err) ? &con_err          : &con_out;
+    int (*vprint)(const char *, va_list) = (err) ? &con_verr         : &con_vout;
 
     if (color)
         print("\033[0;%dm%s:%d:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, (int)column, sel[level], msgtype);
diff --git a/exec.c b/exec.c
index c4de8addec619b8d9521a7925d258d17907abcae..57b47318fab3211a8d269db944933ad26eeb95ee 100644 (file)
--- a/exec.c
+++ b/exec.c
  */
 #ifndef QCVM_LOOP
 #include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
 #include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
 
 #include "gmqcc.h"
 
@@ -54,9 +53,9 @@ static void qcvmerror(qc_program_t *prog, const char *fmt, ...)
 
 qc_program_t* prog_load(const char *filename, bool skipversion)
 {
-    qc_program_t   *prog;
     prog_header_t   header;
-    FILE         *file  = fs_file_open(filename, "rb");
+    qc_program_t   *prog;
+    fs_file_t      *file  = fs_file_open(filename, "rb");
 
     if (!file)
         return NULL;
@@ -91,11 +90,11 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
     }
 
 #define read_data(hdrvar, progvar, reserved)                           \
-    if (fs_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 (fs_file_read (                                                    \
+    if (fs_file_read (                                                 \
             vec_add(prog->progvar, header.hdrvar.length + reserved),   \
             sizeof(*prog->progvar),                                    \
             header.hdrvar.length,                                      \
@@ -352,7 +351,7 @@ static void trace_print_global(qc_program_t *prog, unsigned int glob, int vtype)
 done:
     if (len < (int)sizeof(spaces)-1) {
         spaces[sizeof(spaces)-1-len] = 0;
-        fs_file_puts(stdout, spaces);
+        fs_file_puts((fs_file_t*)stdout, spaces);
         spaces[sizeof(spaces)-1-len] = ' ';
     }
 }
@@ -877,17 +876,10 @@ static void prog_main_setparams(qc_program_t *prog) {
         arg->vector[2] = 0;
         switch (main_params[i].vtype) {
             case TYPE_VECTOR:
-#ifdef _MSC_VER
-                (void)sscanf_s(main_params[i].value, " %f %f %f ",
-                               &arg->vector[0],
-                               &arg->vector[1],
-                               &arg->vector[2]);
-#else
-                (void)sscanf(main_params[i].value, " %f %f %f ",
-                             &arg->vector[0],
-                             &arg->vector[1],
-                             &arg->vector[2]);
-#endif
+                (void)util_sscanf(main_params[i].value, " %f %f %f ",
+                                       &arg->vector[0],
+                                       &arg->vector[1],
+                                       &arg->vector[2]);
                 break;
             case TYPE_FLOAT:
                 arg->_float = atof(main_params[i].value);
diff --git a/fs.c b/fs.c
index 501041febe01709a3b965ddb56db813c553bbe97..55e4edced16558d92eb1a69a098826b465247d96 100644 (file)
--- a/fs.c
+++ b/fs.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#define GMQCC_PLATFORM_HEADER
 #include "gmqcc.h"
+#include "platform.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
-#include <crtdbg.h> /* _CrtSetReportMode, _CRT_ASSERT */
-/* {{{ */
-    /*
-     * 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");
-        exit(EXIT_FAILURE);
-    }
-
-    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);
-    }
+fs_file_t *fs_file_open(const char *filename, const char *mode) {
+    return (fs_file_t*)platform_fopen(filename, mode);
+}
 
-    size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
-        return fread(buffer, size, count, fp);
-    }
+size_t fs_file_read(void *buffer, size_t size, size_t count, fs_file_t *fp) {
+    return platform_fread(buffer, size, count, (FILE*)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);
+int fs_file_printf(fs_file_t *fp, const char *format, ...) {
+    int      rt;
+    va_list  va;
+    va_start(va, format);
+    rt = platform_vfprintf((FILE*)fp, format, va);
+    va_end  (va);
 
-        return rt;
-    }
-
-/* }}} */
-#endif
+    return rt;
+}
 
-/*
- * 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);
+void fs_file_close(fs_file_t *fp) {
+    platform_fclose((FILE*)fp);
 }
 
 size_t  fs_file_write (
     const void    *buffer,
     size_t         size,
     size_t         count,
-    FILE          *fp
+    fs_file_t     *fp
 ) {
-    /* Invokes file_exception on windows if fp is null */
-    return fwrite(buffer, size, count, fp);
+    return platform_fwrite(buffer, size, count, (FILE*)fp);
+}
+
+int fs_file_error(fs_file_t *fp) {
+    return platform_ferror((FILE*)fp);
 }
 
-int fs_file_error(FILE *fp) {
-    /* Invokes file_exception on windows if fp is null */
-    return ferror(fp);
+int fs_file_getc(fs_file_t *fp) {
+    int get = platform_fgetc((FILE*)fp);
+    return (get == EOF) ? FS_FILE_EOF : get;
 }
 
-int fs_file_getc(FILE *fp) {
-    /* Invokes file_exception on windows if fp is null */
-    return fgetc(fp);
+int fs_file_puts(fs_file_t *fp, const char *str) {
+    return platform_fputs(str, (FILE*)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(fs_file_t *fp, long int off, int whence) {
+    switch(whence) {
+        case FS_FILE_SEEK_CUR: whence = SEEK_CUR; break;
+        case FS_FILE_SEEK_SET: whence = SEEK_SET; break;
+        case FS_FILE_SEEK_END: whence = SEEK_END; break;
+    }
+    return platform_fseek((FILE*)fp, off, whence);
 }
 
-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);
+long int fs_file_tell(fs_file_t *fp) {
+    return platform_ftell((FILE*)fp);
 }
 
-long int fs_file_tell(FILE *fp) {
-    /* Invokes file_exception on windows if fp is null */
-    return ftell(fp);
+int fs_file_flush(fs_file_t *fp) {
+    return platform_fflush((FILE*)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 fs_file_getline(char **lineptr, size_t *n, fs_file_t *stream) {
     int   chr;
     int   ret;
     char *pos;
@@ -201,7 +115,7 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
             pos = *n - chr + *lineptr;
         }
 
-        if (ferror(stream))
+        if (fs_file_error(stream))
             return -1;
         if (c == EOF) {
             if (pos == *lineptr)
@@ -219,94 +133,18 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
     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;
-
-        util_strncpy(dir->dd_name, name, strlen(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 */)) {
-                    util_strncpy(dirname, dir->dd_name, n);
-                    util_strncpy(dirname + n, "\\*.*", 4);   /* 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)))) {
-            util_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);
-    }
-#else
-#   if !defined(__MINGW32__)
-#       include <sys/stat.h> /* mkdir */
-
-        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_make(const char *path) {
+    return platform_mkdir(path, 0700);
 }
 
-int fs_dir_close(DIR *dir) {
-    return closedir(dir);
+fs_dir_t *fs_dir_open(const char *name) {
+    return (fs_dir_t*)platform_opendir(name);
 }
 
-struct dirent *fs_dir_read(DIR *dir) {
-    return readdir(dir);
+int fs_dir_close(fs_dir_t *dir) {
+    return platform_closedir((DIR*)dir);
 }
 
-#endif /*! defined(_WIN32) && !defined(__MINGW32__) */
+fs_dirent_t *fs_dir_read(fs_dir_t *dir) {
+    return (fs_dirent_t*)platform_readdir((DIR*)dir);
+}
diff --git a/ftepp.c b/ftepp.c
index 050d6d81b92f8f9f2f3a1b8371bd1da77b7d6d84..36bb1a7b59faeca6390ef3ce31fac56e8de5127f 100644 (file)
--- a/ftepp.c
+++ b/ftepp.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <time.h>
 #include <string.h>
 #include <stdlib.h>
+#include <time.h>
 #include <sys/stat.h>
 
 #include "gmqcc.h"
 #include "lexer.h"
 
 #define HT_MACROS 1024
+
 typedef struct {
     bool on;
     bool was_on;
@@ -85,22 +86,14 @@ static uint32_t ftepp_predef_randval  = 0;
 
 /* __DATE__ */
 static char *ftepp_predef_date(lex_file *context) {
-    struct tm *itime = NULL;
-    time_t     rtime;
-    char      *value = (char*)mem_a(82);
-    /* 82 is enough for strftime but we also have " " in our string */
+    const struct tm *itime = NULL;
+    char            *value = (char*)mem_a(82);
+    time_t           rtime;
 
     (void)context;
 
-    /* get time */
     time (&rtime);
-
-#ifdef _MSC_VER
-    localtime_s(itime, &rtime);
-#else
-    itime = localtime(&rtime);
-#endif
-
+    itime = util_localtime(&rtime);
     strftime(value, 82, "\"%b %d %Y\"", itime);
 
     return value;
@@ -108,22 +101,14 @@ static char *ftepp_predef_date(lex_file *context) {
 
 /* __TIME__ */
 static char *ftepp_predef_time(lex_file *context) {
-    struct tm *itime = NULL;
-    time_t     rtime;
-    char      *value = (char*)mem_a(82);
-    /* 82 is enough for strftime but we also have " " in our string */
+    const struct tm *itime = NULL;
+    char            *value = (char*)mem_a(82);
+    time_t           rtime;
 
     (void)context;
 
-    /* get time */
     time (&rtime);
-
-#ifdef _MSC_VER
-    localtime_s(itime, &rtime);
-#else
-    itime = localtime(&rtime);
-#endif
-
+    itime = util_localtime(&rtime);
     strftime(value, 82, "\"%X\"", itime);
 
     return value;
@@ -180,27 +165,14 @@ static char *ftepp_predef_randomlast(lex_file *context) {
 /* __TIMESTAMP__ */
 static char *ftepp_predef_timestamp(lex_file *context) {
     struct stat finfo;
-    char       *find;
+    const char *find;
     char       *value;
     size_t      size;
-#ifdef _MSC_VER
-    char        buffer[64];
-#endif
+
     if (stat(context->name, &finfo))
         return util_strdup("\"<failed to determine timestamp>\"");
 
-    /*
-     * ctime and its fucking annoying newline char, no worries, we're
-     * professionals here.
-     */
-
-#ifndef _MSC_VER
-    find  = ctime(&finfo.st_mtime);
-#else
-    ctime_s(buffer, sizeof(buffer), &finfo.st_mtime);
-    find = buffer;
-#endif
-
+    find = util_ctime(&finfo.st_mtime);
     value = (char*)mem_a(strlen(find) + 1);
     memcpy(&value[1], find, (size = strlen(find)) - 1);
 
@@ -1303,7 +1275,7 @@ static void unescape(const char *str, char *out) {
 
 static char *ftepp_include_find_path(const char *file, const char *pathfile)
 {
-    FILE       *fp;
+    fs_file_t  *fp;
     char       *filename = NULL;
     const char *last_slash;
     size_t      len;
diff --git a/gmqcc.h b/gmqcc.h
index cb70d665e965bda2aed266da5c5fbe609c109c4c..61429f34577bf630975e369e478a431c7d291a9c 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -24,7 +24,8 @@
 #ifndef GMQCC_HDR
 #define GMQCC_HDR
 #include <stdarg.h>
-#include <stdio.h> /* TODO: remove this */
+#include <stddef.h>
+#include <time.h>   /* TODO: remove?*/
 
 /*
  * Disable some over protective warnings in visual studio because fixing them is a waste
@@ -252,46 +253,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
 #   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;
-    /*
-     * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well
-     * which is not hard at all.
-     */
-#    ifdef S_ISDIR
-#        undef  S_ISDIR
-#    endif /*! S_ISDIR */
-#   define S_ISDIR(X) ((X)&_S_IFDIR)
-#else
-#   include <dirent.h>
-#endif /*! _WIN32 && !defined(__MINGW32__) */
-
-/*===================================================================*/
-/*=========================== stat.c ================================*/
-/*===================================================================*/
+/* stat.c */
 void  stat_info          (void);
 char *stat_mem_strdup    (const char *, size_t,         const char *, bool);
 void *stat_mem_reallocate(void *,       size_t, size_t, const char *);
@@ -307,9 +269,7 @@ void *stat_mem_allocate  (size_t, size_t, const char *);
 #define util_strdup(SRC)         stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false)
 #define util_strdupe(SRC)        stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true)
 
-/*===================================================================*/
-/*=========================== util.c ================================*/
-/*===================================================================*/
+/* util.c */
 
 /*
  * Microsoft implements against the spec versions of ctype.h. Which
@@ -329,10 +289,9 @@ void *stat_mem_allocate  (size_t, size_t, const char *);
 #define util_isprint(a) (((unsigned)(a)-0x20) < 0x5F)
 #define util_isspace(a) (((a) >= 9 && (a) <= 13) || (a) == ' ')
 
-bool  util_filexists     (const char *);
 bool  util_strupper      (const char *);
 bool  util_strdigit      (const char *);
-void  util_endianswap    (void *,  size_t, unsigned int);
+void  util_endianswap    (void *, size_t, unsigned int);
 
 size_t util_strtocmd         (const char *, char *, size_t);
 size_t util_strtononcmd      (const char *, char *, size_t);
@@ -343,18 +302,18 @@ uint16_t util_crc16(uint16_t crc, const char *data, size_t len);
 void     util_seed(uint32_t);
 uint32_t util_rand(void);
 
-/*
- * String functions (formatting, copying, concatenating, errors). These are wrapped
- * to use the MSVC _safe_ versions when using MSVC, plus some implementations of
- * these are non-conformant or don't exist such as asprintf and snprintf, which are
- * not supported in C90, but do exist in C99.
- */
-int         util_vasprintf(char **ret, const char *fmt, va_list);
-int         util_asprintf (char **ret, const char *fmt, ...);
-int         util_snprintf (char *src,  size_t bytes, const char *format, ...);
-char       *util_strcat   (char *dest, const char *src);
-char       *util_strncpy  (char *dest, const char *src, size_t num);
-const char *util_strerror (int num);
+int      util_asprintf (char **ret, const char *fmt, ...);
+int      util_sscanf   (const char *str, const char *format, ...);
+char    *util_strncpy  (char *dest, const char *src, size_t n);
+char    *util_strncat  (char *dest, const char *src, size_t n);
+char    *util_strcat   (char *dest, const char *src);
+const char *util_strerror(int err);
+
+const struct tm *util_localtime(const time_t *timer);
+const char      *util_ctime    (const time_t *timer);
+
+typedef struct fs_file_s fs_file_t;
+bool            util_isatty   (fs_file_t *);
 
 /*
  * A flexible vector implementation: all vector pointers contain some
@@ -391,13 +350,6 @@ void _util_vec_grow(void **a, size_t i, size_t s);
 #define vec_append(A,N,S) ((void)(memcpy(vec_add((A), (N)), (S), (N) * sizeof(*(S)))))
 #define vec_remove(A,I,N) ((void)(memmove((A)+(I),(A)+((I)+(N)),sizeof(*(A))*(vec_meta(A)->used-(I)-(N))),vec_meta(A)->used-=(N)))
 
-typedef struct correct_trie_s {
-    void                  *value;
-    struct correct_trie_s *entries;
-} correct_trie_t;
-
-correct_trie_t* correct_trie_new(void);
-
 typedef struct hash_table_s {
     size_t                size;
     struct hash_node_t **table;
@@ -445,34 +397,48 @@ void          util_htrm  (hash_table_t *ht, const char *key, void (*cb)(void*));
 void         *util_htget (hash_table_t *ht, const char *key);
 void         *util_htgeth(hash_table_t *ht, const char *key, size_t hash);
 
-/*===================================================================*/
-/*============================ file.c ===============================*/
-/*===================================================================*/
-/* file handling */
-void           fs_file_close  (FILE *);
-int            fs_file_error  (FILE *);
-int            fs_file_getc   (FILE *);
-int            fs_file_printf (FILE *, const char *, ...);
-int            fs_file_puts   (FILE *, const char *);
-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 */
+int           util_snprintf(char *str, size_t, const char *fmt, ...);
+
+
+/* fs.c */
+#define FS_FILE_SEEK_SET  0
+#define FS_FILE_SEEK_CUR  1
+#define FS_FILE_SEEK_END  2
+#define FS_FILE_EOF      -1
+
+typedef struct fs_dir_s  fs_dir_t;
+/*typedef struct fs_file_s fs_file_t;*/
+typedef struct dirent    fs_dirent_t;
+
+void           fs_file_close  (fs_file_t *);
+int            fs_file_error  (fs_file_t *);
+int            fs_file_getc   (fs_file_t *);
+int            fs_file_printf (fs_file_t *, const char *, ...);
+int            fs_file_puts   (fs_file_t *, const char *);
+int            fs_file_seek   (fs_file_t *, long int, int);
+long           fs_file_tell   (fs_file_t *);
+int            fs_file_flush  (fs_file_t *);
+
+size_t         fs_file_read   (void *,        size_t, size_t, fs_file_t *);
+size_t         fs_file_write  (const void *,  size_t, size_t, fs_file_t *);
+
+fs_file_t     *fs_file_open   (const char *, const char *);
+int            fs_file_getline(char  **, size_t *, fs_file_t *);
+
 int            fs_dir_make    (const char *);
-DIR           *fs_dir_open    (const char *);
-int            fs_dir_close   (DIR *);
-struct dirent *fs_dir_read    (DIR *);
+fs_dir_t      *fs_dir_open    (const char *);
+int            fs_dir_close   (fs_dir_t *);
+fs_dirent_t   *fs_dir_read    (fs_dir_t *);
 
 
-/*===================================================================*/
-/*=========================== correct.c =============================*/
-/*===================================================================*/
+/* correct.c */
+typedef struct correct_trie_s {
+    void                  *value;
+    struct correct_trie_s *entries;
+} correct_trie_t;
+
+correct_trie_t* correct_trie_new(void);
+
 typedef struct {
     char   ***edits;
     size_t  **lens;
@@ -484,9 +450,8 @@ char *correct_str (correction_t *, correct_trie_t*, const char *);
 void  correct_init(correction_t *);
 void  correct_free(correction_t *);
 
-/*===================================================================*/
-/*=========================== code.c ================================*/
-/*===================================================================*/
+
+/* code.c */
 
 /* Note: if you change the order, fix type_sizeof in ir.c */
 enum {
@@ -783,9 +748,7 @@ void      code_push_statement(code_t *, prog_section_statement_t *stmt, lex_ctx_
 void      code_pop_statement (code_t *);
 
 
-/*===================================================================*/
-/*============================ con.c ================================*/
-/*===================================================================*/
+/* conout.c */
 enum {
     CON_BLACK   = 30,
     CON_RED,
@@ -804,8 +767,8 @@ enum {
     LVL_ERROR
 };
 
-FILE *con_default_out(void);
-FILE *con_default_err(void);
+fs_file_t *con_default_out(void);
+fs_file_t *con_default_err(void);
 
 void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap);
 void con_printmsg  (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...);
@@ -833,10 +796,8 @@ bool GMQCC_WARN compile_warning (lex_ctx_t ctx, int warntype, const char *fmt, .
 bool GMQCC_WARN vcompile_warning(lex_ctx_t ctx, int warntype, const char *fmt, va_list ap);
 void            compile_show_werrors(void);
 
-/*===================================================================*/
-/*============================= ir.c ================================*/
-/*===================================================================*/
-
+/* ir.c */
+/* TODO: cleanup */
 enum store_types {
     store_global,
     store_local,  /* local, assignable for now, should get promoted later */
@@ -849,9 +810,7 @@ typedef struct {
     qcfloat_t x, y, z;
 } vec3_t;
 
-/*===================================================================*/
-/*============================= exec.c ==============================*/
-/*===================================================================*/
+/* exec.c */
 
 /* TODO: cleanup */
 /*
@@ -944,9 +903,7 @@ qcany_t*            prog_getedict  (qc_program_t *prog, qcint_t e);
 qcint_t               prog_tempstring(qc_program_t *prog, const char *_str);
 
 
-/*===================================================================*/
-/*===================== parser.c commandline ========================*/
-/*===================================================================*/
+/* parser.c */
 struct parser_s;
 struct parser_s *parser_create        (void);
 bool             parser_compile_file  (struct parser_s *parser, const char *);
@@ -954,9 +911,7 @@ bool             parser_compile_string(struct parser_s *parser, const char *, co
 bool             parser_finish        (struct parser_s *parser, const char *);
 void             parser_cleanup       (struct parser_s *parser);
 
-/*===================================================================*/
-/*====================== ftepp.c commandline ========================*/
-/*===================================================================*/
+/* ftepp.c */
 struct ftepp_s;
 struct ftepp_s *ftepp_create           (void);
 bool            ftepp_preprocess_file  (struct ftepp_s *ftepp, const char *filename);
@@ -967,9 +922,7 @@ void            ftepp_flush            (struct ftepp_s *ftepp);
 void            ftepp_add_define       (struct ftepp_s *ftepp, const char *source, const char *name);
 void            ftepp_add_macro        (struct ftepp_s *ftepp, const char *name,   const char *value);
 
-/*===================================================================*/
-/*======================= main.c commandline ========================*/
-/*===================================================================*/
+/* main.c */
 
 #if 1
 /* Helpers to allow for a whole lot of flags. Otherwise we'd limit
@@ -987,16 +940,12 @@ typedef uint32_t longbit;
 #define LONGBIT_SET(B, I) ((B) = (I))
 #endif
 
-/*===================================================================*/
-/*============================= utf8.c ==============================*/
-/*===================================================================*/
+/* utf.8 */
 typedef long utf8ch_t;
 int utf8_from(char *, utf8ch_t);
 int utf8_to(utf8ch_t *, const unsigned char *, size_t);
 
-/*===================================================================*/
-/*============================= opts.c ==============================*/
-/*===================================================================*/
+/* opts.c */
 typedef struct {
     const char *name;
     longbit     bit;
index 20ffdd48aad6b4eafb5569fcf50e56a8fc0110f4..f95ff7cb697c91c82633ec0af99368bbca97834f 100644 (file)
@@ -13,11 +13,14 @@ CC      ?= clang
 LDFLAGS +=
 LIBS    += -lm
 
+#common objects
+COMMON   = ansi.o util.o stat.o fs.o opts.o conout.o
+
 #objects
-OBJ_C = main.o lexer.o parser.o fs.o stat.o util.o code.o ast.o ir.o conout.o ftepp.o opts.o utf8.o correct.o fold.o intrin.o
-OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o
-OBJ_T = test.o util.o opts.o conout.o fs.o stat.o
-OBJ_X = exec-standalone.o util.o opts.o conout.o fs.o stat.o
+OBJ_C = $(COMMON) main.o lexer.o parser.o code.o ast.o ir.o ftepp.o utf8.o correct.o fold.o intrin.o
+OBJ_P = $(COMMON) pak.o
+OBJ_T = $(COMMON) test.o
+OBJ_X = $(COMMON) exec-standalone.o
 
 #gource flags
 GOURCEFLAGS =                 \
diff --git a/ir.c b/ir.c
index f0274e11bb5795a1deb26b879f060b448f34c5de..9967d7d8dbd91649a62c55b69772a91fa3c6e2de 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -3977,10 +3977,6 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
 
 #define IND_BUFSZ 1024
 
-#ifdef _MSC_VER
-#   define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
-#endif
-
 static const char *qc_opname(int op)
 {
     if (op < 0) return "<INVALID>";
@@ -4039,7 +4035,7 @@ void ir_function_dump(ir_function *f, char *ind,
         return;
     }
     oprintf("%sfunction %s\n", ind, f->name);
-    strncat(ind, "\t", IND_BUFSZ-1);
+    util_strncat(ind, "\t", IND_BUFSZ-1);
     if (vec_size(f->locals))
     {
         oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
@@ -4135,7 +4131,7 @@ void ir_block_dump(ir_block* b, char *ind,
 {
     size_t i;
     oprintf("%s:%s\n", ind, b->label);
-    strncat(ind, "\t", IND_BUFSZ-1);
+    util_strncat(ind, "\t", IND_BUFSZ-1);
 
     if (b->instr && b->instr[0])
         oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1));
@@ -4169,7 +4165,7 @@ void ir_instr_dump(ir_instr *in, char *ind,
         return;
     }
 
-    strncat(ind, "\t", IND_BUFSZ-1);
+    util_strncat(ind, "\t", IND_BUFSZ-1);
 
     if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
         ir_value_dump(in->_ops[0], oprintf);
diff --git a/lexer.c b/lexer.c
index 5882bdbfc2e76f2100e12006194e001f55da90c1..6c8ccd9db127c82c11996ccf82a08037e196c840 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -25,6 +25,7 @@
 
 #include "gmqcc.h"
 #include "lexer.h"
+
 /*
  * List of Keywords
  */
@@ -179,8 +180,8 @@ static void lex_token_new(lex_file *lex)
 
 lex_file* lex_open(const char *file)
 {
-    lex_file *lex;
-    FILE *in = fs_file_open(file, "rb");
+    lex_file  *lex;
+    fs_file_t *in = fs_file_open(file, "rb");
 
     if (!in) {
         lexerror(NULL, "open failed: '%s'\n", file);
@@ -273,11 +274,11 @@ static int lex_fgetc(lex_file *lex)
     }
     if (lex->open_string) {
         if (lex->open_string_pos >= lex->open_string_length)
-            return EOF;
+            return FS_FILE_EOF;
         lex->column++;
         return lex->open_string[lex->open_string_pos++];
     }
-    return EOF;
+    return FS_FILE_EOF;
 }
 
 /* Get or put-back data
@@ -493,7 +494,7 @@ static bool lex_try_pragma(lex_file *lex)
         goto unroll;
 
     lex->line = line;
-    while (ch != '\n' && ch != EOF)
+    while (ch != '\n' && ch != FS_FILE_EOF)
         ch = lex_getch(lex);
     vec_free(command);
     vec_free(param);
@@ -573,7 +574,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
     do
     {
         ch = lex_getch(lex);
-        while (ch != EOF && util_isspace(ch)) {
+        while (ch != FS_FILE_EOF && util_isspace(ch)) {
             if (ch == '\n') {
                 if (lex_try_pragma(lex))
                     continue;
@@ -613,7 +614,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
                     lex_tokench(lex, ' ');
                 }
 
-                while (ch != EOF && ch != '\n') {
+                while (ch != FS_FILE_EOF && ch != '\n') {
                     if (lex->flags.preprocessing)
                         lex_tokench(lex, ' '); /* ch); */
                     ch = lex_getch(lex);
@@ -638,7 +639,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
                     lex_tokench(lex, ' ');
                 }
 
-                while (ch != EOF)
+                while (ch != FS_FILE_EOF)
                 {
                     ch = lex_getch(lex);
                     if (ch == '*') {
@@ -671,7 +672,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
             ch = '/';
             break;
         }
-    } while (ch != EOF && util_isspace(ch));
+    } while (ch != FS_FILE_EOF && util_isspace(ch));
 
     if (haswhite) {
         lex_endtoken(lex);
@@ -687,7 +688,7 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
     int ch;
 
     ch = lex_getch(lex);
-    while (ch != EOF && isident(ch))
+    while (ch != FS_FILE_EOF && isident(ch))
     {
         lex_tokench(lex, ch);
         ch = lex_getch(lex);
@@ -707,7 +708,7 @@ static int lex_parse_frame(lex_file *lex)
     lex_token_new(lex);
 
     ch = lex_getch(lex);
-    while (ch != EOF && ch != '\n' && util_isspace(ch))
+    while (ch != FS_FILE_EOF && ch != '\n' && util_isspace(ch))
         ch = lex_getch(lex);
 
     if (ch == '\n')
@@ -768,7 +769,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
     char u8buf[8]; /* way more than enough */
     int  u8len, uc;
 
-    while (ch != EOF)
+    while (ch != FS_FILE_EOF)
     {
         ch = lex_getch(lex);
         if (ch == quote)
@@ -777,18 +778,18 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
         if (lex->flags.preprocessing && ch == '\\') {
             lex_tokench(lex, ch);
             ch = lex_getch(lex);
-            if (ch == EOF) {
+            if (ch == FS_FILE_EOF) {
                 lexerror(lex, "unexpected end of file");
-                lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
+                lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
                 return (lex->tok.ttype = TOKEN_ERROR);
             }
             lex_tokench(lex, ch);
         }
         else if (ch == '\\') {
             ch = lex_getch(lex);
-            if (ch == EOF) {
+            if (ch == FS_FILE_EOF) {
                 lexerror(lex, "unexpected end of file");
-                lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
+                lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
                 return (lex->tok.ttype = TOKEN_ERROR);
             }
 
@@ -911,7 +912,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
             lex_tokench(lex, ch);
     }
     lexerror(lex, "unexpected end of file within string constant");
-    lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
+    lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
     return (lex->tok.ttype = TOKEN_ERROR);
 }
 
@@ -1032,7 +1033,7 @@ int lex_do(lex_file *lex)
     if (lex->eof)
         return (lex->tok.ttype = TOKEN_FATAL);
 
-    if (ch == EOF) {
+    if (ch == FS_FILE_EOF) {
         lex->eof = true;
         return (lex->tok.ttype = TOKEN_EOF);
     }
@@ -1069,7 +1070,7 @@ int lex_do(lex_file *lex)
         if (!strcmp(v, "framevalue"))
         {
             ch = lex_getch(lex);
-            while (ch != EOF && util_isspace(ch) && ch != '\n')
+            while (ch != FS_FILE_EOF && util_isspace(ch) && ch != '\n')
                 ch = lex_getch(lex);
 
             if (!util_isdigit(ch)) {
@@ -1149,7 +1150,7 @@ int lex_do(lex_file *lex)
             vec_free(lex->frames);
             /* skip line (fteqcc does it too) */
             ch = lex_getch(lex);
-            while (ch != EOF && ch != '\n')
+            while (ch != FS_FILE_EOF && ch != '\n')
                 ch = lex_getch(lex);
             return lex_do(lex);
         }
@@ -1163,7 +1164,7 @@ int lex_do(lex_file *lex)
         {
             /* skip line */
             ch = lex_getch(lex);
-            while (ch != EOF && ch != '\n')
+            while (ch != FS_FILE_EOF && ch != '\n')
                 ch = lex_getch(lex);
             return lex_do(lex);
         }
@@ -1473,14 +1474,10 @@ int lex_do(lex_file *lex)
         lex_endtoken(lex);
 
         lex->tok.ttype = TOKEN_CHARCONST;
-         /* It's a vector if we can successfully scan 3 floats */
-#ifdef _MSC_VER
-        if (sscanf_s(lex->tok.value, " %f %f %f ",
-                   &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
-#else
-        if (sscanf(lex->tok.value, " %f %f %f ",
+
+        /* It's a vector if we can successfully scan 3 floats */
+        if (util_sscanf(lex->tok.value, " %f %f %f ",
                    &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
-#endif
 
         {
              lex->tok.ttype = TOKEN_VECTORCONST;
diff --git a/lexer.h b/lexer.h
index 24e29ddee4080659be406da5f073ef041ecdb115..3184fcc3ecf2bbb0b911fa7c5ad40fd942d6d688 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -105,7 +105,7 @@ typedef struct {
 } frame_macro;
 
 typedef struct lex_file_s {
-    FILE   *file;
+    fs_file_t  *file;
     const char *open_string;
     size_t      open_string_length;
     size_t      open_string_pos;
diff --git a/main.c b/main.c
index 9a76706b06653412f017945dde44aa891ccdc06e..74d927daf98187ef4bff8cff4983d20ee341d0e9 100644 (file)
--- a/main.c
+++ b/main.c
@@ -531,7 +531,7 @@ static bool options_parse(int argc, char **argv) {
 }
 
 /* returns the line number, or -1 on error */
-static bool progs_nextline(char **out, size_t *alen,FILE *src) {
+static bool progs_nextline(char **out, size_t *alen, fs_file_t *src) {
     int    len;
     char  *line;
     char  *start;
@@ -562,7 +562,7 @@ int main(int argc, char **argv) {
     bool            opts_output_free = false;
     bool            operators_free   = false;
     bool            progs_src        = false;
-    FILE            *outfile         = NULL;
+    fs_file_t       *outfile         = NULL;
     struct parser_s *parser          = NULL;
     struct ftepp_s  *ftepp           = NULL;
 
@@ -667,10 +667,10 @@ int main(int argc, char **argv) {
     }
 
     if (!vec_size(items)) {
-        FILE  *src;
-        char  *line    = NULL;
-        size_t linelen = 0;
-        bool   hasline = false;
+        fs_file_t *src;
+        char      *line    = NULL;
+        size_t     linelen = 0;
+        bool       hasline = false;
 
         progs_src = true;
 
diff --git a/msvc.c b/msvc.c
new file mode 100644 (file)
index 0000000..e6e9256
--- /dev/null
+++ b/msvc.c
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+#define GMQCC_PLATFORM_HEADER
+#include <string.h>
+#include <stdlib.h>
+
+#include "platform.h"
+
+#define CTIME_BUFFER    64
+#define GETENV_BUFFER   4096
+#define STRERROR_BUFFER 128
+
+static void **platform_mem_pool = NULL;
+static void platform_mem_atexit() {
+    size_t i;
+    for (i = 0; i < vec_size(platform_mem_pool); i++)
+        mem_d(platform_mem_pool[i]);
+    vec_free(platform_mem_pool);
+}
+
+static void *platform_mem_allocate(size_t bytes) {
+    void *mem = NULL;
+    if (!platform_mem_pool) {
+        atexit(&platform_mem_atexit);
+        vec_push(platform_mem_pool, NULL);
+    }
+
+    mem = mem_a(bytes);
+    vec_push(platform_mem_pool, mem);
+
+    return mem;
+}
+
+int platform_vsnprintf(char *buffer, size_t bytes, const char *format, va_list arg) {
+    vsnprintf_s(buffer, bytes, bytes, format, arg);
+}
+
+int platform_vsscanf(const char *str, const char *format, va_list va) {
+    return vsscanf_s(str, format, va);
+}
+
+const struct tm *platform_localtime(const time_t *timer) {
+    struct tm *t;
+    t = (struct tm*)platform_mem_allocate(sizeof(struct tm));
+    localtime_s(&t, timer);
+    return t;
+}
+
+const char *platform_ctime(const time_t *timer) {
+    char *buffer = (char *)platform_mem_allocate(CTIME_BUFFER);
+    ctime_s(buffer, CTIME_BUFFER, timer);
+    return buffer;
+}
+
+char *platform_strncat(char *dest, const char *src, size_t num) {
+    return strncat_s(dest, num, src, _TRUNCATE);
+}
+
+const char *platform_tmpnam(char *str) {
+    return tmpnam_s(str, L_tmpnam);
+}
+
+const char *platform_getenv(char *var) {
+    char  *buffer = (char *)platform_mem_allocate(GETENV_BUFFER);
+    size_t size;
+    getenv_s(&size, buffer, GETENV_BUFFER, var);
+    return buffer;
+}
+
+/*
+ * TODO: this isn't exactly 'accurate' for MSVC but it seems to work,
+ * at least to some extent.
+ */
+int platform_vasprintf(char **dat, const char *fmt, va_list args) {
+    int   ret;
+    int   len;
+    char *tmp = NULL;
+
+    if ((len = _vscprintf(fmt, args)) < 0) {
+        *dat = NULL;
+        return -1;
+    }
+
+    tmp = (char*)mem_a(len + 1);
+    if ((ret = _vsnprintf_s(tmp, len+1, len+1, fmt, args)) != len) {
+        mem_d(tmp);
+        *dat = NULL;
+        return -1;
+    }
+    *dat = tmp;
+    return len;
+}
+
+char *platform_strcat(char *dest, const char *src) {
+    strcat_s(dest, strlen(src), src);
+    return dest;
+}
+
+char *platform_strncpy(char *dest, const char *src, size_t num) {
+    strncpy_s(dest, num, src, num);
+    return dest;
+}
+
+const char *platform_strerror(int err) {
+    char *buffer = (char*)platform_mem_allocate(STRERROR_BUFFER);
+    strerror_s(buffer, STRERROR_BUFFER, err);
+    return buffer;
+}
+
+FILE *platform_fopen(const char *filename, const char *mode) {
+    FILE *handle;
+    return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
+}
+
+size_t platform_fread(void *ptr, size_t size, size_t count, FILE *stream) {
+    return fread_s(ptr, size, size, count, stream);
+}
+
+size_t platform_fwrite(const void *ptr, size_t size, size_t count, FILE *stream) {
+    return fwrite(ptr, size, count, stream);
+}
+
+int platform_fflush(FILE *stream) {
+    return fflush(stream);
+}
+
+int platform_vfprintf(FILE *stream, const char *format, va_list arg) {
+    return vfprintf_s(stream, format, arg);
+}
+
+int platform_fclose(FILE *stream) {
+    return fclose(stream);
+}
+
+int platform_ferror(FILE *stream) {
+    return ferror(stream);
+}
+
+int platform_fgetc(FILE *stream) {
+    return fgetc(stream);
+}
+
+int platform_fputs(const char *str, FILE *stream) {
+    return fputs(str, stream);
+}
+
+int platform_fseek(FILE *stream, long offset, int origin) {
+    return fseek(stream, offset, origin);
+}
+
+long platform_ftell(FILE *stream) {
+    return ftell(stream);
+}
+
+int platform_mkdir(const char *path, int mode) {
+    return mkdir(path, mode);
+}
+
+DIR *platform_opendir(const char *path) {
+    DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(path));
+    if (!dir)
+        return NULL;
+
+    platform_strncpy(dir->dd_name, path, strlen(path));
+    return dir;
+}
+
+int platform_closedir(DIR *dir) {
+    FindClose((HANDLE)dir->dd_handle);
+    mem_d((void*)dir);
+    return 0;
+}
+
+struct dirent *platform_readdir(DIR *dir) {
+    WIN32_FIND_DATA info;
+    struct dirent  *data;
+    int             ret;
+
+    if (!dir->dd_handle) {
+        char *dirname;
+        if (*dir->dd_name) {
+            size_t n = strlen(dir->dd_name);
+            if ((dir = (char*)mem_a(n+5))) {
+                platform_strncpy(dirname,     dir->dd_name, n);
+                platform_strncpy(dirname + n, "\\*.*",      4);
+            }
+        } else {
+            if (!(dirname = util_strdup("\\*.*")))
+                return NULL;
+        }
+
+        dir->dd_handle = (long)FindFirstFile(dirname, &info);
+        mem_d(dirname);
+        ret = !(!dir->dd_handle);
+    } else if (dir->dd_handle != -11) {
+        ret = FindNextFile((HANDLE)dir->dd_handle, &info);
+    } else {
+        ret = 0;
+    }
+
+    if (!ret)
+        return NULL;
+
+    if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
+        platform_strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
+        data->d_name[FILENAME_MAX - 1] = '\0';
+        data->d_namelen                = strlen(data->d_name);
+    }
+
+    return data;
+}
+
+int platform_istty(int fd) {
+    return _isatty(fd);
+}
diff --git a/opts.c b/opts.c
index 27d6a560473ead2f183a8adbeffc95c3fd470901..1d8fd73597d6f4ae0d2861347e6422f466bc9891 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -213,7 +213,7 @@ static char *opts_ini_next(const char *s, char c) {
 }
 
 static size_t opts_ini_parse (
-    FILE   *filehandle,
+    fs_file_t *filehandle,
     char *(*loadhandle)(const char *, const char *, const char *),
     char **errorhandle
 ) {
@@ -230,7 +230,7 @@ static size_t opts_ini_parse (
     char *read_name;
     char *read_value;
 
-    while (fs_file_getline(&line, &linesize, filehandle) != EOF) {
+    while (fs_file_getline(&line, &linesize, filehandle) != FS_FILE_EOF) {
         parse_beg = line;
 
         /* handle BOM */
@@ -380,7 +380,7 @@ void opts_ini_init(const char *file) {
      */
     char       *error = NULL;
     size_t     line;
-    FILE       *ini;
+    fs_file_t  *ini;
 
     if (!file) {
         /* try ini */
diff --git a/pak.c b/pak.c
index 0b3f2216e2b4777c7892cedc0d04f72dfd4378f4..6fdd88b83a61b9e288b0849f2151c250ab288272 100644 (file)
--- a/pak.c
+++ b/pak.c
@@ -124,7 +124,7 @@ static void pak_tree_build(const char *entry) {
 typedef struct {
     pak_directory_t *directories;
     pak_header_t     header;
-    FILE            *handle;
+    fs_file_t       *handle;
     bool             insert;
 } pak_file_t;
 
@@ -162,7 +162,7 @@ static pak_file_t *pak_open_read(const char *file) {
      * 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);
+    fs_file_seek(pak->handle, pak->header.diroff, FS_FILE_SEEK_SET);
 
     /*
      * Read in all directories from the PAK file. These are considered
@@ -266,7 +266,7 @@ static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdi
     pak_directory_t *dir   = NULL;
     unsigned char   *dat   = NULL;
     char            *local = NULL;
-    FILE            *out   = NULL;
+    fs_file_t       *out   = NULL;
 
     if (!pak_exists(pak, file, &dir)) {
         return false;
@@ -295,7 +295,7 @@ static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdi
     mem_d(local);
 
     /* read */
-    if (fs_file_seek (pak->handle, dir->pos, SEEK_SET) != 0)
+    if (fs_file_seek (pak->handle, dir->pos, FS_FILE_SEEK_SET) != 0)
         goto err;
 
     fs_file_read (dat, 1, dir->len, pak->handle);
@@ -333,7 +333,7 @@ static bool pak_insert_one(pak_file_t *pak, const char *file) {
     pak_directory_t dir;
     unsigned char  *dat;
     long            len;
-    FILE           *fp;
+    fs_file_t      *fp;
 
     /*
      * We don't allow insertion on files that already exist within the
@@ -351,9 +351,9 @@ static bool pak_insert_one(pak_file_t *pak, const char *file) {
      * the directory entry, and the actual contents of the file
      * to the PAK file itself.
      */
-    if (fs_file_seek(fp, 0, SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0))
+    if (fs_file_seek(fp, 0, FS_FILE_SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0))
         goto err;
-    if (fs_file_seek(fp, 0, SEEK_SET) != 0)
+    if (fs_file_seek(fp, 0, FS_FILE_SEEK_SET) != 0)
         goto err;
 
     dir.len = len;
@@ -438,18 +438,17 @@ static bool pak_close(pak_file_t *pak) {
         pak->header.diroff = tell;
 
         /* patch header */
-        if (fs_file_seek (pak->handle, 0, SEEK_SET) != 0)
+        if (fs_file_seek (pak->handle, 0, FS_FILE_SEEK_SET) != 0)
             goto err;
 
         fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
 
         /* write directories */
-        if (fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET) != 0)
+        if (fs_file_seek (pak->handle, pak->header.diroff, FS_FILE_SEEK_SET) != 0)
             goto err;
 
-        for (itr = 0; itr < vec_size(pak->directories); itr++) {
+        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);
@@ -496,6 +495,7 @@ static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out,
     return true;
 }
 
+#include <stdio.h>
 int main(int argc, char **argv) {
     bool          extract   = true;
     char         *redirout  = (char*)stdout;
index eeec52e01ea9ce0cd345135b73f25cedf2bdc469..30a9d7866ef691f06768f2cb496228d4439077d5 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -23,6 +23,7 @@
  */
 #include <string.h>
 #include <math.h>
+
 #include "parser.h"
 
 #define PARSER_HT_LOCALS  2
@@ -5912,7 +5913,7 @@ parser_t *parser_create()
         }
     }
     if (!parser->assign_op) {
-        printf("internal error: initializing parser: failed to find assign operator\n");
+        con_err("internal error: initializing parser: failed to find assign operator\n");
         mem_d(parser);
         return NULL;
     }
diff --git a/platform.h b/platform.h
new file mode 100644 (file)
index 0000000..27abc64
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * 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.
+ */
+
+#ifndef GMQCC_PLATFORM_HDR
+#define GMQCC_PLATFORM_HDR
+
+#ifndef GMQCC_PLATFORM_HEADER
+#   error "This header shouldn't be included!"
+#endif
+
+#undef GMQCC_PLATFORM_HEADER
+#include <stdarg.h>
+#include <time.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#   ifndef STDERR_FILENO
+#       define STDERR_FILENO 2
+#   endif
+#   ifndef STDOUT_FILENO
+#       define STDOUT_FILENO 1
+#   endif
+#   ifndef __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;
+
+#       ifdef S_ISDIR
+#           undef  S_ISDIR
+#       endif /*! S_ISDIR */
+#       define S_ISDIR(X) ((X)&_S_IFDIR)
+#   else
+#       include <dirent.h>
+#   endif /*!__MINGW32__*/
+#else
+#   include <sys/types.h>
+#   include <sys/stat.h>
+#   include <unistd.h>
+#   include <dirent.h>
+#endif /*!_WIN32*/
+
+/*
+ * Function: platform_vsnprintf
+ *  Write formatted output using a pointer to a lis of arguments.
+ *
+ * Parameters:
+ *  buffer - Storage location for output.
+ *  bytes  - Maximum number of characters to write.
+ *  format - Format specification.
+ *  arg    - Variable argument list.
+ *
+ * Returns:
+ *  The number of characters written if the number of characters to write
+ *  is less than or equal to `bytes`; if the number of characters to write
+ *  is greater than `bytes`, this function returns -1 indicating that the
+ *  output has been truncated. The return value does not include the
+ *  terminating null, if one is written.
+ *
+ * Remarks:
+ *  Function takes pointer to an argument list, then formats the data,
+ *  and writes up to `bytes` characters to the memory pointed to by
+ *  `buffer`. If there is room at the end (that is, if the number of
+ *  character to write is less than `bytes`), the buffer will be null-terminated.
+ */
+int platform_vsnprintf(char *buffer, size_t bytes, const char *format, va_list arg);
+
+/*
+ * Function: platform_vsscanf
+ *  Reads formatted data from a string.
+ *
+ * Parameters:
+ *  buffer - Stored data to read.
+ *  format - Format specification.
+ *  arg    - Variable argument list.
+ *
+ * Returns:
+ *  The number of fields that are successfully converted and assigned;
+ *  the return value does not include fields that were read but not
+ *  assigned. A return vlaue of 0 indicated that no fields were assigned.
+ *  The return value if EOF for error or if the end of the string is
+ *  reached before the first conversion.
+ *
+ * Remarks:
+ *  Reads data from `buffer` into the locations that are given by each
+ *  argument in the `arg` argument list. Every argument in the list must
+ *  be a pointer to a variable that has a type that corresponds to a
+ *  type specifier in `format`. The `format` argument controls th
+ *  interpretation of the input fields and has the same form and function
+ *  as the `format` argument for the *scanf* function. If copying takes
+ *  place between strings that overlap, the behaviour is undefined.
+ */
+int platform_vsscanf(const char *buffer, const char *format, va_list arg);
+
+/*
+ * Function: platform_localtime
+ *  Convert a time value and correct for the local time zone.
+ *
+ * Parameters
+ *  timer - Pointer to stored time.
+ *
+ * Returns:
+ *  A pointer to a structure result, or NULL if the date passed to
+ *  the function is before midnight, January 1, 1970.
+ */
+const struct tm *platform_localtime(const time_t *timer);
+
+/*
+ * Function: platform_ctime
+ *  Convert a time value to a string and adjust for local time zone
+ *  settings.
+ *
+ * Parameters:
+ *  timer - Pointer to stored time.
+ *
+ * Returns:
+ *  Pointer to the character string result. NULL will be returned if time
+ *  represents a date before midnight, January 1, 1970, UTC.
+ *
+ * Remarks:
+ *  Converts a time value stored as a `time_t` value into a chracter string.
+ *  The `timer` value is usually obtained from a call to *time*, which returns
+ *  the number of seconds since midnight, January 1, 1970 UTC. The return
+ *  value of the string contains exactly 26 characters. A 24-hour clock is used.
+ *  All fields have constant width. The newline chracter and the null character
+ *  occupy the last two positions of the string. The converted character string
+ *  is also adjusted according to the local time zone settings.
+ */
+const char *platform_ctime(const time_t *timer);
+
+/*
+ * Function: platform_strncat
+ *  Append characters of a string.
+ *
+ * Parameters:
+ *  dest - Null terminated destination string
+ *  src  - Source string
+ *  num  - Number of characters to append
+ *
+ * Returns:
+ *  Pointer to the destination string. No return value is used to indicate
+ *  an error.
+ *
+ * Remarks:
+ *  Function appends, at mode, the first `num` characters of `src` to
+ *  `dest`. The initial character of `src` overwrites the terminating
+ *  null chracter of `dest`. If a null character appears in `src` before
+ *  `num` chracters are appended, `platform_strncat` appends all chracters
+ *  from `src`, up to the null chracter. If `num` is greater than the
+ *  length of `src`, the length of `src` is used in place of `num`.
+ */
+char *platform_strncat(char *dest, const char *src, size_t num);
+
+/*
+ * Function: platform_tmpnam
+ *  Generates names you can use to create temporary files.
+ *
+ * Parameters:
+ *  str - Pointer that will hold the generated name and will be identical
+ *        to the name returned by the function. This is a convenient way
+ *        to save the generated name.
+ *
+ * Returns:
+ *  Pointer to the name generate or *NULL* if there is a failure. Failure
+ *  can occur if you attempt more than TMP_MAX calls.
+ *
+ * Remarks:
+ *  Returns a name unique in the current workign directory.
+ */
+const char *platform_tmpnam(char *str);
+
+/*
+ * Function: platform_getenv
+ *  Get a value from the current enviroment.
+ *
+ * Parameters:
+ *  var - Enviroment variable name
+ *
+ * Returns:
+ *  A pointer to the enviroment table entry containing `var. It's not
+ *  safe to modify the value of the enviroment variable using the returned
+ *  pointer. The return value is *NULL* if `var` is not found in the
+ *  enviroment table.
+ */
+const char *platform_getenv(char *var);
+
+/*
+ * Function: platform_vasprintf
+ *  Print to allocated string
+ *
+ * Parameters:
+ *  dat  - Pointer to pointer to store allocated data.
+ *  fmt  - Format specification.
+ *  args - Variable argument list.
+ *
+ * Returns:
+ *  Number of character written, -1 is used to indicate an error.
+ *
+ * Remarks:
+ *  Allocate a string large enough to hold the output including
+ *  the terminating null character than write formatted output
+ *  to it using format specification.
+ */
+int platform_vasprintf(char **dat, const char *fmt, va_list args);
+
+/*
+ * Function: platform_vfprintf
+ *  Write formatted output using a pointer to a list of arguments.
+ *
+ * Parameters:
+ *  stream - Pointer to stream.
+ *  format - Format specification.
+ *  atrg   - Variable argument list.
+ *
+ * Returns:
+ *  Number of characters written, not including the terminating null
+ *  character, or a negitive value if an output error occurs. -1 is
+ *  also used to indicate an error.
+ *
+ * Remarks:
+ *  Takes a pointer to an argument list, then formats and writes the
+ *  given data to `stream`.
+ */
+int platform_vfprintf(FILE *stream, const char *format, va_list arg);
+
+/*
+ * Function: platform_strcat
+ *  Append characters of a string.
+ *
+ * Parameters:
+ *  dest - Null terminated destination string
+ *  src  - Source string
+ *
+ * Returns:
+ *  Pointer to the destination string. No return value is used to indicate
+ *  an error.
+ *
+ * Remarks:
+ *  Appens `src` to `dest` and terminates with resulting null character.
+ *  The initial character of `src` overwrites the terminating null
+ *  character of `dest`. The behaviour of platform_strcat is undefined
+ *  if the source and destination string overlap.
+ */
+char *platform_strcat(char *dest, const char *src);
+
+/*
+ * Function: platform_strncpy
+ *  Copys characters of one string to another.
+ *
+ * Parameters:
+ *  dest - Destination string.
+ *  src  - Source string.
+ *  num  - Number of characters to be copied.
+ *
+ * Returns:
+ *  `dest`. No return value is reserved to indicate an error.
+ *
+ * Remarks:
+ *  Copies the initial characters of `src` to `dest` and returns `dest`.
+ *  If `num` is less than or equal to the length of `src1 a null character
+ *  is not appended automatically to the copied string. If `num` is greater
+ *  than the length of `src`, the destination string is padded with null
+ *  characters up to length `num`. The behaviour of this function is undefined
+ *  if the source and destination strings overlap.
+ */
+char *platform_strncpy(char *dest, const char *src, size_t num);
+
+/*
+ * Function: platform_strerror
+ *  Get a system error message
+ *
+ * Parameters:
+ *  err - Error number.
+ *
+ * Returns:
+ *  A pointer to the error message
+ */
+const char *platform_strerror(int err);
+
+/*
+ * Function: platform_fopen
+ *  Opens a file
+ *
+ * Parameters:
+ *  filename - File name.
+ *  mode     - Kind of access that's enabled.
+ *
+ * Returns:
+ *  A pointer to the open file. A null pointer value indicates an error.
+ */
+FILE *platform_fopen(const char *filename, const char *mode);
+
+/*
+ * Function: platform_fread
+ *  Reads data from a stream
+ *
+ * Parameters:
+ *  ptr    - Storage location for data.
+ *  size   - Item size in bytes.
+ *  count  - Maximum number of items to be read.
+ *  stream - Pointer to stream
+ *
+ * Returns:
+ *  The number of full items actually read, which may be less than `count`
+ *  if an error occurs or if the end of the file is encountered before
+ *  reaching `count`. If `size` or `count` is 0, `platform_fread`
+ *  returns 0 and the buffer contents are unchanged.
+ */
+size_t platform_fread(void *ptr, size_t size, size_t count, FILE *stream);
+
+/*
+ * Function: platform_fwrite
+ *  Writes data to a stream
+ *
+ * Parameters:
+ *  ptr    - Pointer to data to be written.
+ *  size   - Item size in bytes.
+ *  count  - Maximum number of items to be read.
+ *  stream - Pointer to stream
+ *
+ * Returns:
+ *  The number of full items actually written, which may be less than
+ *  `count` if an error occurs. Also, if an error occurs, the
+ *  file-position indicator cannot be determined.
+ *
+ * Remarks:
+ *  Writes up to `count` items, of `size` length each, from `ptr` to the
+ *  output stream. The file pointer associated with stream (if there is one)
+ *  is incremented by the number of bytes actually written.
+ */
+size_t platform_fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
+
+/*
+ * Function: platform_fflush
+ *  Flushes a stream
+ *
+ * Parameters:
+ *  stream - Pointer to stream
+ *
+ * Returns:
+ *  0 value if the buffer was succesffuly flushed. The value 0 is also
+ *  returned in cases in which the specified stream has no buffer or is
+ *  open for reading only. A return value of *EOF* indicates an error.
+ *
+ * Remarks:
+ *  Flushes a stream. If the file associated with stream is open for output,
+ *  platform_fflush writes to that file the contents of the buffer
+ *  associated with the stream. If the stream is open for input,
+ *  platform_fflush clears the contents of the buffer. platform_fflush
+ *  negates the effect of any prior call to ungetc against stream. Also,
+ *  platform_fflush(NULL) flushes all streams opened for output.
+ *  The stream remains open after the call. platform_fflush has no effect
+ *  on an unbuffered stream.
+ */
+int platform_fflush(FILE *stream);
+
+/*
+ * Function: platform_fclose
+ *  Closes a stream.
+ *
+ * Parameters:
+ *  stream - Pointer to stream.
+ *
+ * Returns:
+ *  0 value. *EOF* is used to indicate an error.
+ *
+ * Remarks:
+ *  Closes a stream.
+ */
+int platform_fclose(FILE *stream);
+
+/*
+ * Function: platform_ferror
+ *  Tests for an error on a stream.
+ *
+ * Parameters:
+ *  stream - Pointer to stream.
+ *
+ * Returns:
+ *  If not error has occured on `stream`, 0 value is returned, otherwise
+ *  it returns a nonzero value.
+ *
+ * Remarks:
+ *  Tests for a reading or writing error on the file associated with `stream`.
+ *  If an error has occured, the error indicator for the stream remains set
+ *  until the stream is closed or rewound.
+ */
+int platform_ferror(FILE *stream);
+
+/*
+ * Function: platform_fgetc
+ *  Read a character from a stream.
+ *
+ * Parameters:
+ *  stream - Pointer to a stream.
+ *
+ * Returns:
+ *  The chracter read as an int or EOF to indicate an error or end-of-file.
+ *
+ * Remarks:
+ *  Reads a single chracter from the current position of the file associated
+ *  with `stream`. Than increments that position. If the steam is at the end
+ *  of the file, the end-of-file indicator for the stream is set.
+ */
+int platform_fgetc(FILE *stream);
+
+/*
+ * Function: platform_fputs
+ *  Write a string to a stream
+ *
+ * Parameters:
+ *  str    - Output string.
+ *  stream - Pointer to stream.
+ *
+ * Returns:
+ *  Non-negative value if successful. EOF is used to indicate an error.
+ *
+ * Remarks:
+ *  Copies `str` to the output stream at the current position.
+ */
+int platform_fputs(const char *str, FILE *stream);
+
+/*
+ * Function: platform_fseek
+ *  Moves the file pointer to a specified location.
+ *
+ * Parameters:
+ *  stream - Pointer to stream.
+ *  offset - Number of bytes from origin to offset.
+ *  origin - Initital position.
+ *
+ * Returns:
+ *  0 value, nonzero values are used to indicate an error.
+ *
+ * Remarks:
+ *  Moves the file pointer (if any) associated with stream to a new
+ *  location that is offset bytes from origin.
+ *  The next operation on the stream takes place at the new location.
+ *  On a stream open for update, the next operation can be either a
+ *  read or a write.
+ */
+int platform_fseek(FILE *stream, long offset, int origin);
+
+/*
+ * Function: platform_ftell
+ *  Gets the current position of a file pointer
+ *
+ * Parameters:
+ *  stream - Pointer to stream
+ *
+ * Returns:
+ *  Current file position. May not reflect physical byte offset, e.g
+ *  systems where read-mode does carriage return-linefeed translation.
+ *  -1 value is used to indivate an error.
+ */
+long platform_ftell(FILE *stream);
+
+/*
+ * Function: platform_mkdir
+ *  Make a directory
+ *
+ * Parameters:
+ *  path    - Path to create
+ *  mode    - The mode of the directory (implementation defined)
+ *
+ * Returns:
+ *  0 value. -1 value is used to indicate an error. On error no
+ *  directory shall be created.
+ *
+ * Remarks:
+ *  Shall create a new empty directory with with the name path specified
+ *  by argument `path.
+ */
+int platform_mkdir(const char *path, int mode);
+
+/*
+ * Function: platform_opendir
+ *  Open a directory
+ *
+ * Parameters:
+ *  path - Path to the directory to open
+ *
+ * Returns:
+ *  Pointer to an object of type *DIR*. A null pointer value indicates
+ *  an error.
+ *
+ * Remarks:
+ *  Shall open a directory stream corresponding to the directory named by
+ *  the `path` argument. The directory stream is positioned at the first entry.
+ */
+DIR *platform_opendir(const char *path);
+
+/*
+ * Function: platform_closedir
+ *  Close a directory stream
+ *
+ * Parameters:
+ *  dir - Pointer to directory stream
+ *
+ * Returns:
+ *  0 value. A -1 value indicated an error.
+ *
+ * Remarks:
+ *  Shall close the directory stream referred to by the argument
+ *  `dir`. Upon return, the value of `dir` may no longer point to
+ *  an accessible object of the type *DIR*.
+ */
+int platform_closedir(DIR *dir);
+
+/*
+ * Function: platform_readdir
+ *  Read directory
+ *
+ * Parameters:
+ *  dir - Pointer to directory stream
+ *
+ * Returns:
+ *  Pointer to an object of type `struct dirent`. A null pointer value
+ *  indicates an error.
+ *
+ * Remarks:
+ *  When the end of the directory is encountered, a null pointer is
+ *  returned.
+ */
+struct dirent *platform_readdir(DIR *dir);
+
+/*
+ * Function: platform_isatty
+ *  Determines whether a file descriptor is associated with a character
+ *  device.
+ *
+ * Returns:
+ *  A nonzero value if the descriptor is associated with a character
+ *  device. Otherwise `platform_isatty` returns 0.
+ */
+int platform_isatty(int fd);
+
+#endif
diff --git a/test.c b/test.c
index fdf3777f4f0af16363a5f6170ab2749742240f16..2672cb6a93fa955cf6f772d49ec41348aa1789a6 100644 (file)
--- a/test.c
+++ b/test.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#define GMQCC_PLATFORM_HEADER /* TODO: eliminate! */
 #include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 
 #include "gmqcc.h"
+#include "platform.h"
 
 static const char *task_bins[] = {
     "./gmqcc",
@@ -53,15 +53,15 @@ static const char *task_bins[] = {
 #include <dirent.h>
 #include <unistd.h>
 typedef struct {
-    FILE *handles[3];
-    int   pipes  [3];
+    fs_file_t *handles[3];
+    int        pipes  [3];
 
     int stderr_fd;
     int stdout_fd;
     int pid;
 } popen_t;
 
-static FILE ** task_popen(const char *command, const char *mode) {
+static fs_file_t **task_popen(const char *command, const char *mode) {
     int     inhandle  [2];
     int     outhandle [2];
     int     errhandle [2];
@@ -103,9 +103,9 @@ static FILE ** task_popen(const char *command, const char *mode) {
         data->pipes  [1] = outhandle[0];
         data->pipes  [2] = errhandle[0];
 
-        data->handles[0] = fdopen(inhandle [1], "w");
-        data->handles[1] = fdopen(outhandle[0], mode);
-        data->handles[2] = fdopen(errhandle[0], mode);
+        data->handles[0] = (fs_file_t*)fdopen(inhandle [1], "w");
+        data->handles[1] = (fs_file_t*)fdopen(outhandle[0], mode);
+        data->handles[2] = (fs_file_t*)fdopen(errhandle[0], mode);
 
         /* sigh */
         vec_free(argv);
@@ -137,7 +137,7 @@ task_popen_error_0:
     return NULL;
 }
 
-static int task_pclose(FILE **handles) {
+static int task_pclose(fs_file_t **handles) {
     popen_t *data   = (popen_t*)handles;
     int      status = 0;
 
@@ -153,22 +153,17 @@ static int task_pclose(FILE **handles) {
 }
 #else
     typedef struct {
-        FILE *handles[3];
-        char  name_err[L_tmpnam];
-        char  name_out[L_tmpnam];
+        fs_file_t *handles[3];
+        char       name_err[L_tmpnam];
+        char       name_out[L_tmpnam];
     } popen_t;
 
-    static FILE **task_popen(const char *command, const char *mode) {
+    static fs_file_t **task_popen(const char *command, const char *mode) {
         char    *cmd  = NULL;
         popen_t *open = (popen_t*)mem_a(sizeof(popen_t));
 
-#ifndef _MSC_VER
-        tmpnam(open->name_err);
-        tmpnam(open->name_out);
-#else
-        tmpnam_s(open->name_err, L_tmpnam);
-        tmpnam_s(open->name_out, L_tmpnam);
-#endif
+        util_tmpnam(open->name_err);
+        util_tmpnam(open->name_out);
 
         (void)mode; /* excluded */
 
@@ -184,10 +179,12 @@ static int task_pclose(FILE **handles) {
         return open->handles;
     }
 
-    static int task_pclose(FILE **files) {
+    static int task_pclose(fs_file_t **files) {
         popen_t *open = ((popen_t*)files);
+
         fs_file_close(files[1]);
         fs_file_close(files[2]);
+
         remove(open->name_err);
         remove(open->name_out);
 
@@ -363,7 +360,7 @@ static bool task_template_generate(task_template_t *tmpl, char tag, const char *
     return true;
 }
 
-static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) {
+static bool task_template_parse(const char *file, task_template_t *tmpl, fs_file_t *fp, size_t *pad) {
     char  *data = NULL;
     char  *back = NULL;
     size_t size = 0;
@@ -373,7 +370,7 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *f
         return false;
 
     /* top down parsing */
-    while (fs_file_getline(&back, &size, fp) != EOF) {
+    while (fs_file_getline(&back, &size, fp) != FS_FILE_EOF) {
         /* skip whitespace */
         data = back;
         if (*data && (*data == ' ' || *data == '\t'))
@@ -504,7 +501,7 @@ static task_template_t *task_template_compile(const char *file, const char *dir,
     /* a page should be enough */
     char             fullfile[4096];
     size_t           filepadd = 0;
-    FILE            *tempfile = NULL;
+    fs_file_t       *tempfile = NULL;
     task_template_t *tmpl     = NULL;
 
     util_snprintf(fullfile,    sizeof(fullfile), "%s/%s", dir, file);
@@ -659,9 +656,9 @@ static void task_template_destroy(task_template_t *tmpl) {
  */
 typedef struct {
     task_template_t *tmpl;
-    FILE           **runhandles;
-    FILE            *stderrlog;
-    FILE            *stdoutlog;
+    fs_file_t       **runhandles;
+    fs_file_t       *stderrlog;
+    fs_file_t       *stdoutlog;
     char            *stdoutlogfile;
     char            *stderrlogfile;
     bool             compiled;
@@ -675,8 +672,8 @@ static task_t *task_tasks = NULL;
  */
 static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
     bool             success = true;
-    DIR             *dir;
-    struct dirent   *files;
+    fs_dir_t        *dir;
+    fs_dirent_t     *files;
     struct stat      directory;
     char             buffer[4096];
     size_t           found = 0;
@@ -733,7 +730,7 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
             if (strcmp(files->d_name + strlen(files->d_name) - 5, ".tmpl") == 0) {
                 task_template_t *tmpl = task_template_compile(files->d_name, directories[i], pad);
                 char             buf[4096]; /* one page should be enough */
-                char            *qcflags = NULL;
+                const char      *qcflags = NULL;
                 task_t           task;
 
                 found ++;
@@ -754,16 +751,7 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
                  * to test compile flags for all tests.  This needs to be
                  * BEFORE other flags (so that the .tmpl can override them)
                  */
-                #ifdef _MSC_VER
-                {
-                    char   buffer[4096];
-                    size_t size;
-                    getenv_s(&size, buffer, sizeof(buffer), "QCFLAGS");
-                    qcflags = buffer;
-                }
-                #else
-                qcflags = getenv("QCFLAGS");
-                #endif
+                qcflags = platform_getenv("QCFLAGS");
 
                 /*
                  * Generate the command required to open a pipe to a process
@@ -881,9 +869,9 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
  * left behind from a previous invoke of the test-suite.
  */
 static void task_precleanup(const char *curdir) {
-    DIR             *dir;
-    struct dirent   *files;
-    char             buffer[4096];
+    fs_dir_t     *dir;
+    fs_dirent_t  *files;
+    char          buffer[4096];
 
     dir = fs_dir_open(curdir);
 
@@ -949,7 +937,7 @@ static bool task_trymatch(size_t i, char ***line) {
     bool             success = true;
     bool             process = true;
     int              retval  = EXIT_SUCCESS;
-    FILE            *execute;
+    fs_file_t       *execute;
     char             buffer[4096];
     task_template_t *tmpl = task_tasks[i].tmpl;
 
@@ -973,7 +961,7 @@ static bool task_trymatch(size_t i, char ***line) {
             );
         }
 
-        execute = popen(buffer, "r");
+        execute = (fs_file_t*)popen(buffer, "r");
         if (!execute)
             return false;
     } else if (!strcmp(tmpl->proceduretype, "-pp")) {
@@ -1006,7 +994,7 @@ static bool task_trymatch(size_t i, char ***line) {
         size_t size    = 0;
         size_t compare = 0;
 
-        while (fs_file_getline(&data, &size, execute) != EOF) {
+        while (fs_file_getline(&data, &size, execute) != FS_FILE_EOF) {
             if (!strcmp(data, "No main function found\n")) {
                 con_err("test failure: `%s` (No main function found) [%s]\n",
                     tmpl->description,
@@ -1015,7 +1003,7 @@ static bool task_trymatch(size_t i, char ***line) {
                 if (!process)
                     fs_file_close(execute);
                 else
-                    pclose(execute);
+                    pclose((FILE*)execute);
                 return false;
             }
 
@@ -1075,7 +1063,7 @@ static bool task_trymatch(size_t i, char ***line) {
     }
 
     if (process)
-        retval = pclose(execute);
+        retval = pclose((FILE*)execute);
     else
         fs_file_close(execute);
 
@@ -1139,7 +1127,7 @@ static size_t 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 (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
+        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != FS_FILE_EOF) {
             fs_file_puts(task_tasks[i].stdoutlog, data);
 
             if (strstr(data, "failed to open file")) {
@@ -1147,7 +1135,7 @@ static size_t task_schedualize(size_t *pad) {
                 execute                = false;
             }
         }
-        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
+        while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != FS_FILE_EOF) {
             /*
              * If a string contains an error we just dissalow execution
              * of it in the vm.
@@ -1162,7 +1150,7 @@ static size_t task_schedualize(size_t *pad) {
             }
 
             fs_file_puts (task_tasks[i].stderrlog, data);
-            fflush(task_tasks[i].stderrlog); /* fast flush for read */
+            fs_file_flush(task_tasks[i].stderrlog); /* fast flush for read */
         }
 
         if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
diff --git a/util.c b/util.c
index 9b32e48394806022e2ab2f0e9c7446aeb211cae1..baff4a435c0c2268624a6982c4d5cbe0371644a6 100644 (file)
--- a/util.c
+++ b/util.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#define GMQCC_PLATFORM_HEADER
 #include <string.h>
 #include <stdlib.h>
+#include <stdarg.h>
 
 #include "gmqcc.h"
+#include "platform.h"
 
 /*
  * Initially this was handled with a table in the gmqcc.h header, but
@@ -224,163 +227,64 @@ size_t util_optimizationtostr(const char *in, char *out, size_t outsz) {
     return util_strtransform(in, out, outsz, "_ ", 'a'-'A');
 }
 
-/*
- * Portable implementation of vasprintf/asprintf. Assumes vsnprintf
- * exists, otherwise compiler error.
- *
- * TODO: fix for MSVC ....
- */
-int util_vasprintf(char **dat, const char *fmt, va_list args) {
-    int   ret;
-    int   len;
-    char *tmp = NULL;
+int util_snprintf(char *str, size_t size, const char *fmt, ...) {
+    va_list  arg;
+    int      ret;
 
-    /*
-     * For visual studio _vsnprintf doesn't tell you the length of a
-     * formatted string if it overflows. However there is a MSVC
-     * intrinsic (which is documented wrong) called _vcsprintf which
-     * will return the required amount to allocate.
-     */
-    #ifdef _MSC_VER
-        if ((len = _vscprintf(fmt, args)) < 0) {
-            *dat = NULL;
-            return -1;
-        }
+    va_start(arg, fmt);
+    ret = platform_vsnprintf(str, size, fmt, arg);
+    va_end(arg);
 
-        tmp = (char*)mem_a(len + 1);
-        if ((ret = _vsnprintf_s(tmp, len+1, len+1, fmt, args)) != len) {
-            mem_d(tmp);
-            *dat = NULL;
-            return -1;
-        }
-        *dat = tmp;
-        return len;
-    #else
-        /*
-         * For everything else we have a decent conforming vsnprintf that
-         * returns the number of bytes needed.  We give it a try though on
-         * a short buffer, since efficiently speaking, it could be nice to
-         * above a second vsnprintf call.
-         */
-        char    buf[128];
-        va_list cpy;
-        va_copy(cpy, args);
-        len = vsnprintf(buf, sizeof(buf), fmt, cpy);
-        va_end (cpy);
-
-        if (len < (int)sizeof(buf)) {
-            *dat = util_strdup(buf);
-            return len;
-        }
-
-        /* not large enough ... */
-        tmp = (char*)mem_a(len + 1);
-        if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
-            mem_d(tmp);
-            *dat = NULL;
-            return -1;
-        }
-
-        *dat = tmp;
-        return len;
-    #endif
+    return ret;
 }
+
 int util_asprintf(char **ret, const char *fmt, ...) {
     va_list  args;
     int      read;
+
     va_start(args, fmt);
-    read = util_vasprintf(ret, fmt, args);
+    read = platform_vasprintf(ret, fmt, args);
     va_end  (args);
 
     return read;
 }
 
-/*
- * These are various re-implementations (wrapping the real ones) of
- * string functions that MSVC considers unsafe. We wrap these up and
- * use the safe variations on MSVC.
- */
-#ifdef _MSC_VER
-    static char **util_strerror_allocated() {
-        static char **data = NULL;
-        return data;
-    }
-
-    static void util_strerror_cleanup(void) {
-        size_t i;
-        char  **data = util_strerror_allocated();
-        for (i = 0; i < vec_size(data); i++)
-            mem_d(data[i]);
-        vec_free(data);
-    }
-
-    const char *util_strerror(int num) {
-        char         *allocated = NULL;
-        static bool   install   = false;
-        static size_t tries     = 0;
-        char        **vector    = util_strerror_allocated();
-
-        /* try installing cleanup handler */
-        while (!install) {
-            if (tries == 32)
-                return "(unknown)";
-
-            install = !atexit(&util_strerror_cleanup);
-            tries ++;
-        }
-
-        allocated = (char*)mem_a(4096); /* A page must be enough */
-        strerror_s(allocated, 4096, num);
-
-        vec_push(vector, allocated);
-        return (const char *)allocated;
-    }
-
-    int util_snprintf(char *src, size_t bytes, const char *format, ...) {
-        int      rt;
-        va_list  va;
-        va_start(va, format);
-
-        rt = vsprintf_s(src, bytes, format, va);
-        va_end  (va);
-
-        return rt;
-    }
-
-    char *util_strcat(char *dest, const char *src) {
-        strcat_s(dest, strlen(src), src);
-        return dest;
-    }
-
-    char *util_strncpy(char *dest, const char *src, size_t num) {
-        strncpy_s(dest, num, src, num);
-        return dest;
-    }
-#else
-    const char *util_strerror(int num) {
-        return strerror(num);
-    }
-
-    int util_snprintf(char *src, size_t bytes, const char *format, ...) {
-        int      rt;
-        va_list  va;
-        va_start(va, format);
-        rt = vsnprintf(src, bytes, format, va);
-        va_end  (va);
+int util_sscanf(const char *str, const char *format, ...) {
+    va_list  args;
+    int      read;
 
-        return rt;
-    }
+    va_start(args, format);
+    read = platform_vsscanf(str, format, args);
+    va_end(args);
 
-    char *util_strcat(char *dest, const char *src) {
-        return strcat(dest, src);
-    }
+    return read;
+}
 
-    char *util_strncpy(char *dest, const char *src, size_t num) {
-        return strncpy(dest, src, num);
-    }
+char *util_strncpy(char *dest, const char *src, size_t n) {
+    return platform_strncpy(dest, src, n);
+}
+char *util_strncat(char *dest, const char *src, size_t n) {
+    return platform_strncat(dest, src, n);
+}
+char *util_strcat(char *dest, const char *src) {
+    return platform_strcat(dest, src);
+}
+const char *util_strerror(int err) {
+    return platform_strerror(err);
+}
 
-#endif /*! _MSC_VER */
+const struct tm *util_localtime(const time_t *timer) {
+    return platform_localtime(timer);
+}
+const char *util_ctime(const time_t *timer) {
+    return platform_ctime(timer);
+}
 
+bool util_isatty(fs_file_t *file) {
+    if (file == (fs_file_t*)stdout) return !!platform_isatty(STDOUT_FILENO);
+    if (file == (fs_file_t*)stderr) return !!platform_isatty(STDERR_FILENO);
+    return false;
+}
 
 void util_seed(uint32_t value) {
     srand((int)value);