CFLAGS += -DNOTRACK
endif
-OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o file.o utf8.o correct.o pak.o
-OBJ_T = test.o util.o conout.o file.o
-OBJ_C = main.o lexer.o parser.o file.o
-OBJ_X = exec-standalone.o util.o conout.o file.o
+OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o pak.o
+OBJ_T = test.o util.o conout.o fs.o
+OBJ_C = main.o lexer.o parser.o fs.o
+OBJ_X = exec-standalone.o util.o conout.o fs.o
ifneq ("$(CYGWIN)", "")
#nullify the common variables that
conout.o: gmqcc.h opts.def
ftepp.o: gmqcc.h opts.def lexer.h
opts.o: gmqcc.h opts.def
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
utf8.o: gmqcc.h opts.def
correct.o: gmqcc.h opts.def
pak.o: gmqcc.h opts.def
test.o: gmqcc.h opts.def
util.o: gmqcc.h opts.def
conout.o: gmqcc.h opts.def
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
main.o: gmqcc.h opts.def lexer.h
lexer.o: gmqcc.h opts.def lexer.h
parser.o: gmqcc.h opts.def lexer.h ast.h ir.h
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
util.o: gmqcc.h opts.def
conout.o: gmqcc.h opts.def
-file.o: gmqcc.h opts.def
+fs.o: gmqcc.h opts.def
if (lnofile) {
uint32_t version = 1;
- fp = file_open(lnofile, "wb");
+ fp = fs_file_open(lnofile, "wb");
if (!fp)
return false;
util_endianswap(code_linenums, vec_size(code_linenums), sizeof(code_linenums[0]));
- if (file_write("LNOF", 4, 1, fp) != 1 ||
- file_write(&version, sizeof(version), 1, fp) != 1 ||
- file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
- file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
- file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
- file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
- file_write(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums))
+ if (fs_file_write("LNOF", 4, 1, fp) != 1 ||
+ fs_file_write(&version, sizeof(version), 1, fp) != 1 ||
+ fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
+ fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
+ fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
+ fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
+ fs_file_write(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums))
{
con_err("failed to write lno file\n");
}
- file_close(fp);
+ fs_file_close(fp);
fp = NULL;
}
- fp = file_open(filename, "wb");
+ fp = fs_file_open(filename, "wb");
if (!fp)
return false;
- if (1 != file_write(&code_header, sizeof(prog_header) , 1 , fp) ||
- vec_size(code_statements) != file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) ||
- vec_size(code_defs) != file_write(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) ||
- vec_size(code_fields) != file_write(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) ||
- vec_size(code_functions) != file_write(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) ||
- vec_size(code_globals) != file_write(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) ||
- vec_size(code_chars) != file_write(code_chars, 1 , vec_size(code_chars) , fp))
+ if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) ||
+ vec_size(code_statements) != fs_file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) ||
+ vec_size(code_defs) != fs_file_write(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) ||
+ vec_size(code_fields) != fs_file_write(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) ||
+ vec_size(code_functions) != fs_file_write(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) ||
+ vec_size(code_globals) != fs_file_write(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) ||
+ vec_size(code_chars) != fs_file_write(code_chars, 1 , vec_size(code_chars) , fp))
{
- file_close(fp);
+ fs_file_close(fp);
return false;
}
vec_free(code_chars);
util_htdel(code_string_cache);
- file_close(fp);
+ fs_file_close(fp);
return true;
}
void con_close() {
if (!GMQCC_IS_DEFINE(console.handle_err))
- file_close(console.handle_err);
+ fs_file_close(console.handle_err);
if (!GMQCC_IS_DEFINE(console.handle_out))
- file_close(console.handle_out);
+ fs_file_close(console.handle_out);
}
void con_color(int state) {
if (GMQCC_IS_DEFINE(out)) {
console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
con_enablecolor();
- } else if (!(console.handle_out = file_open(out, "w"))) return 0;
+ } else if (!(console.handle_out = fs_file_open(out, "w"))) return 0;
if (GMQCC_IS_DEFINE(err)) {
console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr;
con_enablecolor();
- } else if (!(console.handle_err = file_open(err, "w"))) return 0;
+ } else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
/* no buffering */
setvbuf(console.handle_out, NULL, _IONBF, 0);
{
qc_program *prog;
prog_header header;
- FILE *file = file_open(filename, "rb");
+ FILE *file = fs_file_open(filename, "rb");
if (!file)
return NULL;
- if (file_read(&header, sizeof(header), 1, file) != 1) {
+ if (fs_file_read(&header, sizeof(header), 1, file) != 1) {
loaderror("failed to read header from '%s'", filename);
- file_close(file);
+ fs_file_close(file);
return NULL;
}
if (!skipversion && header.version != 6) {
loaderror("header says this is a version %i progs, we need version 6\n", header.version);
- file_close(file);
+ fs_file_close(file);
return NULL;
}
prog = (qc_program*)mem_a(sizeof(qc_program));
if (!prog) {
- file_close(file);
+ fs_file_close(file);
fprintf(stderr, "failed to allocate program data\n");
return NULL;
}
}
#define read_data(hdrvar, progvar, reserved) \
- if (file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
+ if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
loaderror("seek failed"); \
goto error; \
} \
- if (file_read ( \
+ if (fs_file_read ( \
vec_add(prog->progvar, header.hdrvar.length + reserved), \
sizeof(*prog->progvar), \
header.hdrvar.length, \
read_data1(strings);
read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */
- file_close(file);
+ fs_file_close(file);
/* profile counters */
memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code));
done:
if (len < (int)sizeof(spaces)-1) {
spaces[sizeof(spaces)-1-len] = 0;
- file_puts(stdout, spaces);
+ fs_file_puts(stdout, spaces);
spaces[sizeof(spaces)-1-len] = ' ';
}
}
+++ /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.
- */
-#include "gmqcc.h"
-
-/*
- * This is essentially a "wrapper" interface around standard C's IO
- * library. There is two reason we implement this, 1) visual studio
- * hearts for "secure" varations, as part of it's "Security Enhancements
- * in the CRT" (http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx).
- * 2) But one of the greater reasons is for the possibility of large file
- * support in the future. I don't expect to reach the 2GB limit any
- * time soon (mainly because that would be insane). But when it comes
- * to adding support for some other larger IO tasks (in the test-suite,
- * or even the QCVM we'll need it). There is also a third possibility of
- * building .dat files directly from zip files (which would be very cool
- * at least I think so).
- */
-#ifdef _MSC_VER
-/* {{{ */
- /*
- * Visual Studio has security CRT features which I actually want to support
- * if we ever port to Windows 8, and want GMQCC to be API safe.
- *
- * We handle them here, for all file-operations.
- */
-
- static void file_exception (
- const wchar_t *expression,
- const wchar_t *function,
- const wchar_t *file,
- unsigned int line,
- uintptr_t reserved
- ) {
- wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression);
- wprintf(L"Aborting ...\n");
- abort();
- }
-
- static void file_init() {
- static bool init = false;
-
- if (init)
- return;
-
- _set_invalid_parameter_handler(&file_exception);
-
- /*
- * Turnoff the message box for CRT asserations otherwise
- * we don't get the error reported to the console as we should
- * otherwise get.
- */
- _CrtSetReportMode(_CRT_ASSERT, 0);
- init = !init;
- }
-
-
- FILE *file_open(const char *filename, const char *mode) {
- FILE *handle = NULL;
- file_init();
-
- return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
- }
-
- size_t file_read(void *buffer, size_t size, size_t count, FILE *fp) {
- file_init();
- return fread_s(buffer, size*count, size, count, fp);
- }
-
- int file_printf(FILE *fp, const char *format, ...) {
- int rt;
- va_list va;
- va_start(va, format);
-
- file_init();
- rt = vfprintf_s(fp, format, va);
- va_end (va);
-
- return rt;
- }
-
-/* }}} */
-#else
-/* {{{ */
- /*
- * All other compilers/platforms that don't restrict insane policies on
- * IO for no aparent reason.
- */
- FILE *file_open(const char *filename, const char *mode) {
- return fopen(filename, mode);
- }
-
- size_t file_read(void *buffer, size_t size, size_t count, FILE *fp) {
- return fread(buffer, size, count, fp);
- }
-
- int file_printf(FILE *fp, const char *format, ...) {
- int rt;
- va_list va;
- va_start(va, format);
- rt = vfprintf(fp, format, va);
- va_end (va);
-
- return rt;
- }
-
-/* }}} */
-#endif
-
-/*
- * These are implemented as just generic wrappers to keep consistency in
- * the API. Not as macros though
- */
-void file_close(FILE *fp) {
- /* Invokes file_exception on windows if fp is null */
- fclose (fp);
-}
-
-size_t file_write (
- const void *buffer,
- size_t size,
- size_t count,
- FILE *fp
-) {
- /* Invokes file_exception on windows if fp is null */
- return fwrite(buffer, size, count, fp);
-}
-
-int file_error(FILE *fp) {
- /* Invokes file_exception on windows if fp is null */
- return ferror(fp);
-}
-
-int file_getc(FILE *fp) {
- /* Invokes file_exception on windows if fp is null */
- return fgetc(fp);
-}
-
-int file_puts(FILE *fp, const char *str) {
- /* Invokes file_exception on windows if fp is null */
- return fputs(str, fp);
-}
-
-int file_seek(FILE *fp, long int off, int whence) {
- /* Invokes file_exception on windows if fp is null */
- return fseek(fp, off, whence);
-}
-
-int file_putc(FILE *fp, int ch) {
- /* Invokes file_exception on windows if fp is null */
- return fputc(ch, fp);
-}
-
-/*
- * Implements libc getline for systems that don't have it, which is
- * assmed all. This works the same as getline().
- */
-int file_getline(char **lineptr, size_t *n, FILE *stream) {
- int chr;
- int ret;
- char *pos;
-
- if (!lineptr || !n || !stream)
- return -1;
- if (!*lineptr) {
- if (!(*lineptr = (char*)mem_a((*n=64))))
- return -1;
- }
-
- chr = *n;
- pos = *lineptr;
-
- for (;;) {
- int c = file_getc(stream);
-
- if (chr < 2) {
- *n += (*n > 16) ? *n : 64;
- chr = *n + *lineptr - pos;
- if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
- return -1;
- pos = *n - chr + *lineptr;
- }
-
- if (ferror(stream))
- return -1;
- if (c == EOF) {
- if (pos == *lineptr)
- return -1;
- else
- break;
- }
-
- *pos++ = c;
- chr--;
- if (c == '\n')
- break;
- }
- *pos = '\0';
- return (ret = pos - *lineptr);
-}
memcpy(vec_add(filename, len+1), file, len);
vec_last(filename) = 0;
- fp = file_open(filename, "rb");
+ fp = fs_file_open(filename, "rb");
if (fp) {
- file_close(fp);
+ fs_file_close(fp);
return filename;
}
vec_free(filename);
#ifdef _MSC_VER
# pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */
# pragma warning(disable : 4018 ) /* signed/unsigned mismatch */
-#endif
+#endif /*! _MSC_VER */
#define GMQCC_VERSION_MAJOR 0
#define GMQCC_VERSION_MINOR 3
# define GMQCC_DEV_VERSION_STRING "development build\n"
#else
# define GMQCC_DEV_VERSION_STRING
-#endif
+#endif /*! GMQCC_GITINGO */
#define GMQCC_STRINGIFY(x) #x
#define GMQCC_IND_STRING(x) GMQCC_STRINGIFY(x)
#ifndef __cplusplus
# ifdef false
# undef false
-# endif /* !false */
+# endif /*! false */
# ifdef true
# undef true
-# endif /* !true */
+# endif /*! true */
# define false (0)
# define true (1)
# ifdef __STDC_VERSION__
typedef int bool;
# else
typedef _Bool bool;
-# endif
+# endif /*! __STDC_VERSION__ < 199901L && __GNUC__ < 3 */
# else
typedef int bool;
-# endif /* !__STDC_VERSION__ */
-#endif /* !__cplusplus */
+# endif /*! __STDC_VERSION__ */
+#endif /*! __cplusplus */
/*
* Of some functions which are generated we want to make sure
#else
# define GMQCC_WARN
# define GMQCC_USED
-#endif
+#endif /*! defined(__GNUC__) || defined (__CLANG__) */
/*
* This is a hack to silent clang regarding empty
* body if statements.
# define GMQCC_INLINE
# else
# define GMQCC_INLINE __attribute__ ((always_inline))
-# endif
+# endif /*! __GNUC__ < 2 */
# else
# define GMQCC_INLINE
-# endif
+# endif /*! defined(__GNUC__) || defined (__CLANG__) */
# else
# define GMQCC_INLINE inline
-# endif
+# endif /*! __STDC_VERSION < 199901L */
/*
* Visual studio has __forcinline we can use. So lets use that
* I suspect it also has just __inline of some sort, but our use
# define GMQCC_INLINE __forceinline
#else
# define GMQCC_INLINE
-#endif /* !__STDC_VERSION__ */
+#endif /*! __STDC_VERSION__ */
/*
* noreturn is present in GCC and clang
# define GMQCC_NORETURN __attribute__ ((noreturn))
#else
# define GMQCC_NORETURN
-#endif
+#endif /*! (defined(__GNUC__) && __GNUC__ >= 2) || defined (__CLANG__) */
#ifndef _MSC_VER
# include <stdint.h>
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
-#endif
+#endif /*! _MSC_VER */
/*
*windows makes these prefixed because they're C99
# define snprintf(X, Y, Z, ...) _snprintf(X, Y, Z, __VA_ARGS__)
/* strtof doesn't exist -> strtod does though :) */
# define strtof(X, Y) (float)(strtod(X, Y))
-#endif
+#endif /*! _MSC_VER */
/*
* Very roboust way at determining endianess at compile time: this handles
# define BIG_ENDIAN
# elif defined (__LITTLE_ENDIAN__) && !defined (LITTLE_ENDIAN)
# define LITTLE_ENDIAN
-# endif
+# endif /*! defined (__BIG_ENDIAN__) && !defined(BIG_ENDIAN) */
# elif !defined (__MINGW32__)
# include <endian.h>
# if !defined (__BEOS__)
# include <byteswap.h>
-# endif
-# endif
-#endif
+# endif /*! !definde (__BEOS__) */
+# endif /*! defined (__FreeBSD__) || defined (__OpenBSD__) */
+#endif /*! defined (__GNUC__) || defined (__GNU_LIBRARY__) */
#if !defined(PLATFORM_BYTE_ORDER)
# if defined (LITTLE_ENDIAN) || defined (BIG_ENDIAN)
# if defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
# elif defined (BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
-# endif
+# endif /*! defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN) */
# elif defined (_LITTLE_ENDIAN) || defined (_BIG_ENDIAN)
# if defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
# elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
-# endif
+# endif /*! defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) */
# elif defined (__LITTLE_ENDIAN__) || defined (__BIG_ENDIAN__)
# if defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__)
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
# elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)
# define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
-# endif
-# endif
-#endif
+# endif /*! defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__) */
+# endif /*! defined(LITTLE_ENDIAN) || defined (BIG_ENDIAN) */
+#endif /*! !defined(PLATFORM_BYTE_ORDER) */
#if !defined (PLATFORM_BYTE_ORDER)
# if defined (__alpha__) || defined (__alpha) || defined (i386) || \
defined (__i386__) || defined (_M_I86) || defined (_M_IX86) || \
# else
# define PLATFORM_BYTE_ORDER -1
# endif
-#endif
+#endif /*! !defined (PLATFORM_BYTE_ORDER) */
+/*
+ * On windows systems where we're not compiling with MING32 we need a
+ * little extra help on dependinces for implementing our own dirent.h
+ * in fs.c.
+ */
+#if defined(_WIN32) && !defined(__MINGW32__)
+# define _WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+# include <fcntl.h>
+
+ struct dirent {
+ long d_ino;
+ unsigned short d_reclen;
+ unsigned short d_namlen;
+ char d_name[FILENAME_MAX];
+ }
+
+ typedef struct {
+ struct _finddata_t dd_dta;
+ struct dirent dd_dir;
+ long dd_handle;
+ int dd_stat;
+ char dd_name[1];
+ } DIR;
+#else
+# include <dirent.h>
+#endif /*! _WIN32 && !defined(__MINGW32__) */
/*===================================================================*/
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
# define mem_d(x) util_memory_d((void*)(x))
# define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__)
-#endif
+#endif /*! NOTRACK */
/*
* A flexible vector implementation: all vector pointers contain some
/*===================================================================*/
/*============================ file.c ===============================*/
/*===================================================================*/
-GMQCC_INLINE void file_close (FILE *);
-GMQCC_INLINE int file_error (FILE *);
-GMQCC_INLINE int file_getc (FILE *);
-GMQCC_INLINE int file_printf (FILE *, const char *, ...);
-GMQCC_INLINE int file_puts (FILE *, const char *);
-GMQCC_INLINE int file_putc (FILE *, int);
-GMQCC_INLINE int file_seek (FILE *, long int, int);
-
-GMQCC_INLINE size_t file_read (void *, size_t, size_t, FILE *);
-GMQCC_INLINE size_t file_write (const void *, size_t, size_t, FILE *);
-
-GMQCC_INLINE FILE *file_open (const char *, const char *);
-/*NOINLINE*/ int file_getline(char **, size_t *, FILE *);
+/* file handling */
+void fs_file_close (FILE *);
+int fs_file_error (FILE *);
+int fs_file_getc (FILE *);
+int fs_file_flush (FILE *);
+int fs_file_printf (FILE *, const char *, ...);
+int fs_file_puts (FILE *, const char *);
+int fs_file_putc (FILE *, int);
+int fs_file_seek (FILE *, long int, int);
+long int fs_file_tell (FILE *);
+
+size_t fs_file_read (void *, size_t, size_t, FILE *);
+size_t fs_file_write (const void *, size_t, size_t, FILE *);
+
+FILE *fs_file_open (const char *, const char *);
+int fs_file_getline(char **, size_t *, FILE *);
+
+/* directory handling */
+DIR *fs_dir_open (const char *);
+int fs_dir_close (DIR *);
+struct dirent *fs_dir_read (DIR *);
+int fs_dir_make (const char *);
+int fs_dir_change (const char *);
/*===================================================================*/
#define OPTS_OPTION_U32(X) (opts.options[X].U32)
#define OPTS_OPTION_STR(X) (opts.options[X].STR)
-#endif
+#endif /*! GMQCC_HDR */
lex_file* lex_open(const char *file)
{
lex_file *lex;
- FILE *in = file_open(file, "rb");
+ FILE *in = fs_file_open(file, "rb");
if (!in) {
lexerror(NULL, "open failed: '%s'\n", file);
lex = (lex_file*)mem_a(sizeof(*lex));
if (!lex) {
- file_close(in);
+ fs_file_close(in);
lexerror(NULL, "out of memory\n");
return NULL;
}
vec_free(lex->modelname);
if (lex->file)
- file_close(lex->file);
+ fs_file_close(lex->file);
#if 0
if (lex->tok)
token_delete(lex->tok);
char *end;
line = *out;
- len = file_getline(&line, alen, src);
+ len = fs_file_getline(&line, alen, src);
if (len == -1)
return false;
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
if (opts_output_wasset) {
- outfile = file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
+ outfile = fs_file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
if (!outfile) {
con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT));
retval = 1;
progs_src = true;
- src = file_open("progs.src", "rb");
+ src = fs_file_open("progs.src", "rb");
if (!src) {
con_err("failed to open `progs.src` for reading\n");
retval = 1;
}
srcdone:
- file_close(src);
+ fs_file_close(src);
mem_d(line);
}
}
out = ftepp_get();
if (out)
- file_printf(outfile, "%s", out);
+ fs_file_printf(outfile, "%s", out);
ftepp_flush();
}
else {
char *read_name;
char *read_value;
- while (file_getline(&line, &linesize, filehandle) != EOF) {
+ while (fs_file_getline(&line, &linesize, filehandle) != EOF) {
parse_beg = line;
/* handle BOM */
if (!file) {
/* try ini */
- if (!(ini = file_open((file = "gmqcc.ini"), "r")))
+ if (!(ini = fs_file_open((file = "gmqcc.ini"), "r")))
/* try cfg */
- if (!(ini = file_open((file = "gmqcc.cfg"), "r")))
+ if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r")))
return;
- } else if (!(ini = file_open(file, "r")))
+ } else if (!(ini = fs_file_open(file, "r")))
return;
con_out("found ini file `%s`\n", file);
vec_free(error);
}
- file_close(ini);
+ fs_file_close(ini);
}
*/
#include <sys/stat.h>
#include <dirent.h>
-#include "gmqcc.h"
+#include "gmqcc.h"
+
+/*
+ * The PAK format uses a FOURCC concept for storing the magic ident within
+ * the header as a uint32_t.
+ */
+#define PAK_FOURCC ((uint32_t)(('P' << 24) | ('A' << 16) | ('C' << 8) | 'K'))
typedef struct {
uint32_t magic; /* "PACK" */
return beg;
}
-/*
- * Used to spawn a directory when creating the pak directory structure/
- * tree. Think of this as mkdir(path, 0700). We just cargo cult our
- * own because _mkdir on windows is "illegal" for Windows8 Certification
- * do to the requirement of SECURITY_ATTRIBUTES on everything.
- */
-static bool pak_tree_spawn(const char *path) {
-#ifdef _MSC_VER
- return CreateDirectoryA(path, NULL); /* non-zero on success */
-#else
- return !!(mkdir(path, 0700)); /* zero on success */
-#endif
-}
-
/*
* When given a string like "a/b/c/d/e/file"
* this function will handle the creation of
memset(directory, 0, 56);
strncpy(directory, entry, 56);
- for (itr = 0; (token = strsep(&directory, "/")) != NULL; itr++) {
+ for (itr = 0; (token = pak_tree_sep(&directory, "/")) != NULL; itr++) {
elements[itr] = token;
}
strcat(pathsplit, elements[jtr]);
strcat(pathsplit, "/");
- pak_tree_spawn(pathsplit);
+ if (fs_dir_make(pathsplit)) {
+ mem_d(pathsplit);
+ mem_d(directory);
+
+ /* TODO: undo on fail */
+
+ return;
+ }
}
mem_d(pathsplit);
if (!(pak = mem_a(sizeof(pak_file_t))))
return NULL;
- if (!(pak->handle = file_open(file, "rb"))) {
+ if (!(pak->handle = fs_file_open(file, "rb"))) {
mem_d(pak);
return NULL;
}
pak->insert = false; /* read doesn't allow insert */
memset (&pak->header, 0, sizeof(pak_header_t));
- file_read (&pak->header, sizeof(pak_header_t), 1, pak->handle);
+ fs_file_read (&pak->header, sizeof(pak_header_t), 1, pak->handle);
util_endianswap(&pak->header, 1, sizeof(pak_header_t));
/*
- * Every PAK file has "PACK" stored as little endian data in the
+ * Every PAK file has "PACK" stored as FOURCC data in the
* header. If this data cannot compare (as checked here), it's
* probably not a PAK file.
*/
- if ((memcmp(&(pak->header.magic), (const void*)"PACK", sizeof(uint32_t)))) {
- file_close(pak->handle);
- mem_d (pak);
+ if (pak->header.magic != PAK_FOURCC) {
+ fs_file_close(pak->handle);
+ mem_d (pak);
return NULL;
}
* Time to read in the directory handles and prepare the directories
* vector. We're going to be reading some the file inwards soon.
*/
- file_seek(pak->handle, pak->header.diroff, SEEK_SET);
+ fs_file_seek(pak->handle, pak->header.diroff, SEEK_SET);
/*
* Read in all directories from the PAK file. These are considered
*/
for (itr = 0; itr < pak->header.dirlen / 64; itr++) {
pak_directory_t dir;
- file_read (&dir, sizeof(pak_directory_t), 1, pak->handle);
- /*util_endianswap(&dir, 1, sizeof(pak_directory_t));*/
+ fs_file_read (&dir, sizeof(pak_directory_t), 1, pak->handle);
+ util_endianswap(&dir, 1, sizeof(pak_directory_t));
vec_push(pak->directories, dir);
}
*/
pak_tree_build(file);
- if (!(pak->handle = file_open(file, "wb"))) {
+ if (!(pak->handle = fs_file_open(file, "wb"))) {
/*
* The directory tree that was created, needs to be
* removed entierly if we failed to open a file.
* "patching" and writing the directories at the end of the
* file.
*/
- pak->insert = true;
-
- /*
- * A valid PAK file contains the magic "PACK" in it's header
- * stored in little endian format.
- */
- memcpy(&(pak->header.magic), (const void*)"PACK", sizeof(uint32_t));
+ pak->insert = true;
+ pak->header.magic = PAK_FOURCC;
/*
* We need to write out the header since files will be wrote out to
* will need to be patched in later with a file_seek, and overwrite,
* we could use offsets and other trickery. This is just easier.
*/
- file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
+ fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
return pak;
}
if (!pak || !file)
return false;
-
- /*
- * We could technically use a hashtable here. But I don't think
- * the lookup complexity is a performance concern. This may be
- * O(n) lookup. But meh?
- */
+
for (itr = 0; itr < vec_size(pak->directories); itr++) {
if (!strcmp(pak->directories[itr].name, file)) {
/*
* Now create the file, if this operation fails. Then abort
* It shouldn't fail though.
*/
- if (!(out = file_open(file, "wb"))) {
+ if (!(out = fs_file_open(file, "wb"))) {
mem_d(dat);
return false;
}
/* read */
- file_seek (pak->handle, dir->pos, SEEK_SET);
- file_read (dat, 1, dir->len, pak->handle);
+ fs_file_seek (pak->handle, dir->pos, SEEK_SET);
+ fs_file_read (dat, 1, dir->len, pak->handle);
/* write */
- file_write(dat, 1, dir->len, out);
+ fs_file_write(dat, 1, dir->len, out);
/* close */
- file_close(out);
+ fs_file_close(out);
/* free */
mem_d(dat);
bool pak_extract_all(pak_file_t *pak, const char *dir) {
size_t itr;
- if (!pak_tree_spawn(dir))
+ if (!fs_dir_make(dir))
return false;
- if (chdir(dir))
+ if (fs_dir_change(dir))
return false;
for (itr = 0; itr < vec_size(pak->directories); itr++) {
if (!pak || !file || !pak->insert || pak_exists(pak, file, NULL))
return false;
- if (!(fp = fopen(file, "rb")))
+ if (!(fp = fs_file_open(file, "rb")))
return false;
/*
* the directory entry, and the actual contents of the file
* to the PAK file itself.
*/
- file_seek(fp, 0, SEEK_END);
- dir.len = ftell(fp);
- file_seek(fp, 0, SEEK_SET);
+ fs_file_seek(fp, 0, SEEK_END);
+ dir.len = fs_file_tell(fp);
+ fs_file_seek(fp, 0, SEEK_SET);
- dir.pos = ftell(pak->handle);
+ dir.pos = fs_file_tell(pak->handle);
/*
* We're limited to 56 bytes for a file name string, that INCLUDES
* the directory and '/' seperators.
*/
if (strlen(file) >= 56) {
- file_close(fp);
+ fs_file_close(fp);
return false;
}
* redirected into the PAK file.
*/
if (!(dat = (unsigned char *)mem_a(dir.len))) {
- file_close(fp);
+ fs_file_close(fp);
return false;
}
- file_read (dat, dir.len, 1, fp);
- file_close(fp);
- file_write(dat, dir.len, 1, pak->handle);
+ fs_file_read (dat, dir.len, 1, fp);
+ fs_file_close(fp);
+ fs_file_write(dat, dir.len, 1, pak->handle);
/*
* Now add the directory to the directories vector, so pak_close
if (!(pak->insert))
return false;
- if (!(dp = opendir(dir)))
+ if (!(dp = fs_dir_open(dir)))
return false;
- while ((dirp = readdir(dp))) {
+ while ((dirp = fs_dir_read(dp))) {
if (!(pak_insert_one(pak, dirp->d_name))) {
- closedir(dp);
+ fs_dir_close(dp);
return false;
}
}
- closedir(dp);
+ fs_dir_close(dp);
return true;
}
pak->header.diroff = ftell(pak->handle);
/* patch header */
- file_seek (pak->handle, 0, SEEK_SET);
- file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
+ fs_file_seek (pak->handle, 0, SEEK_SET);
+ fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
/* write directories */
- file_seek (pak->handle, pak->header.diroff, SEEK_SET);
+ fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET);
for (itr = 0; itr < vec_size(pak->directories); itr++) {
- file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle);
+ fs_file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle);
}
}
- vec_free (pak->directories);
- file_close(pak->handle);
- mem_d (pak);
+ vec_free (pak->directories);
+ fs_file_close(pak->handle);
+ mem_d (pak);
return true;
}
-
-#if 0
-/* test extraction */
-int main() {
- pak_file_t *pak = pak_open("pak0.pak", "r");
- if (!pak) abort();
-
- pak_extract_all(pak, "foo/");
-
- pak_close(pak);
- return 0;
-}
-#endif
-
return status;
}
#else
-# define _WIN32_LEAN_AND_MEAN
-# define popen _popen
-# define pclose _pclose
-# include <windows.h>
-# include <io.h>
-# include <fcntl.h>
/*
* Bidirectional piping implementation for windows using CreatePipe and DuplicateHandle +
* other hacks.
*/
-
typedef struct {
int __dummy;
/* TODO: implement */
(void)files;
return;
}
-
-# ifdef __MINGW32__
- /* mingw32 has dirent.h */
-# include <dirent.h>
-# elif defined (_WIN32)
- /*
- * visual studio lacks dirent.h it's a posix thing
- * so we emulate it with the WinAPI.
- */
-
- struct dirent {
- long d_ino;
- unsigned short d_reclen;
- unsigned short d_namlen;
- char d_name[FILENAME_MAX];
- };
-
- typedef struct {
- struct _finddata_t dd_dta;
- struct dirent dd_dir;
- long dd_handle;
- int dd_stat;
- char dd_name[1];
- } DIR;
-
- DIR *opendir(const char *name) {
- DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(name));
- if (!dir)
- return NULL;
-
- strcpy(dir->dd_name, name);
- return dir;
- }
-
- int closedir(DIR *dir) {
- FindClose((HANDLE)dir->dd_handle);
- mem_d ((void*)dir);
- return 0;
- }
-
- struct dirent *readdir(DIR *dir) {
- WIN32_FIND_DATA info;
- struct dirent *data;
- int rets;
-
- if (!dir->dd_handle) {
- char *dirname;
- if (*dir->dd_name) {
- size_t n = strlen(dir->dd_name);
- if ((dirname = (char*)mem_a(n + 5) /* 4 + 1 */)) {
- strcpy(dirname, dir->dd_name);
- strcpy(dirname + n, "\\*.*"); /* 4 + 1 */
- }
- } else {
- if (!(dirname = util_strdup("\\*.*")))
- return NULL;
- }
-
- dir->dd_handle = (long)FindFirstFile(dirname, &info);
- mem_d(dirname);
- rets = !(!dir->dd_handle);
- } else if (dir->dd_handle != -11) {
- rets = FindNextFile ((HANDLE)dir->dd_handle, &info);
- } else {
- rets = 0;
- }
-
- if (!rets)
- return NULL;
-
- if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
- strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
- data->d_name[FILENAME_MAX - 1] = '\0'; /* terminate */
- data->d_namlen = strlen(data->d_name);
- }
- return data;
- }
-
- /*
- * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well
- * which is not hard at all.
- */
-# undef S_ISDIR /* undef just incase */
-# define S_ISDIR(X) ((X)&_S_IFDIR)
-# endif
-#endif
+#endif /*! _WIN32 */
#define TASK_COMPILE 0
#define TASK_EXECUTE 1
-
/*
* Task template system:
* templates are rules for a specific test, used to create a "task" that
return false;
/* top down parsing */
- while (file_getline(&back, &size, fp) != EOF) {
+ while (fs_file_getline(&back, &size, fp) != EOF) {
/* skip whitespace */
data = back;
if (*data && (*data == ' ' || *data == '\t'))
memset (fullfile, 0, sizeof(fullfile));
snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file);
- tempfile = file_open(fullfile, "r");
+ tempfile = fs_file_open(fullfile, "r");
tmpl = (task_template_t*)mem_a(sizeof(task_template_t));
task_template_nullify(tmpl);
}
success:
- file_close(tempfile);
+ fs_file_close(tempfile);
return tmpl;
failure:
* so the check to see if it's not null here is required.
*/
if (tempfile)
- file_close(tempfile);
+ fs_file_close(tempfile);
mem_d (tmpl);
return NULL;
memset (buf,0,sizeof(buf));
snprintf(buf, sizeof(buf), "%s.stdout", tmpl->tempfilename);
task.stdoutlogfile = util_strdup(buf);
- if (!(task.stdoutlog = file_open(buf, "w"))) {
+ if (!(task.stdoutlog = fs_file_open(buf, "w"))) {
con_err("error opening %s for stdout\n", buf);
continue;
}
memset (buf,0,sizeof(buf));
snprintf(buf, sizeof(buf), "%s.stderr", tmpl->tempfilename);
task.stderrlogfile = util_strdup(buf);
- if (!(task.stderrlog = file_open(buf, "w"))) {
+ if (!(task.stderrlog = fs_file_open(buf, "w"))) {
con_err("error opening %s for stderr\n", buf);
continue;
}
* annoying to have to do all this cleanup work.
*/
if (task_tasks[i].runhandles) task_pclose(task_tasks[i].runhandles);
- if (task_tasks[i].stdoutlog) file_close (task_tasks[i].stdoutlog);
- if (task_tasks[i].stderrlog) file_close (task_tasks[i].stderrlog);
+ if (task_tasks[i].stdoutlog) fs_file_close (task_tasks[i].stdoutlog);
+ if (task_tasks[i].stderrlog) fs_file_close (task_tasks[i].stderrlog);
/*
* Only remove the log files if the test actually compiled otherwise
char *data = NULL;
size_t size = 0;
size_t compare = 0;
- while (file_getline(&data, &size, execute) != EOF) {
+ while (fs_file_getline(&data, &size, execute) != EOF) {
if (!strcmp(data, "No main function found\n")) {
con_err("test failure: `%s` (No main function found) [%s]\n",
tmpl->description,
* Read data from stdout first and pipe that stuff into a log file
* then we do the same for stderr.
*/
- while (file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
- file_puts(task_tasks[i].stdoutlog, data);
+ while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
+ fs_file_puts(task_tasks[i].stdoutlog, data);
if (strstr(data, "failed to open file")) {
task_tasks[i].compiled = false;
execute = false;
}
- fflush(task_tasks[i].stdoutlog);
+ fs_file_flush(task_tasks[i].stdoutlog);
}
- while (file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
+ while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
/*
* If a string contains an error we just dissalow execution
* of it in the vm.
task_tasks[i].compiled = false;
}
- file_puts(task_tasks[i].stderrlog, data);
- fflush(task_tasks[i].stdoutlog);
+ fs_file_puts (task_tasks[i].stderrlog, data);
+ fs_file_flush(task_tasks[i].stdoutlog);
}
if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {