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)

This commit is contained in:
Dale Weiler 2012-12-23 06:05:22 +00:00
parent b4e38a8fed
commit 13003bf6af
12 changed files with 326 additions and 142 deletions

View file

@ -27,10 +27,10 @@ ifeq ($(track), no)
CFLAGS += -DNOTRACK CFLAGS += -DNOTRACK
endif endif
OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.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 OBJ_T = test.o util.o conout.o file.o
OBJ_C = main.o lexer.o parser.o OBJ_C = main.o lexer.o parser.o file.o
OBJ_X = exec-standalone.o util.o conout.o OBJ_X = exec-standalone.o util.o conout.o file.o
ifneq ("$(CYGWIN)", "") ifneq ("$(CYGWIN)", "")
#nullify the common variables that #nullify the common variables that

39
code.c
View file

@ -154,41 +154,42 @@ bool code_write(const char *filename, const char *lnofile) {
uint32_t lnotype = *(unsigned int*)"LNOF"; uint32_t lnotype = *(unsigned int*)"LNOF";
uint32_t version = 1; uint32_t version = 1;
fp = util_fopen(lnofile, "wb"); fp = file_open(lnofile, "wb");
if (!fp) if (!fp)
return false; return false;
util_endianswap(&version, 1, sizeof(version)); util_endianswap(&version, 1, sizeof(version));
util_endianswap(code_linenums, vec_size(code_linenums), sizeof(code_linenums[0])); 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 || if (file_write(&lnotype, sizeof(lnotype), 1, fp) != 1 ||
fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || file_write(&version, sizeof(version), 1, fp) != 1 ||
fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
fwrite(code_linenums, sizeof(code_linenums[0]), vec_size(code_linenums), fp) != vec_size(code_linenums)) 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"); con_err("failed to write lno file\n");
} }
fclose(fp); file_close(fp);
fp = NULL; fp = NULL;
} }
fp = util_fopen(filename, "wb"); fp = file_open(filename, "wb");
if (!fp) if (!fp)
return false; return false;
if (1 != fwrite(&code_header, sizeof(prog_header) , 1 , fp) || if (1 != file_write(&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_statements) != file_write(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_defs) != file_write(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_fields) != file_write(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_functions) != file_write(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_globals) != file_write(code_globals, sizeof(int32_t) , vec_size(code_globals) , fp) ||
vec_size(code_chars) != fwrite(code_chars, 1 , vec_size(code_chars) , fp)) vec_size(code_chars) != file_write(code_chars, 1 , vec_size(code_chars) , fp))
{ {
fclose(fp); file_close(fp);
return false; return false;
} }
@ -253,6 +254,6 @@ bool code_write(const char *filename, const char *lnofile) {
vec_free(code_functions); vec_free(code_functions);
vec_free(code_globals); vec_free(code_globals);
vec_free(code_chars); vec_free(code_chars);
fclose(fp); file_close(fp);
return true; return true;
} }

View file

@ -21,6 +21,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "gmqcc.h" #include "gmqcc.h"
#include <stdio.h>
/* /*
* isatty/STDERR_FILENO/STDOUT_FILNO * isatty/STDERR_FILENO/STDOUT_FILNO
@ -167,7 +168,7 @@ static int win_fputs(const char *str, FILE *h) {
state = -1; state = -1;
} }
} else { } else {
fputc(*str, h); file_putc(*str, h);
length ++; length ++;
} }
str++; str++;
@ -218,7 +219,7 @@ static int con_write(FILE *handle, const char *fmt, va_list va) {
char data[4096]; char data[4096];
memset(data, 0, sizeof(data)); memset(data, 0, sizeof(data));
vsnprintf(data, sizeof(data), fmt, va); 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 #endif
return ln; return ln;
@ -230,9 +231,9 @@ static int con_write(FILE *handle, const char *fmt, va_list va) {
void con_close() { void con_close() {
if (!GMQCC_IS_DEFINE(console.handle_err)) if (!GMQCC_IS_DEFINE(console.handle_err))
fclose(console.handle_err); file_close(console.handle_err);
if (!GMQCC_IS_DEFINE(console.handle_out)) if (!GMQCC_IS_DEFINE(console.handle_out))
fclose(console.handle_out); file_close(console.handle_out);
} }
void con_color(int state) { void con_color(int state) {
@ -268,15 +269,18 @@ void con_reset() {
int con_change(const char *out, const char *err) { int con_change(const char *out, const char *err) {
con_close(); 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)) { if (GMQCC_IS_DEFINE(out)) {
console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr; console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
con_enablecolor(); 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)) { if (GMQCC_IS_DEFINE(err)) {
console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr; console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr;
con_enablecolor(); 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 */ /* no buffering */
setvbuf(console.handle_out, NULL, _IONBF, 0); setvbuf(console.handle_out, NULL, _IONBF, 0);

25
exec.c
View file

@ -55,27 +55,26 @@ qc_program* prog_load(const char *filename)
{ {
qc_program *prog; qc_program *prog;
prog_header header; prog_header header;
FILE *file; FILE *file = file_open(filename, "rb");
file = util_fopen(filename, "rb");
if (!file) if (!file)
return NULL; 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); loaderror("failed to read header from '%s'", filename);
fclose(file); file_close(file);
return NULL; return NULL;
} }
if (header.version != 6) { if (header.version != 6) {
loaderror("header says this is a version %i progs, we need version 6\n", header.version); loaderror("header says this is a version %i progs, we need version 6\n", header.version);
fclose(file); file_close(file);
return NULL; return NULL;
} }
prog = (qc_program*)mem_a(sizeof(qc_program)); prog = (qc_program*)mem_a(sizeof(qc_program));
if (!prog) { if (!prog) {
fclose(file); file_close(file);
printf("failed to allocate program data\n"); printf("failed to allocate program data\n");
return NULL; return NULL;
} }
@ -91,15 +90,17 @@ qc_program* prog_load(const char *filename)
} }
#define read_data(hdrvar, progvar, reserved) \ #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"); \ loaderror("seek failed"); \
goto error; \ goto error; \
} \ } \
if (fread(vec_add(prog->progvar, header.hdrvar.length + reserved), \ if (file_read ( \
vec_add(prog->progvar, header.hdrvar.length + reserved), \
sizeof(*prog->progvar), \ sizeof(*prog->progvar), \
header.hdrvar.length, file) \ header.hdrvar.length, \
!= header.hdrvar.length) \ file \
{ \ )!= header.hdrvar.length \
) { \
loaderror("read failed"); \ loaderror("read failed"); \
goto error; \ goto error; \
} }
@ -113,7 +114,7 @@ qc_program* prog_load(const char *filename)
read_data1(strings); read_data1(strings);
read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */ 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 */ /* profile counters */
memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code)); memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code));

215
file.c Normal file
View file

@ -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);
}

View file

@ -991,9 +991,9 @@ static char *ftepp_include_find_path(const char *file, const char *pathfile)
memcpy(vec_add(filename, len+1), file, len); memcpy(vec_add(filename, len+1), file, len);
vec_last(filename) = 0; vec_last(filename) = 0;
fp = util_fopen(filename, "rb"); fp = file_open(filename, "rb");
if (fp) { if (fp) {
fclose(fp); file_close(fp);
return filename; return filename;
} }
vec_free(filename); vec_free(filename);

31
gmqcc.h
View file

@ -26,8 +26,8 @@
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <ctype.h> #include <ctype.h>
/* /*
@ -159,7 +159,6 @@
# define strtof(X, Y) (float)(strtod(X, Y)) # define strtof(X, Y) (float)(strtod(X, Y))
#endif #endif
/* /*
* Very roboust way at determining endianess at compile time: this handles * Very roboust way at determining endianess at compile time: this handles
* almost every possible situation. Otherwise a runtime check has to be * almost every possible situation. Otherwise a runtime check has to be
@ -245,8 +244,6 @@
/*===================================================================*/ /*===================================================================*/
/*=========================== util.c ================================*/ /*=========================== util.c ================================*/
/*===================================================================*/ /*===================================================================*/
FILE *util_fopen(const char *filename, const char *mode);
void *util_memory_a (size_t, unsigned int, const char *); void *util_memory_a (size_t, unsigned int, const char *);
void util_memory_d (void *, unsigned int, const char *); void util_memory_d (void *, unsigned int, const char *);
void *util_memory_r (void *, size_t, 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 *); bool util_strdigit (const char *);
char *util_strdup (const char *); char *util_strdup (const char *);
void util_debug (const char *, const char *, ...); void util_debug (const char *, const char *, ...);
int util_getline (char **, size_t *, FILE *);
void util_endianswap (void *, size_t, unsigned int); void util_endianswap (void *, size_t, unsigned int);
size_t util_strtocmd (const char *, char *, size_t); size_t util_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); 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_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); 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 ================================*/ /*=========================== code.c ================================*/
/*===================================================================*/ /*===================================================================*/
/* TODO: cleanup */
/* Note: if you change the order, fix type_sizeof in ir.c */ /* Note: if you change the order, fix type_sizeof in ir.c */
enum { enum {
TYPE_VOID , TYPE_VOID ,
@ -806,6 +823,7 @@ vector vec3_mulvf(vector, float);
/*============================= exec.c ==============================*/ /*============================= exec.c ==============================*/
/*===================================================================*/ /*===================================================================*/
/* TODO: cleanup */
/* /*
* Darkplaces has (or will have) a 64 bit prog loader * Darkplaces has (or will have) a 64 bit prog loader
* where the 32 bit qc program is autoconverted on load. * 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_compile_string(const char *name, const char *str);
bool parser_finish (const char *output); bool parser_finish (const char *output);
void parser_cleanup (); void parser_cleanup ();
/* TODO: make compile_string accept len and remove this */
/* There's really no need to strlen() preprocessed files */ /* There's really no need to strlen() preprocessed files */
bool parser_compile_string_len(const char *name, const char *str, size_t len); bool parser_compile_string_len(const char *name, const char *str, size_t len);
@ -1015,6 +1035,7 @@ typedef enum {
COMPILER_GMQCC /* this QuakeC */ COMPILER_GMQCC /* this QuakeC */
} opts_std_t; } opts_std_t;
/* TODO: cleanup this */
typedef struct { typedef struct {
uint32_t O; /* -Ox */ uint32_t O; /* -Ox */
const char *output; /* -o file */ const char *output; /* -o file */

View file

@ -186,7 +186,7 @@ static void lex_token_new(lex_file *lex)
lex_file* lex_open(const char *file) lex_file* lex_open(const char *file)
{ {
lex_file *lex; lex_file *lex;
FILE *in = util_fopen(file, "rb"); FILE *in = file_open(file, "rb");
if (!in) { if (!in) {
lexerror(NULL, "open failed: '%s'\n", file); 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)); lex = (lex_file*)mem_a(sizeof(*lex));
if (!lex) { if (!lex) {
fclose(in); file_close(in);
lexerror(NULL, "out of memory\n"); lexerror(NULL, "out of memory\n");
return NULL; return NULL;
} }
@ -260,7 +260,7 @@ void lex_close(lex_file *lex)
vec_free(lex->modelname); vec_free(lex->modelname);
if (lex->file) if (lex->file)
fclose(lex->file); file_close(lex->file);
#if 0 #if 0
if (lex->tok) if (lex->tok)
token_delete(lex->tok); token_delete(lex->tok);

19
main.c
View file

@ -139,8 +139,8 @@ static bool options_parse(int argc, char **argv) {
bool argend = false; bool argend = false;
size_t itr; size_t itr;
char buffer[1024]; char buffer[1024];
char *redirout = (char*)stdout; char *redirout = NULL;
char *redirerr = (char*)stderr; char *redirerr = NULL;
char *config = NULL; char *config = NULL;
while (!argend && argc > 1) { while (!argend && argc > 1) {
@ -474,7 +474,7 @@ static bool progs_nextline(char **out, size_t *alen,FILE *src) {
char *end; char *end;
line = *out; line = *out;
len = util_getline(&line, alen, src); len = file_getline(&line, alen, src);
if (len == -1) if (len == -1)
return false; return false;
@ -553,15 +553,16 @@ int main(int argc, char **argv) {
if (opts.pp_only) { if (opts.pp_only) {
if (opts_output_wasset) { if (opts_output_wasset) {
outfile = util_fopen(opts.output, "wb"); outfile = file_open(opts.output, "wb");
if (!outfile) { if (!outfile) {
con_err("failed to open `%s` for writing\n", opts.output); con_err("failed to open `%s` for writing\n", opts.output);
retval = 1; retval = 1;
goto cleanup; goto cleanup;
} }
} }
else else {
outfile = stdout; /* TODO: stdout without stdout .. */
}
} }
if (!opts.pp_only) { if (!opts.pp_only) {
@ -604,7 +605,7 @@ int main(int argc, char **argv) {
progs_src = true; progs_src = true;
src = util_fopen("progs.src", "rb"); src = file_open("progs.src", "rb");
if (!src) { if (!src) {
con_err("failed to open `progs.src` for reading\n"); con_err("failed to open `progs.src` for reading\n");
retval = 1; retval = 1;
@ -633,7 +634,7 @@ int main(int argc, char **argv) {
} }
srcdone: srcdone:
fclose(src); file_close(src);
mem_d(line); mem_d(line);
} }
@ -663,7 +664,7 @@ srcdone:
} }
out = ftepp_get(); out = ftepp_get();
if (out) if (out)
fprintf(outfile, "%s", out); file_printf(outfile, "%s", out);
ftepp_flush(); ftepp_flush();
} }
else { else {

10
opts.c
View file

@ -169,7 +169,7 @@ static size_t opts_ini_parse (
char *read_name; char *read_name;
char *read_value; char *read_value;
while (util_getline(&line, &linesize, filehandle) != EOF) { while (file_getline(&line, &linesize, filehandle) != EOF) {
parse_beg = line; parse_beg = line;
/* handle BOM */ /* handle BOM */
@ -315,11 +315,11 @@ void opts_ini_init(const char *file) {
if (!file) { if (!file) {
/* try ini */ /* try ini */
if (!(ini = fopen((file = "gmqcc.ini"), "r"))) if (!(ini = file_open((file = "gmqcc.ini"), "r")))
/* try cfg */ /* try cfg */
if (!(ini = fopen((file = "gmqcc.cfg"), "r"))) if (!(ini = file_open((file = "gmqcc.cfg"), "r")))
return; return;
} else if (!(ini = fopen(file, "r"))) } else if (!(ini = file_open(file, "r")))
return; return;
con_out("found ini file `%s`\n", file); con_out("found ini file `%s`\n", file);
@ -330,5 +330,5 @@ void opts_ini_init(const char *file) {
vec_free(error); vec_free(error);
} }
fclose(ini); file_close(ini);
} }

26
test.c
View file

@ -451,7 +451,7 @@ bool task_template_parse(const char *file, task_template_t *template, FILE *fp)
return false; return false;
/* top down parsing */ /* top down parsing */
while (util_getline(&back, &size, fp) != EOF) { while (file_getline(&back, &size, fp) != EOF) {
/* skip whitespace */ /* skip whitespace */
data = back; data = back;
if (*data && (*data == ' ' || *data == '\t')) 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)); memset (fullfile, 0, sizeof(fullfile));
snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file); snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file);
tempfile = fopen(fullfile, "r"); tempfile = file_open(fullfile, "r");
template = mem_a(sizeof(task_template_t)); template = mem_a(sizeof(task_template_t));
task_template_nullify(template); task_template_nullify(template);
@ -667,7 +667,7 @@ task_template_t *task_template_compile(const char *file, const char *dir) {
} }
success: success:
fclose(tempfile); file_close(tempfile);
return template; return template;
failure: failure:
@ -676,7 +676,7 @@ failure:
* so the check to see if it's not null here is required. * so the check to see if it's not null here is required.
*/ */
if (tempfile) if (tempfile)
fclose(tempfile); file_close(tempfile);
mem_d (template); mem_d (template);
return NULL; return NULL;
@ -812,7 +812,7 @@ bool task_propagate(const char *curdir) {
memset (buf,0,sizeof(buf)); memset (buf,0,sizeof(buf));
snprintf(buf, sizeof(buf), "%s.stdout", template->tempfilename); snprintf(buf, sizeof(buf), "%s.stdout", template->tempfilename);
task.stdoutlogfile = util_strdup(buf); 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); con_err("error opening %s for stdout\n", buf);
continue; continue;
} }
@ -820,7 +820,7 @@ bool task_propagate(const char *curdir) {
memset (buf,0,sizeof(buf)); memset (buf,0,sizeof(buf));
snprintf(buf, sizeof(buf), "%s.stderr", template->tempfilename); snprintf(buf, sizeof(buf), "%s.stderr", template->tempfilename);
task.stderrlogfile = util_strdup(buf); 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); con_err("error opening %s for stderr\n", buf);
continue; continue;
} }
@ -904,8 +904,8 @@ void task_destroy(const char *curdir) {
* annoying to have to do all this cleanup work. * annoying to have to do all this cleanup work.
*/ */
if (task_tasks[i].runhandles) task_pclose(task_tasks[i].runhandles); 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].stdoutlog) file_close (task_tasks[i].stdoutlog);
if (task_tasks[i].stderrlog) fclose (task_tasks[i].stderrlog); if (task_tasks[i].stderrlog) file_close (task_tasks[i].stderrlog);
/* /*
* Only remove the log files if the test actually compiled otherwise * 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; char *data = NULL;
size_t size = 0; size_t size = 0;
size_t compare = 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")) { if (!strcmp(data, "No main function found\n")) {
con_err("test failure: `%s` [%s] (No main function found)\n", con_err("test failure: `%s` [%s] (No main function found)\n",
template->description, template->description,
@ -1059,8 +1059,8 @@ void task_schedualize() {
* Read data from stdout first and pipe that stuff into a log file * Read data from stdout first and pipe that stuff into a log file
* then we do the same for stderr. * then we do the same for stderr.
*/ */
while (util_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) { while (file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
fputs(data, task_tasks[i].stdoutlog); file_puts(task_tasks[i].stdoutlog, data);
if (strstr(data, "failed to open file")) { if (strstr(data, "failed to open file")) {
task_tasks[i].compiled = false; task_tasks[i].compiled = false;
@ -1069,7 +1069,7 @@ void task_schedualize() {
fflush(task_tasks[i].stdoutlog); 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 * If a string contains an error we just dissalow execution
* of it in the vm. * of it in the vm.
@ -1083,7 +1083,7 @@ void task_schedualize() {
task_tasks[i].compiled = false; task_tasks[i].compiled = false;
} }
fputs(data, task_tasks[i].stderrlog); file_puts(task_tasks[i].stderrlog, data);
fflush(task_tasks[i].stdoutlog); fflush(task_tasks[i].stdoutlog);
} }

63
util.c
View file

@ -25,6 +25,7 @@
#include <errno.h> #include <errno.h>
#include "gmqcc.h" #include "gmqcc.h"
/* TODO: remove globals ... */
uint64_t mem_ab = 0; uint64_t mem_ab = 0;
uint64_t mem_db = 0; uint64_t mem_db = 0;
uint64_t mem_at = 0; uint64_t mem_at = 0;
@ -347,54 +348,6 @@ uint16_t util_crc16(const char *k, int len, const short clamp) {
} }
#endif #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 util_strtocmd(const char *in, char *out, size_t outsz) {
size_t sz = 1; size_t sz = 1;
for (; *in && sz < outsz; ++in, ++out, ++sz) 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; return sz-1;
} }
/* TODO: rewrite ... when I redo the ve cleanup */
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
}
void _util_vec_grow(void **a, size_t i, size_t s) { void _util_vec_grow(void **a, size_t i, size_t s) {
size_t m = *a ? 2*_vec_beg(*a)+i : i+1; 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); void *p = mem_r((*a ? _vec_raw(*a) : NULL), s * m + sizeof(size_t)*2);