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
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;
}
vec_free(code_functions);
vec_free(code_globals);
vec_free(code_chars);
- fclose(fp);
+ file_close(fp);
return true;
}
* SOFTWARE.
*/
#include "gmqcc.h"
+#include <stdio.h>
/*
* isatty/STDERR_FILENO/STDOUT_FILNO
state = -1;
}
} else {
- fputc(*str, h);
+ file_putc(*str, h);
length ++;
}
str++;
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;
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) {
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);
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;
}
}
#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; \
}
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));
--- /dev/null
+/*
+ * 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);
+}
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);
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
#include <stdarg.h>
+#include <stdio.h>
#include <ctype.h>
/*
# 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
/*===================================================================*/
/*=========================== 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 *);
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);
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 ,
/*============================= exec.c ==============================*/
/*===================================================================*/
+/* TODO: cleanup */
/*
* Darkplaces has (or will have) a 64 bit prog loader
* where the 32 bit qc program is autoconverted on load.
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);
COMPILER_GMQCC /* this QuakeC */
} opts_std_t;
+/* TODO: cleanup this */
typedef struct {
uint32_t O; /* -Ox */
const char *output; /* -o file */
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);
lex = (lex_file*)mem_a(sizeof(*lex));
if (!lex) {
- fclose(in);
+ file_close(in);
lexerror(NULL, "out of memory\n");
return NULL;
}
vec_free(lex->modelname);
if (lex->file)
- fclose(lex->file);
+ file_close(lex->file);
#if 0
if (lex->tok)
token_delete(lex->tok);
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) {
char *end;
line = *out;
- len = util_getline(&line, alen, src);
+ len = file_getline(&line, alen, src);
if (len == -1)
return false;
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) {
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;
}
srcdone:
- fclose(src);
+ file_close(src);
mem_d(line);
}
}
out = ftepp_get();
if (out)
- fprintf(outfile, "%s", out);
+ file_printf(outfile, "%s", out);
ftepp_flush();
}
else {
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 */
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);
vec_free(error);
}
- fclose(ini);
+ file_close(ini);
}
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'))
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);
}
success:
- fclose(tempfile);
+ file_close(tempfile);
return template;
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;
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;
}
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;
}
* 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
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,
* 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;
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.
task_tasks[i].compiled = false;
}
- fputs(data, task_tasks[i].stderrlog);
+ file_puts(task_tasks[i].stderrlog, data);
fflush(task_tasks[i].stdoutlog);
}
#include <errno.h>
#include "gmqcc.h"
+/* TODO: remove globals ... */
uint64_t mem_ab = 0;
uint64_t mem_db = 0;
uint64_t mem_at = 0;
}
#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)
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);