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
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

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

View file

@ -21,6 +21,7 @@
* SOFTWARE.
*/
#include "gmqcc.h"
#include <stdio.h>
/*
* 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);

31
exec.c
View file

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

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

31
gmqcc.h
View file

@ -26,8 +26,8 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
/*
@ -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 */

View file

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

19
main.c
View file

@ -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 {

10
opts.c
View file

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

26
test.c
View file

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

63
util.c
View file

@ -25,6 +25,7 @@
#include <errno.h>
#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);