From: Dale Weiler Date: Fri, 8 Feb 2013 12:06:59 +0000 (+0000) Subject: Cleanup cargocult directory and file specific things, to fs.c (renamed file.c which... X-Git-Tag: before-library~131 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=8d59d7029d02fef54d905f2de9babcb571f7ead2 Cleanup cargocult directory and file specific things, to fs.c (renamed file.c which also contains directory handling stuff). Also cleaned up some stuff, and added proper end comments to conditional inclusion stuff. --- diff --git a/Makefile b/Makefile index e229f21..f64263b 100644 --- a/Makefile +++ b/Makefile @@ -41,10 +41,10 @@ ifeq ($(track), no) CFLAGS += -DNOTRACK endif -OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o file.o utf8.o correct.o 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 @@ -199,7 +199,7 @@ ir.o: gmqcc.h opts.def ir.h conout.o: gmqcc.h opts.def ftepp.o: gmqcc.h opts.def lexer.h opts.o: gmqcc.h opts.def -file.o: gmqcc.h opts.def +fs.o: gmqcc.h opts.def utf8.o: gmqcc.h opts.def correct.o: gmqcc.h opts.def pak.o: gmqcc.h opts.def @@ -207,13 +207,13 @@ 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 diff --git a/code.c b/code.c index 43a34c9..5728a8d 100644 --- a/code.c +++ b/code.c @@ -171,7 +171,7 @@ bool code_write(const char *filename, const char *lnofile) { if (lnofile) { uint32_t version = 1; - fp = file_open(lnofile, "wb"); + fp = fs_file_open(lnofile, "wb"); if (!fp) return false; @@ -179,34 +179,34 @@ bool code_write(const char *filename, const char *lnofile) { util_endianswap(code_linenums, vec_size(code_linenums), sizeof(code_linenums[0])); - if (file_write("LNOF", 4, 1, fp) != 1 || - file_write(&version, sizeof(version), 1, fp) != 1 || - file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || - file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || - file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || - file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || - file_write(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums)) + if (fs_file_write("LNOF", 4, 1, fp) != 1 || + fs_file_write(&version, sizeof(version), 1, fp) != 1 || + fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || + fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || + fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || + fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || + fs_file_write(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums)) { con_err("failed to write lno file\n"); } - file_close(fp); + fs_file_close(fp); fp = NULL; } - fp = file_open(filename, "wb"); + fp = fs_file_open(filename, "wb"); if (!fp) return false; - if (1 != file_write(&code_header, sizeof(prog_header) , 1 , fp) || - vec_size(code_statements) != file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) || - vec_size(code_defs) != file_write(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) || - vec_size(code_fields) != file_write(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) || - vec_size(code_functions) != file_write(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) || - vec_size(code_globals) != file_write(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) || - vec_size(code_chars) != file_write(code_chars, 1 , vec_size(code_chars) , fp)) + if (1 != fs_file_write(&code_header, sizeof(prog_header) , 1 , fp) || + vec_size(code_statements) != fs_file_write(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) || + vec_size(code_defs) != fs_file_write(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) || + vec_size(code_fields) != fs_file_write(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) || + vec_size(code_functions) != fs_file_write(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) || + vec_size(code_globals) != fs_file_write(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) || + vec_size(code_chars) != fs_file_write(code_chars, 1 , vec_size(code_chars) , fp)) { - file_close(fp); + fs_file_close(fp); return false; } @@ -273,6 +273,6 @@ bool code_write(const char *filename, const char *lnofile) { vec_free(code_chars); util_htdel(code_string_cache); - file_close(fp); + fs_file_close(fp); return true; } diff --git a/conout.c b/conout.c index 81cf481..b7cc2e1 100644 --- a/conout.c +++ b/conout.c @@ -231,9 +231,9 @@ static int con_write(FILE *handle, const char *fmt, va_list va) { void con_close() { if (!GMQCC_IS_DEFINE(console.handle_err)) - file_close(console.handle_err); + fs_file_close(console.handle_err); if (!GMQCC_IS_DEFINE(console.handle_out)) - file_close(console.handle_out); + fs_file_close(console.handle_out); } void con_color(int state) { @@ -275,12 +275,12 @@ int con_change(const char *out, const char *err) { if (GMQCC_IS_DEFINE(out)) { console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr; con_enablecolor(); - } else if (!(console.handle_out = file_open(out, "w"))) return 0; + } else if (!(console.handle_out = fs_file_open(out, "w"))) return 0; if (GMQCC_IS_DEFINE(err)) { console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr; con_enablecolor(); - } else if (!(console.handle_err = file_open(err, "w"))) return 0; + } else if (!(console.handle_err = fs_file_open(err, "w"))) return 0; /* no buffering */ setvbuf(console.handle_out, NULL, _IONBF, 0); diff --git a/exec.c b/exec.c index d544815..f44bd62 100644 --- a/exec.c +++ b/exec.c @@ -55,26 +55,26 @@ qc_program* prog_load(const char *filename, bool skipversion) { qc_program *prog; prog_header header; - FILE *file = file_open(filename, "rb"); + FILE *file = fs_file_open(filename, "rb"); if (!file) return NULL; - if (file_read(&header, sizeof(header), 1, file) != 1) { + if (fs_file_read(&header, sizeof(header), 1, file) != 1) { loaderror("failed to read header from '%s'", filename); - file_close(file); + fs_file_close(file); return NULL; } if (!skipversion && header.version != 6) { loaderror("header says this is a version %i progs, we need version 6\n", header.version); - file_close(file); + fs_file_close(file); return NULL; } prog = (qc_program*)mem_a(sizeof(qc_program)); if (!prog) { - file_close(file); + fs_file_close(file); fprintf(stderr, "failed to allocate program data\n"); return NULL; } @@ -90,11 +90,11 @@ qc_program* prog_load(const char *filename, bool skipversion) } #define read_data(hdrvar, progvar, reserved) \ - if (file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ + if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ loaderror("seek failed"); \ goto error; \ } \ - if (file_read ( \ + if (fs_file_read ( \ vec_add(prog->progvar, header.hdrvar.length + reserved), \ sizeof(*prog->progvar), \ header.hdrvar.length, \ @@ -114,7 +114,7 @@ qc_program* prog_load(const char *filename, bool skipversion) read_data1(strings); read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */ - file_close(file); + fs_file_close(file); /* profile counters */ memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code)); @@ -354,7 +354,7 @@ static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) done: if (len < (int)sizeof(spaces)-1) { spaces[sizeof(spaces)-1-len] = 0; - file_puts(stdout, spaces); + fs_file_puts(stdout, spaces); spaces[sizeof(spaces)-1-len] = ' '; } } diff --git a/file.c b/file.c deleted file mode 100644 index fe6167f..0000000 --- a/file.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2012, 2013 - * Dale Weiler - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "gmqcc.h" - -/* - * This is essentially a "wrapper" interface around standard C's IO - * library. There is two reason we implement this, 1) visual studio - * hearts for "secure" varations, as part of it's "Security Enhancements - * in the CRT" (http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx). - * 2) But one of the greater reasons is for the possibility of large file - * support in the future. I don't expect to reach the 2GB limit any - * time soon (mainly because that would be insane). But when it comes - * to adding support for some other larger IO tasks (in the test-suite, - * or even the QCVM we'll need it). There is also a third possibility of - * building .dat files directly from zip files (which would be very cool - * at least I think so). - */ -#ifdef _MSC_VER -/* {{{ */ - /* - * Visual Studio has security CRT features which I actually want to support - * if we ever port to Windows 8, and want GMQCC to be API safe. - * - * We handle them here, for all file-operations. - */ - - static void file_exception ( - const wchar_t *expression, - const wchar_t *function, - const wchar_t *file, - unsigned int line, - uintptr_t reserved - ) { - wprintf(L"Invalid parameter dectected %s:%d %s [%s]\n", file, line, function, expression); - wprintf(L"Aborting ...\n"); - abort(); - } - - static void file_init() { - static bool init = false; - - if (init) - return; - - _set_invalid_parameter_handler(&file_exception); - - /* - * Turnoff the message box for CRT asserations otherwise - * we don't get the error reported to the console as we should - * otherwise get. - */ - _CrtSetReportMode(_CRT_ASSERT, 0); - init = !init; - } - - - FILE *file_open(const char *filename, const char *mode) { - FILE *handle = NULL; - file_init(); - - return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle; - } - - size_t file_read(void *buffer, size_t size, size_t count, FILE *fp) { - file_init(); - return fread_s(buffer, size*count, size, count, fp); - } - - int file_printf(FILE *fp, const char *format, ...) { - int rt; - va_list va; - va_start(va, format); - - file_init(); - rt = vfprintf_s(fp, format, va); - va_end (va); - - return rt; - } - -/* }}} */ -#else -/* {{{ */ - /* - * All other compilers/platforms that don't restrict insane policies on - * IO for no aparent reason. - */ - FILE *file_open(const char *filename, const char *mode) { - return fopen(filename, mode); - } - - size_t file_read(void *buffer, size_t size, size_t count, FILE *fp) { - return fread(buffer, size, count, fp); - } - - int file_printf(FILE *fp, const char *format, ...) { - int rt; - va_list va; - va_start(va, format); - rt = vfprintf(fp, format, va); - va_end (va); - - return rt; - } - -/* }}} */ -#endif - -/* - * These are implemented as just generic wrappers to keep consistency in - * the API. Not as macros though - */ -void file_close(FILE *fp) { - /* Invokes file_exception on windows if fp is null */ - fclose (fp); -} - -size_t file_write ( - const void *buffer, - size_t size, - size_t count, - FILE *fp -) { - /* Invokes file_exception on windows if fp is null */ - return fwrite(buffer, size, count, fp); -} - -int file_error(FILE *fp) { - /* Invokes file_exception on windows if fp is null */ - return ferror(fp); -} - -int file_getc(FILE *fp) { - /* Invokes file_exception on windows if fp is null */ - return fgetc(fp); -} - -int file_puts(FILE *fp, const char *str) { - /* Invokes file_exception on windows if fp is null */ - return fputs(str, fp); -} - -int file_seek(FILE *fp, long int off, int whence) { - /* Invokes file_exception on windows if fp is null */ - return fseek(fp, off, whence); -} - -int file_putc(FILE *fp, int ch) { - /* Invokes file_exception on windows if fp is null */ - return fputc(ch, fp); -} - -/* - * Implements libc getline for systems that don't have it, which is - * assmed all. This works the same as getline(). - */ -int file_getline(char **lineptr, size_t *n, FILE *stream) { - int chr; - int ret; - char *pos; - - if (!lineptr || !n || !stream) - return -1; - if (!*lineptr) { - if (!(*lineptr = (char*)mem_a((*n=64)))) - return -1; - } - - chr = *n; - pos = *lineptr; - - for (;;) { - int c = file_getc(stream); - - if (chr < 2) { - *n += (*n > 16) ? *n : 64; - chr = *n + *lineptr - pos; - if (!(*lineptr = (char*)mem_r(*lineptr,*n))) - return -1; - pos = *n - chr + *lineptr; - } - - if (ferror(stream)) - return -1; - if (c == EOF) { - if (pos == *lineptr) - return -1; - else - break; - } - - *pos++ = c; - chr--; - if (c == '\n') - break; - } - *pos = '\0'; - return (ret = pos - *lineptr); -} diff --git a/ftepp.c b/ftepp.c index 27e3afe..4734639 100644 --- a/ftepp.c +++ b/ftepp.c @@ -1250,9 +1250,9 @@ static char *ftepp_include_find_path(const char *file, const char *pathfile) memcpy(vec_add(filename, len+1), file, len); vec_last(filename) = 0; - fp = file_open(filename, "rb"); + fp = fs_file_open(filename, "rb"); if (fp) { - file_close(fp); + fs_file_close(fp); return filename; } vec_free(filename); diff --git a/gmqcc.h b/gmqcc.h index ae44301..206688f 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -37,7 +37,7 @@ #ifdef _MSC_VER # pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */ # pragma warning(disable : 4018 ) /* signed/unsigned mismatch */ -#endif +#endif /*! _MSC_VER */ #define GMQCC_VERSION_MAJOR 0 #define GMQCC_VERSION_MINOR 3 @@ -55,7 +55,7 @@ # define GMQCC_DEV_VERSION_STRING "development build\n" #else # define GMQCC_DEV_VERSION_STRING -#endif +#endif /*! GMQCC_GITINGO */ #define GMQCC_STRINGIFY(x) #x #define GMQCC_IND_STRING(x) GMQCC_STRINGIFY(x) @@ -78,10 +78,10 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ #ifndef __cplusplus # ifdef false # undef false -# endif /* !false */ +# endif /*! false */ # ifdef true # undef true -# endif /* !true */ +# endif /*! true */ # define false (0) # define true (1) # ifdef __STDC_VERSION__ @@ -89,11 +89,11 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ typedef int bool; # else typedef _Bool bool; -# endif +# endif /*! __STDC_VERSION__ < 199901L && __GNUC__ < 3 */ # else typedef int bool; -# endif /* !__STDC_VERSION__ */ -#endif /* !__cplusplus */ +# endif /*! __STDC_VERSION__ */ +#endif /*! __cplusplus */ /* * Of some functions which are generated we want to make sure @@ -106,7 +106,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ #else # define GMQCC_WARN # define GMQCC_USED -#endif +#endif /*! defined(__GNUC__) || defined (__CLANG__) */ /* * This is a hack to silent clang regarding empty * body if statements. @@ -125,13 +125,13 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define GMQCC_INLINE # else # define GMQCC_INLINE __attribute__ ((always_inline)) -# endif +# endif /*! __GNUC__ < 2 */ # else # define GMQCC_INLINE -# endif +# endif /*! defined(__GNUC__) || defined (__CLANG__) */ # else # define GMQCC_INLINE inline -# endif +# endif /*! __STDC_VERSION < 199901L */ /* * Visual studio has __forcinline we can use. So lets use that * I suspect it also has just __inline of some sort, but our use @@ -141,7 +141,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define GMQCC_INLINE __forceinline #else # define GMQCC_INLINE -#endif /* !__STDC_VERSION__ */ +#endif /*! __STDC_VERSION__ */ /* * noreturn is present in GCC and clang @@ -153,7 +153,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define GMQCC_NORETURN __attribute__ ((noreturn)) #else # define GMQCC_NORETURN -#endif +#endif /*! (defined(__GNUC__) && __GNUC__ >= 2) || defined (__CLANG__) */ #ifndef _MSC_VER # include @@ -166,7 +166,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; -#endif +#endif /*! _MSC_VER */ /* *windows makes these prefixed because they're C99 @@ -177,7 +177,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define snprintf(X, Y, Z, ...) _snprintf(X, Y, Z, __VA_ARGS__) /* strtof doesn't exist -> strtod does though :) */ # define strtof(X, Y) (float)(strtod(X, Y)) -#endif +#endif /*! _MSC_VER */ /* * Very roboust way at determining endianess at compile time: this handles @@ -197,14 +197,14 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define BIG_ENDIAN # elif defined (__LITTLE_ENDIAN__) && !defined (LITTLE_ENDIAN) # define LITTLE_ENDIAN -# endif +# endif /*! defined (__BIG_ENDIAN__) && !defined(BIG_ENDIAN) */ # elif !defined (__MINGW32__) # include # if !defined (__BEOS__) # include -# endif -# endif -#endif +# endif /*! !definde (__BEOS__) */ +# endif /*! defined (__FreeBSD__) || defined (__OpenBSD__) */ +#endif /*! defined (__GNUC__) || defined (__GNU_LIBRARY__) */ #if !defined(PLATFORM_BYTE_ORDER) # if defined (LITTLE_ENDIAN) || defined (BIG_ENDIAN) # if defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN) @@ -215,7 +215,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE # elif defined (BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG -# endif +# endif /*! defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN) */ # elif defined (_LITTLE_ENDIAN) || defined (_BIG_ENDIAN) # if defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE @@ -225,7 +225,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE # elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN) # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG -# endif +# endif /*! defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) */ # elif defined (__LITTLE_ENDIAN__) || defined (__BIG_ENDIAN__) # if defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__) # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE @@ -235,9 +235,9 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE # elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__) # define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG -# endif -# endif -#endif +# endif /*! defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__) */ +# endif /*! defined(LITTLE_ENDIAN) || defined (BIG_ENDIAN) */ +#endif /*! !defined(PLATFORM_BYTE_ORDER) */ #if !defined (PLATFORM_BYTE_ORDER) # if defined (__alpha__) || defined (__alpha) || defined (i386) || \ defined (__i386__) || defined (_M_I86) || defined (_M_IX86) || \ @@ -257,8 +257,36 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # else # define PLATFORM_BYTE_ORDER -1 # endif -#endif +#endif /*! !defined (PLATFORM_BYTE_ORDER) */ +/* + * On windows systems where we're not compiling with MING32 we need a + * little extra help on dependinces for implementing our own dirent.h + * in fs.c. + */ +#if defined(_WIN32) && !defined(__MINGW32__) +# define _WIN32_LEAN_AND_MEAN +# include +# include +# include + + 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 +#endif /*! _WIN32 && !defined(__MINGW32__) */ /*===================================================================*/ @@ -296,7 +324,7 @@ int util_asprintf (char **ret, const char *fmt, ...); # define mem_a(x) util_memory_a((x), __LINE__, __FILE__) # define mem_d(x) util_memory_d((void*)(x)) # define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__) -#endif +#endif /*! NOTRACK */ /* * A flexible vector implementation: all vector pointers contain some @@ -434,19 +462,29 @@ void util_hsdel(hash_set_t *); /*===================================================================*/ /*============================ file.c ===============================*/ /*===================================================================*/ -GMQCC_INLINE void file_close (FILE *); -GMQCC_INLINE int file_error (FILE *); -GMQCC_INLINE int file_getc (FILE *); -GMQCC_INLINE int file_printf (FILE *, const char *, ...); -GMQCC_INLINE int file_puts (FILE *, const char *); -GMQCC_INLINE int file_putc (FILE *, int); -GMQCC_INLINE int file_seek (FILE *, long int, int); - -GMQCC_INLINE size_t file_read (void *, size_t, size_t, FILE *); -GMQCC_INLINE size_t file_write (const void *, size_t, size_t, FILE *); - -GMQCC_INLINE FILE *file_open (const char *, const char *); -/*NOINLINE*/ int file_getline(char **, size_t *, FILE *); +/* file handling */ +void fs_file_close (FILE *); +int fs_file_error (FILE *); +int fs_file_getc (FILE *); +int fs_file_flush (FILE *); +int fs_file_printf (FILE *, const char *, ...); +int fs_file_puts (FILE *, const char *); +int fs_file_putc (FILE *, int); +int fs_file_seek (FILE *, long int, int); +long int fs_file_tell (FILE *); + +size_t fs_file_read (void *, size_t, size_t, FILE *); +size_t fs_file_write (const void *, size_t, size_t, FILE *); + +FILE *fs_file_open (const char *, const char *); +int fs_file_getline(char **, size_t *, FILE *); + +/* directory handling */ +DIR *fs_dir_open (const char *); +int fs_dir_close (DIR *); +struct dirent *fs_dir_read (DIR *); +int fs_dir_make (const char *); +int fs_dir_change (const char *); /*===================================================================*/ @@ -1168,4 +1206,4 @@ extern opts_cmd_t opts; #define OPTS_OPTION_U32(X) (opts.options[X].U32) #define OPTS_OPTION_STR(X) (opts.options[X].STR) -#endif +#endif /*! GMQCC_HDR */ diff --git a/lexer.c b/lexer.c index 0dc17ad..bb60121 100644 --- a/lexer.c +++ b/lexer.c @@ -184,7 +184,7 @@ static void lex_token_new(lex_file *lex) lex_file* lex_open(const char *file) { lex_file *lex; - FILE *in = file_open(file, "rb"); + FILE *in = fs_file_open(file, "rb"); if (!in) { lexerror(NULL, "open failed: '%s'\n", file); @@ -193,7 +193,7 @@ lex_file* lex_open(const char *file) lex = (lex_file*)mem_a(sizeof(*lex)); if (!lex) { - file_close(in); + fs_file_close(in); lexerror(NULL, "out of memory\n"); return NULL; } @@ -258,7 +258,7 @@ void lex_close(lex_file *lex) vec_free(lex->modelname); if (lex->file) - file_close(lex->file); + fs_file_close(lex->file); #if 0 if (lex->tok) token_delete(lex->tok); diff --git a/main.c b/main.c index 5e4e8c1..e801aaf 100644 --- a/main.c +++ b/main.c @@ -522,7 +522,7 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) { char *end; line = *out; - len = file_getline(&line, alen, src); + len = fs_file_getline(&line, alen, src); if (len == -1) return false; @@ -608,7 +608,7 @@ int main(int argc, char **argv) { if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) { if (opts_output_wasset) { - outfile = file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb"); + outfile = fs_file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb"); if (!outfile) { con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT)); retval = 1; @@ -660,7 +660,7 @@ int main(int argc, char **argv) { progs_src = true; - src = file_open("progs.src", "rb"); + src = fs_file_open("progs.src", "rb"); if (!src) { con_err("failed to open `progs.src` for reading\n"); retval = 1; @@ -689,7 +689,7 @@ int main(int argc, char **argv) { } srcdone: - file_close(src); + fs_file_close(src); mem_d(line); } @@ -723,7 +723,7 @@ srcdone: } out = ftepp_get(); if (out) - file_printf(outfile, "%s", out); + fs_file_printf(outfile, "%s", out); ftepp_flush(); } else { diff --git a/opts.c b/opts.c index c669ee7..aa923bd 100644 --- a/opts.c +++ b/opts.c @@ -190,7 +190,7 @@ static size_t opts_ini_parse ( char *read_name; char *read_value; - while (file_getline(&line, &linesize, filehandle) != EOF) { + while (fs_file_getline(&line, &linesize, filehandle) != EOF) { parse_beg = line; /* handle BOM */ @@ -345,11 +345,11 @@ void opts_ini_init(const char *file) { if (!file) { /* try ini */ - if (!(ini = file_open((file = "gmqcc.ini"), "r"))) + if (!(ini = fs_file_open((file = "gmqcc.ini"), "r"))) /* try cfg */ - if (!(ini = file_open((file = "gmqcc.cfg"), "r"))) + if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r"))) return; - } else if (!(ini = file_open(file, "r"))) + } else if (!(ini = fs_file_open(file, "r"))) return; con_out("found ini file `%s`\n", file); @@ -360,5 +360,5 @@ void opts_ini_init(const char *file) { vec_free(error); } - file_close(ini); + fs_file_close(ini); } diff --git a/pak.c b/pak.c index 875ca3d..35963ea 100644 --- a/pak.c +++ b/pak.c @@ -22,7 +22,13 @@ */ #include #include -#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" */ @@ -71,20 +77,6 @@ static char *pak_tree_sep(char **str, const char *sep) { 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 @@ -107,7 +99,7 @@ static void pak_tree_build(const char *entry) { 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; } @@ -115,7 +107,14 @@ static void pak_tree_build(const char *entry) { 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); @@ -136,7 +135,7 @@ static pak_file_t *pak_open_read(const char *file) { 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; } @@ -145,17 +144,17 @@ static pak_file_t *pak_open_read(const char *file) { 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; } @@ -163,7 +162,7 @@ static pak_file_t *pak_open_read(const char *file) { * Time to read in the directory handles and prepare the directories * vector. We're going to be reading some the file inwards soon. */ - 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 @@ -171,8 +170,8 @@ static pak_file_t *pak_open_read(const char *file) { */ 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); } @@ -191,7 +190,7 @@ static pak_file_t *pak_open_write(const char *file) { */ 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. @@ -208,13 +207,8 @@ static pak_file_t *pak_open_write(const char *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 @@ -222,7 +216,7 @@ static pak_file_t *pak_open_write(const char *file) { * 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; } @@ -244,12 +238,7 @@ bool pak_exists(pak_file_t *pak, const char *file, pak_directory_t **dir) { 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)) { /* @@ -292,21 +281,21 @@ bool pak_extract_one(pak_file_t *pak, const char *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); @@ -317,10 +306,10 @@ bool pak_extract_one(pak_file_t *pak, const char *file) { 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++) { @@ -348,7 +337,7 @@ bool pak_insert_one(pak_file_t *pak, const char *file) { 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; /* @@ -356,18 +345,18 @@ bool pak_insert_one(pak_file_t *pak, const char *file) { * the directory entry, and the actual contents of the file * to the PAK file itself. */ - 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; } @@ -378,13 +367,13 @@ bool pak_insert_one(pak_file_t *pak, const char *file) { * 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 @@ -406,17 +395,17 @@ bool pak_insert_all(pak_file_t *pak, const char *dir) { 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; } @@ -435,34 +424,20 @@ bool pak_close(pak_file_t *pak) { 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 - diff --git a/test.c b/test.c index 42a1272..310f996 100644 --- a/test.c +++ b/test.c @@ -152,17 +152,10 @@ int task_pclose(FILE **handles) { return status; } #else -# define _WIN32_LEAN_AND_MEAN -# define popen _popen -# define pclose _pclose -# include -# include -# include /* * Bidirectional piping implementation for windows using CreatePipe and DuplicateHandle + * other hacks. */ - typedef struct { int __dummy; /* TODO: implement */ @@ -181,96 +174,10 @@ int task_pclose(FILE **handles) { (void)files; return; } - -# ifdef __MINGW32__ - /* mingw32 has dirent.h */ -# include -# 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 @@ -439,7 +346,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size 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')) @@ -580,7 +487,7 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_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); @@ -664,7 +571,7 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t } success: - file_close(tempfile); + fs_file_close(tempfile); return tmpl; failure: @@ -673,7 +580,7 @@ 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; @@ -853,7 +760,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) { 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; } @@ -861,7 +768,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) { 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; } @@ -920,8 +827,8 @@ void task_destroy(void) { * annoying to have to do all this cleanup work. */ if (task_tasks[i].runhandles) task_pclose(task_tasks[i].runhandles); - if (task_tasks[i].stdoutlog) file_close (task_tasks[i].stdoutlog); - if (task_tasks[i].stderrlog) file_close (task_tasks[i].stderrlog); + if (task_tasks[i].stdoutlog) fs_file_close (task_tasks[i].stdoutlog); + if (task_tasks[i].stderrlog) fs_file_close (task_tasks[i].stderrlog); /* * Only remove the log files if the test actually compiled otherwise @@ -995,7 +902,7 @@ bool task_execute(task_template_t *tmpl, char ***line) { char *data = NULL; size_t size = 0; size_t compare = 0; - while (file_getline(&data, &size, execute) != EOF) { + while (fs_file_getline(&data, &size, execute) != EOF) { if (!strcmp(data, "No main function found\n")) { con_err("test failure: `%s` (No main function found) [%s]\n", tmpl->description, @@ -1070,17 +977,17 @@ void task_schedualize(size_t *pad) { * Read data from stdout first and pipe that stuff into a log file * then we do the same for stderr. */ - while (file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) { - file_puts(task_tasks[i].stdoutlog, data); + while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) { + fs_file_puts(task_tasks[i].stdoutlog, data); if (strstr(data, "failed to open file")) { task_tasks[i].compiled = false; execute = false; } - fflush(task_tasks[i].stdoutlog); + fs_file_flush(task_tasks[i].stdoutlog); } - while (file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) { + while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) { /* * If a string contains an error we just dissalow execution * of it in the vm. @@ -1094,8 +1001,8 @@ void task_schedualize(size_t *pad) { task_tasks[i].compiled = false; } - file_puts(task_tasks[i].stderrlog, data); - fflush(task_tasks[i].stdoutlog); + fs_file_puts (task_tasks[i].stderrlog, data); + fs_file_flush(task_tasks[i].stdoutlog); } if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {