From: Dale Weiler Date: Sun, 23 Dec 2012 06:05:22 +0000 (+0000) Subject: Wrapper around FILE to take advantage of MSVC "secure" CRT. We don't actually defend... X-Git-Tag: 0.2~13 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=13003bf6af9cf8c76cd024b0bf11695b92fba093;p=xonotic%2Fgmqcc.git Wrapper around FILE to take advantage of MSVC "secure" CRT. We don't actually defend bounds checks (we just hack in the few ones to silent MSVC .. and to pass WinRT "native code" rules) --- diff --git a/Makefile b/Makefile index 0d1cee7..94b25e3 100644 --- a/Makefile +++ b/Makefile @@ -27,10 +27,10 @@ ifeq ($(track), no) CFLAGS += -DNOTRACK endif -OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o -OBJ_T = test.o util.o conout.o -OBJ_C = main.o lexer.o parser.o -OBJ_X = exec-standalone.o util.o conout.o +OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o file.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 ifneq ("$(CYGWIN)", "") #nullify the common variables that diff --git a/code.c b/code.c index 42a5595..0ad8bec 100644 --- a/code.c +++ b/code.c @@ -154,41 +154,42 @@ bool code_write(const char *filename, const char *lnofile) { uint32_t lnotype = *(unsigned int*)"LNOF"; uint32_t version = 1; - fp = util_fopen(lnofile, "wb"); + fp = file_open(lnofile, "wb"); if (!fp) return false; util_endianswap(&version, 1, sizeof(version)); util_endianswap(code_linenums, vec_size(code_linenums), sizeof(code_linenums[0])); - if (fwrite(&lnotype, sizeof(lnotype), 1, fp) != 1 || - fwrite(&version, sizeof(version), 1, fp) != 1 || - fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || - fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || - fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || - fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || - fwrite(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums)) + + if (file_write(&lnotype, sizeof(lnotype), 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)) { con_err("failed to write lno file\n"); } - fclose(fp); + file_close(fp); fp = NULL; } - fp = util_fopen(filename, "wb"); + fp = file_open(filename, "wb"); if (!fp) return false; - if (1 != fwrite(&code_header, sizeof(prog_header) , 1 , fp) || - vec_size(code_statements) != fwrite(code_statements, sizeof(prog_section_statement), vec_size(code_statements), fp) || - vec_size(code_defs) != fwrite(code_defs, sizeof(prog_section_def) , vec_size(code_defs) , fp) || - vec_size(code_fields) != fwrite(code_fields, sizeof(prog_section_field) , vec_size(code_fields) , fp) || - vec_size(code_functions) != fwrite(code_functions, sizeof(prog_section_function) , vec_size(code_functions) , fp) || - vec_size(code_globals) != fwrite(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) || - vec_size(code_chars) != fwrite(code_chars, 1 , vec_size(code_chars) , fp)) + 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)) { - fclose(fp); + file_close(fp); return false; } @@ -253,6 +254,6 @@ bool code_write(const char *filename, const char *lnofile) { vec_free(code_functions); vec_free(code_globals); vec_free(code_chars); - fclose(fp); + file_close(fp); return true; } diff --git a/conout.c b/conout.c index b8227e5..bf8b522 100644 --- a/conout.c +++ b/conout.c @@ -21,6 +21,7 @@ * SOFTWARE. */ #include "gmqcc.h" +#include /* * isatty/STDERR_FILENO/STDOUT_FILNO @@ -167,7 +168,7 @@ static int win_fputs(const char *str, FILE *h) { state = -1; } } else { - fputc(*str, h); + file_putc(*str, h); length ++; } str++; @@ -218,7 +219,7 @@ static int con_write(FILE *handle, const char *fmt, va_list va) { char data[4096]; memset(data, 0, sizeof(data)); vsnprintf(data, sizeof(data), fmt, va); - ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(data, handle) : fputs(data, handle); + ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(data, handle) : file_puts(data, handle); } #endif return ln; @@ -230,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)) - fclose(console.handle_err); + file_close(console.handle_err); if (!GMQCC_IS_DEFINE(console.handle_out)) - fclose(console.handle_out); + file_close(console.handle_out); } void con_color(int state) { @@ -268,15 +269,18 @@ void con_reset() { int con_change(const char *out, const char *err) { con_close(); + if (!out) out = (const char *)((!console.handle_out) ? stdout : console.handle_out); + if (!err) err = (const char *)((!console.handle_err) ? stderr : console.handle_err); + if (GMQCC_IS_DEFINE(out)) { console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr; con_enablecolor(); - } else if (!(console.handle_out = fopen(out, "w"))) return 0; + } else if (!(console.handle_out = 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 = fopen(err, "w"))) return 0; + } else if (!(console.handle_err = file_open(err, "w"))) return 0; /* no buffering */ setvbuf(console.handle_out, NULL, _IONBF, 0); diff --git a/exec.c b/exec.c index f4a986e..0b9b362 100644 --- a/exec.c +++ b/exec.c @@ -53,29 +53,28 @@ static void qcvmerror(qc_program *prog, const char *fmt, ...) qc_program* prog_load(const char *filename) { - qc_program *prog; - prog_header header; - FILE *file; + qc_program *prog; + prog_header header; + FILE *file = file_open(filename, "rb"); - file = util_fopen(filename, "rb"); if (!file) return NULL; - if (fread(&header, sizeof(header), 1, file) != 1) { + if (file_read(&header, sizeof(header), 1, file) != 1) { loaderror("failed to read header from '%s'", filename); - fclose(file); + file_close(file); return NULL; } if (header.version != 6) { loaderror("header says this is a version %i progs, we need version 6\n", header.version); - fclose(file); + file_close(file); return NULL; } prog = (qc_program*)mem_a(sizeof(qc_program)); if (!prog) { - fclose(file); + file_close(file); printf("failed to allocate program data\n"); return NULL; } @@ -91,15 +90,17 @@ qc_program* prog_load(const char *filename) } #define read_data(hdrvar, progvar, reserved) \ - if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ + if (file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ loaderror("seek failed"); \ goto error; \ } \ - if (fread(vec_add(prog->progvar, header.hdrvar.length + reserved), \ - sizeof(*prog->progvar), \ - header.hdrvar.length, file) \ - != header.hdrvar.length) \ - { \ + if (file_read ( \ + vec_add(prog->progvar, header.hdrvar.length + reserved), \ + sizeof(*prog->progvar), \ + header.hdrvar.length, \ + file \ + )!= header.hdrvar.length \ + ) { \ loaderror("read failed"); \ goto error; \ } @@ -113,7 +114,7 @@ qc_program* prog_load(const char *filename) read_data1(strings); read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */ - fclose(file); + file_close(file); /* profile counters */ memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code)); diff --git a/file.c b/file.c new file mode 100644 index 0000000..2bbd81f --- /dev/null +++ b/file.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2012 + * Wolfgang Bumiller + * 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 GMQCC_INLINE file_close(FILE *fp) { + /* Invokes file_exception on windows if fp is null */ + fclose (fp); +} + +size_t GMQCC_INLINE 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 GMQCC_INLINE file_error(FILE *fp) { + /* Invokes file_exception on windows if fp is null */ + return ferror(fp); +} + +int GMQCC_INLINE file_getc(FILE *fp) { + /* Invokes file_exception on windows if fp is null */ + return fgetc(fp); +} + +int GMQCC_INLINE file_puts(FILE *fp, const char *str) { + /* Invokes file_exception on windows if fp is null */ + return fputs(str, fp); +} + +int GMQCC_INLINE file_seek(FILE *fp, long int off, int whence) { + /* Invokes file_exception on windows if fp is null */ + return fseek(fp, off, whence); +} + +/* + * 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 96c20bf..ed501a5 100644 --- a/ftepp.c +++ b/ftepp.c @@ -991,9 +991,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 = util_fopen(filename, "rb"); + fp = file_open(filename, "rb"); if (fp) { - fclose(fp); + file_close(fp); return filename; } vec_free(filename); diff --git a/gmqcc.h b/gmqcc.h index af98f3f..1e4fe3b 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -26,8 +26,8 @@ #include #include #include -#include #include +#include #include /* @@ -159,7 +159,6 @@ # define strtof(X, Y) (float)(strtod(X, Y)) #endif - /* * Very roboust way at determining endianess at compile time: this handles * almost every possible situation. Otherwise a runtime check has to be @@ -245,8 +244,6 @@ /*===================================================================*/ /*=========================== util.c ================================*/ /*===================================================================*/ -FILE *util_fopen(const char *filename, const char *mode); - void *util_memory_a (size_t, unsigned int, const char *); void util_memory_d (void *, unsigned int, const char *); void *util_memory_r (void *, size_t, unsigned int, const char *); @@ -257,7 +254,6 @@ bool util_strupper (const char *); bool util_strdigit (const char *); char *util_strdup (const char *); void util_debug (const char *, const char *, ...); -int util_getline (char **, size_t *, FILE *); void util_endianswap (void *, size_t, unsigned int); size_t util_strtocmd (const char *, char *, size_t); @@ -383,10 +379,31 @@ void util_htdel (hash_table_t *ht); size_t util_hthash(hash_table_t *ht, const char *key); void *util_htgeth(hash_table_t *ht, const char *key, size_t hash); void util_htseth(hash_table_t *ht, const char *key, size_t hash, void *value); + +/*===================================================================*/ +/*============================ file.c ===============================*/ +/*===================================================================*/ +void GMQCC_INLINE file_close (FILE *); + +int GMQCC_INLINE file_error (FILE *); +int GMQCC_INLINE file_getc (FILE *); +int GMQCC_INLINE file_printf (FILE *, const char *, ...); +int GMQCC_INLINE file_puts (FILE *, const char *); +int GMQCC_INLINE file_seek (FILE *, long int, int); + +size_t GMQCC_INLINE file_read (void *, size_t, size_t, FILE *); +size_t GMQCC_INLINE file_write (const void *, size_t, size_t, FILE *); + +FILE* GMQCC_INLINE file_open (const char *, const char *); + +int /*NO_INLINE*/ file_getline(char **, size_t *, FILE *); + + /*===================================================================*/ /*=========================== code.c ================================*/ /*===================================================================*/ +/* TODO: cleanup */ /* Note: if you change the order, fix type_sizeof in ir.c */ enum { TYPE_VOID , @@ -806,6 +823,7 @@ vector vec3_mulvf(vector, float); /*============================= exec.c ==============================*/ /*===================================================================*/ +/* TODO: cleanup */ /* * Darkplaces has (or will have) a 64 bit prog loader * where the 32 bit qc program is autoconverted on load. @@ -910,6 +928,8 @@ bool parser_compile_file (const char *filename); bool parser_compile_string(const char *name, const char *str); bool parser_finish (const char *output); void parser_cleanup (); + +/* TODO: make compile_string accept len and remove this */ /* There's really no need to strlen() preprocessed files */ bool parser_compile_string_len(const char *name, const char *str, size_t len); @@ -1015,6 +1035,7 @@ typedef enum { COMPILER_GMQCC /* this QuakeC */ } opts_std_t; +/* TODO: cleanup this */ typedef struct { uint32_t O; /* -Ox */ const char *output; /* -o file */ diff --git a/lexer.c b/lexer.c index 7fc606c..cf554fb 100644 --- a/lexer.c +++ b/lexer.c @@ -186,7 +186,7 @@ static void lex_token_new(lex_file *lex) lex_file* lex_open(const char *file) { lex_file *lex; - FILE *in = util_fopen(file, "rb"); + FILE *in = file_open(file, "rb"); if (!in) { lexerror(NULL, "open failed: '%s'\n", file); @@ -195,7 +195,7 @@ lex_file* lex_open(const char *file) lex = (lex_file*)mem_a(sizeof(*lex)); if (!lex) { - fclose(in); + file_close(in); lexerror(NULL, "out of memory\n"); return NULL; } @@ -260,7 +260,7 @@ void lex_close(lex_file *lex) vec_free(lex->modelname); if (lex->file) - fclose(lex->file); + file_close(lex->file); #if 0 if (lex->tok) token_delete(lex->tok); diff --git a/main.c b/main.c index d6edd5c..d732ef9 100644 --- a/main.c +++ b/main.c @@ -139,8 +139,8 @@ static bool options_parse(int argc, char **argv) { bool argend = false; size_t itr; char buffer[1024]; - char *redirout = (char*)stdout; - char *redirerr = (char*)stderr; + char *redirout = NULL; + char *redirerr = NULL; char *config = NULL; while (!argend && argc > 1) { @@ -474,7 +474,7 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) { char *end; line = *out; - len = util_getline(&line, alen, src); + len = file_getline(&line, alen, src); if (len == -1) return false; @@ -553,15 +553,16 @@ int main(int argc, char **argv) { if (opts.pp_only) { if (opts_output_wasset) { - outfile = util_fopen(opts.output, "wb"); + outfile = file_open(opts.output, "wb"); if (!outfile) { con_err("failed to open `%s` for writing\n", opts.output); retval = 1; goto cleanup; } } - else - outfile = stdout; + else { + /* TODO: stdout without stdout .. */ + } } if (!opts.pp_only) { @@ -604,7 +605,7 @@ int main(int argc, char **argv) { progs_src = true; - src = util_fopen("progs.src", "rb"); + src = file_open("progs.src", "rb"); if (!src) { con_err("failed to open `progs.src` for reading\n"); retval = 1; @@ -633,7 +634,7 @@ int main(int argc, char **argv) { } srcdone: - fclose(src); + file_close(src); mem_d(line); } @@ -663,7 +664,7 @@ srcdone: } out = ftepp_get(); if (out) - fprintf(outfile, "%s", out); + file_printf(outfile, "%s", out); ftepp_flush(); } else { diff --git a/opts.c b/opts.c index 6008fb1..69e93b4 100644 --- a/opts.c +++ b/opts.c @@ -169,7 +169,7 @@ static size_t opts_ini_parse ( char *read_name; char *read_value; - while (util_getline(&line, &linesize, filehandle) != EOF) { + while (file_getline(&line, &linesize, filehandle) != EOF) { parse_beg = line; /* handle BOM */ @@ -315,11 +315,11 @@ void opts_ini_init(const char *file) { if (!file) { /* try ini */ - if (!(ini = fopen((file = "gmqcc.ini"), "r"))) + if (!(ini = file_open((file = "gmqcc.ini"), "r"))) /* try cfg */ - if (!(ini = fopen((file = "gmqcc.cfg"), "r"))) + if (!(ini = file_open((file = "gmqcc.cfg"), "r"))) return; - } else if (!(ini = fopen(file, "r"))) + } else if (!(ini = file_open(file, "r"))) return; con_out("found ini file `%s`\n", file); @@ -330,5 +330,5 @@ void opts_ini_init(const char *file) { vec_free(error); } - fclose(ini); + file_close(ini); } diff --git a/test.c b/test.c index b29a3d4..495b547 100644 --- a/test.c +++ b/test.c @@ -451,7 +451,7 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp) return false; /* top down parsing */ - while (util_getline(&back, &size, fp) != EOF) { + while (file_getline(&back, &size, fp) != EOF) { /* skip whitespace */ data = back; if (*data && (*data == ' ' || *data == '\t')) @@ -592,7 +592,7 @@ task_template_t *task_template_compile(const char *file, const char *dir) { memset (fullfile, 0, sizeof(fullfile)); snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file); - tempfile = fopen(fullfile, "r"); + tempfile = file_open(fullfile, "r"); template = mem_a(sizeof(task_template_t)); task_template_nullify(template); @@ -667,7 +667,7 @@ task_template_t *task_template_compile(const char *file, const char *dir) { } success: - fclose(tempfile); + file_close(tempfile); return template; failure: @@ -676,7 +676,7 @@ failure: * so the check to see if it's not null here is required. */ if (tempfile) - fclose(tempfile); + file_close(tempfile); mem_d (template); return NULL; @@ -812,7 +812,7 @@ bool task_propagate(const char *curdir) { memset (buf,0,sizeof(buf)); snprintf(buf, sizeof(buf), "%s.stdout", template->tempfilename); task.stdoutlogfile = util_strdup(buf); - if (!(task.stdoutlog = fopen(buf, "w"))) { + if (!(task.stdoutlog = file_open(buf, "w"))) { con_err("error opening %s for stdout\n", buf); continue; } @@ -820,7 +820,7 @@ bool task_propagate(const char *curdir) { memset (buf,0,sizeof(buf)); snprintf(buf, sizeof(buf), "%s.stderr", template->tempfilename); task.stderrlogfile = util_strdup(buf); - if (!(task.stderrlog = fopen(buf, "w"))) { + if (!(task.stderrlog = file_open(buf, "w"))) { con_err("error opening %s for stderr\n", buf); continue; } @@ -904,8 +904,8 @@ void task_destroy(const char *curdir) { * 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) fclose (task_tasks[i].stdoutlog); - if (task_tasks[i].stderrlog) fclose (task_tasks[i].stderrlog); + if (task_tasks[i].stdoutlog) file_close (task_tasks[i].stdoutlog); + if (task_tasks[i].stderrlog) file_close (task_tasks[i].stderrlog); /* * Only remove the log files if the test actually compiled otherwise @@ -983,7 +983,7 @@ bool task_execute(task_template_t *template, char ***line) { char *data = NULL; size_t size = 0; size_t compare = 0; - while (util_getline(&data, &size, execute) != EOF) { + while (file_getline(&data, &size, execute) != EOF) { if (!strcmp(data, "No main function found\n")) { con_err("test failure: `%s` [%s] (No main function found)\n", template->description, @@ -1059,8 +1059,8 @@ void task_schedualize() { * Read data from stdout first and pipe that stuff into a log file * then we do the same for stderr. */ - while (util_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) { - fputs(data, task_tasks[i].stdoutlog); + while (file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) { + file_puts(task_tasks[i].stdoutlog, data); if (strstr(data, "failed to open file")) { task_tasks[i].compiled = false; @@ -1069,7 +1069,7 @@ void task_schedualize() { fflush(task_tasks[i].stdoutlog); } - while (util_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) { + while (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. @@ -1083,7 +1083,7 @@ void task_schedualize() { task_tasks[i].compiled = false; } - fputs(data, task_tasks[i].stderrlog); + file_puts(task_tasks[i].stderrlog, data); fflush(task_tasks[i].stdoutlog); } diff --git a/util.c b/util.c index 2b2f1b0..c744b15 100644 --- a/util.c +++ b/util.c @@ -25,6 +25,7 @@ #include #include "gmqcc.h" +/* TODO: remove globals ... */ uint64_t mem_ab = 0; uint64_t mem_db = 0; uint64_t mem_at = 0; @@ -347,54 +348,6 @@ uint16_t util_crc16(const char *k, int len, const short clamp) { } #endif -/* - * Implements libc getline for systems that don't have it, which is - * assmed all. This works the same as getline(). - */ -int util_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 = 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); -} - size_t util_strtocmd(const char *in, char *out, size_t outsz) { size_t sz = 1; for (; *in && sz < outsz; ++in, ++out, ++sz) @@ -411,19 +364,7 @@ size_t util_strtononcmd(const char *in, char *out, size_t outsz) { return sz-1; } - -FILE *util_fopen(const char *filename, const char *mode) -{ -#ifdef _MSC_VER - FILE *out; - if (fopen_s(&out, filename, mode) != 0) - return NULL; - return out; -#else - return fopen(filename, mode); -#endif -} - +/* TODO: rewrite ... when I redo the ve cleanup */ void _util_vec_grow(void **a, size_t i, size_t s) { size_t m = *a ? 2*_vec_beg(*a)+i : i+1; void *p = mem_r((*a ? _vec_raw(*a) : NULL), s * m + sizeof(size_t)*2);