# 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
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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);
+}
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);
* 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)
* 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);
}
/*
* 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);
}
/**********************************************************************
}
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();
}
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;
* 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) {
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);
*/
#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"
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;
}
#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, \
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] = ' ';
}
}
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);
* 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;
pos = *n - chr + *lineptr;
}
- if (ferror(stream))
+ if (fs_file_error(stream))
return -1;
if (c == EOF) {
if (pos == *lineptr)
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);
+}
* 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;
/* __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;
/* __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;
/* __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);
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;
#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
# 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 *);
#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
#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);
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
#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;
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;
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 {
void code_pop_statement (code_t *);
-/*===================================================================*/
-/*============================ con.c ================================*/
-/*===================================================================*/
+/* conout.c */
enum {
CON_BLACK = 30,
CON_RED,
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, ...);
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 */
qcfloat_t x, y, z;
} vec3_t;
-/*===================================================================*/
-/*============================= exec.c ==============================*/
-/*===================================================================*/
+/* exec.c */
/* TODO: cleanup */
/*
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 *);
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);
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
#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;
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 = \
#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>";
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));
{
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));
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);
#include "gmqcc.h"
#include "lexer.h"
+
/*
* List of Keywords
*/
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);
}
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
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);
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;
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);
lex_tokench(lex, ' ');
}
- while (ch != EOF)
+ while (ch != FS_FILE_EOF)
{
ch = lex_getch(lex);
if (ch == '*') {
ch = '/';
break;
}
- } while (ch != EOF && util_isspace(ch));
+ } while (ch != FS_FILE_EOF && util_isspace(ch));
if (haswhite) {
lex_endtoken(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);
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')
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)
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);
}
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);
}
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);
}
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)) {
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);
}
{
/* 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);
}
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;
} 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;
}
/* 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;
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;
}
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;
--- /dev/null
+/*
+ * 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);
+}
}
static size_t opts_ini_parse (
- FILE *filehandle,
+ fs_file_t *filehandle,
char *(*loadhandle)(const char *, const char *, const char *),
char **errorhandle
) {
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 */
*/
char *error = NULL;
size_t line;
- FILE *ini;
+ fs_file_t *ini;
if (!file) {
/* try ini */
typedef struct {
pak_directory_t *directories;
pak_header_t header;
- FILE *handle;
+ fs_file_t *handle;
bool insert;
} pak_file_t;
* 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
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;
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);
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
* 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;
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);
return true;
}
+#include <stdio.h>
int main(int argc, char **argv) {
bool extract = true;
char *redirout = (char*)stdout;
*/
#include <string.h>
#include <math.h>
+
#include "parser.h"
#define PARSER_HT_LOCALS 2
}
}
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;
}
--- /dev/null
+/*
+ * 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
* 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",
#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];
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);
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;
}
#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 */
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);
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;
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'))
/* 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);
*/
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;
*/
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;
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 ++;
* 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
* 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);
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;
);
}
- execute = popen(buffer, "r");
+ execute = (fs_file_t*)popen(buffer, "r");
if (!execute)
return false;
} else if (!strcmp(tmpl->proceduretype, "-pp")) {
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,
if (!process)
fs_file_close(execute);
else
- pclose(execute);
+ pclose((FILE*)execute);
return false;
}
}
if (process)
- retval = pclose(execute);
+ retval = pclose((FILE*)execute);
else
fs_file_close(execute);
* 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")) {
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.
}
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")) {
* 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
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);