mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-02-17 17:11:32 +00:00
Merge branch 'cooking' of git://github.com/graphitemaster/gmqcc into cooking
This commit is contained in:
commit
82afdb1e2c
21 changed files with 1304 additions and 847 deletions
27
Makefile
27
Makefile
|
@ -148,21 +148,22 @@ install-doc:
|
|||
|
||||
# DO NOT DELETE
|
||||
|
||||
util.o: gmqcc.h opts.def
|
||||
fs.o: gmqcc.h opts.def
|
||||
conout.o: gmqcc.h opts.def
|
||||
opts.o: gmqcc.h opts.def
|
||||
pak.o: gmqcc.h opts.def
|
||||
pak.o: gmqcc.h opts.def platform.h
|
||||
ansi.o: platform.h gmqcc.h opts.def
|
||||
util.o: gmqcc.h opts.def platform.h
|
||||
stat.o: gmqcc.h opts.def
|
||||
test.o: gmqcc.h opts.def
|
||||
fs.o: gmqcc.h opts.def platform.h
|
||||
conout.o: gmqcc.h opts.def platform.h
|
||||
opts.o: gmqcc.h opts.def platform.h
|
||||
test.o: gmqcc.h opts.def platform.h
|
||||
main.o: gmqcc.h opts.def lexer.h
|
||||
lexer.o: gmqcc.h opts.def lexer.h
|
||||
parser.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h
|
||||
lexer.o: gmqcc.h opts.def lexer.h platform.h
|
||||
parser.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h platform.h
|
||||
code.o: gmqcc.h opts.def
|
||||
ast.o: gmqcc.h opts.def ast.h ir.h parser.h lexer.h
|
||||
ir.o: gmqcc.h opts.def ir.h
|
||||
ftepp.o: gmqcc.h opts.def lexer.h
|
||||
ast.o: gmqcc.h opts.def ast.h ir.h parser.h lexer.h platform.h
|
||||
ir.o: gmqcc.h opts.def ir.h platform.h
|
||||
ftepp.o: gmqcc.h opts.def lexer.h platform.h
|
||||
utf8.o: gmqcc.h opts.def
|
||||
correct.o: gmqcc.h opts.def
|
||||
fold.o: ast.h ir.h gmqcc.h opts.def parser.h lexer.h
|
||||
intrin.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h
|
||||
fold.o: ast.h ir.h gmqcc.h opts.def parser.h lexer.h platform.h
|
||||
intrin.o: parser.h gmqcc.h opts.def lexer.h ast.h ir.h platform.h
|
||||
|
|
4
PORTING
Normal file
4
PORTING
Normal file
|
@ -0,0 +1,4 @@
|
|||
Porting gmqcc to a new platform is farily trivial, in most cases ansi.c
|
||||
will be sufficent enough to get it to run on your favorite platform. If
|
||||
however it isn't you can duplicate ansi.c and change it accordingly.
|
||||
Changes to platform.h may also be required.
|
169
ansi.c
Normal file
169
ansi.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (C) 2012, 2013
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#define GMQCC_PLATFORM_HEADER
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "gmqcc.h"
|
||||
|
||||
int platform_vsnprintf(char *buffer, size_t bytes, const char *format, va_list arg) {
|
||||
return vsnprintf(buffer, bytes, format, arg);
|
||||
}
|
||||
|
||||
int platform_vsscanf(const char *str, const char *format, va_list arg) {
|
||||
return vsscanf(str, format, arg);
|
||||
}
|
||||
|
||||
const struct tm *platform_localtime(const time_t *timer) {
|
||||
return localtime(timer);
|
||||
}
|
||||
|
||||
const char *platform_ctime(const time_t *timer) {
|
||||
return ctime(timer);
|
||||
}
|
||||
|
||||
char *platform_strncat(char *dest, const char *src, size_t num) {
|
||||
return strncat(dest, src, num);
|
||||
}
|
||||
|
||||
const char *platform_tmpnam(char *str) {
|
||||
return tmpnam(str);
|
||||
}
|
||||
|
||||
const char *platform_getenv(char *var) {
|
||||
return getenv(var);
|
||||
}
|
||||
|
||||
int platform_vasprintf(char **dat, const char *fmt, va_list args) {
|
||||
int ret;
|
||||
int len;
|
||||
char *tmp = NULL;
|
||||
char buf[128];
|
||||
va_list cpy;
|
||||
|
||||
va_copy(cpy, args);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, cpy);
|
||||
va_end (cpy);
|
||||
|
||||
if (len < (int)sizeof(buf)) {
|
||||
*dat = util_strdup(buf);
|
||||
return len;
|
||||
}
|
||||
|
||||
tmp = (char*)mem_a(len + 1);
|
||||
if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
|
||||
mem_d(tmp);
|
||||
*dat = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dat = tmp;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *platform_strcat(char *dest, const char *src) {
|
||||
return strcat(dest, src);
|
||||
}
|
||||
|
||||
char *platform_strncpy(char *dest, const char *src, size_t num) {
|
||||
return strncpy(dest, src, num);
|
||||
}
|
||||
|
||||
const char *platform_strerror(int err) {
|
||||
return strerror(err);
|
||||
}
|
||||
|
||||
FILE *platform_fopen(const char *filename, const char *mode) {
|
||||
return fopen(filename, mode);
|
||||
}
|
||||
|
||||
size_t platform_fread(void *ptr, size_t size, size_t count, FILE *stream) {
|
||||
return fread(ptr, size, count, stream);
|
||||
}
|
||||
|
||||
size_t platform_fwrite(const void *ptr, size_t size, size_t count, FILE *stream) {
|
||||
return fwrite(ptr, size, count, stream);
|
||||
}
|
||||
|
||||
int platform_fflush(FILE *stream) {
|
||||
return fflush(stream);
|
||||
}
|
||||
|
||||
int platform_vfprintf(FILE *stream, const char *format, va_list arg) {
|
||||
return vfprintf(stream, format, arg);
|
||||
}
|
||||
|
||||
int platform_fclose(FILE *stream) {
|
||||
return fclose(stream);
|
||||
}
|
||||
|
||||
int platform_ferror(FILE *stream) {
|
||||
return ferror(stream);
|
||||
}
|
||||
|
||||
int platform_fgetc(FILE *stream) {
|
||||
return fgetc(stream);
|
||||
}
|
||||
|
||||
int platform_fputs(const char *str, FILE *stream) {
|
||||
return fputs(str, stream);
|
||||
}
|
||||
|
||||
int platform_fseek(FILE *stream, long offset, int origin) {
|
||||
return fseek(stream, offset, origin);
|
||||
}
|
||||
|
||||
long platform_ftell(FILE *stream) {
|
||||
return ftell(stream);
|
||||
}
|
||||
|
||||
int platform_mkdir(const char *path, int mode) {
|
||||
/*
|
||||
* For some reason mingw32 just doesn't have a correct mkdir impl
|
||||
* so we handle that here.
|
||||
*/
|
||||
# ifdef _WIN32
|
||||
(void)mode;
|
||||
return mkdir(path);
|
||||
# else
|
||||
return mkdir(path, mode);
|
||||
# endif /*!_WIN32*/
|
||||
}
|
||||
|
||||
DIR *platform_opendir(const char *path) {
|
||||
return opendir(path);
|
||||
}
|
||||
|
||||
int platform_closedir(DIR *dir) {
|
||||
return closedir(dir);
|
||||
}
|
||||
|
||||
struct dirent *platform_readdir(DIR *dir) {
|
||||
return readdir(dir);
|
||||
}
|
||||
|
||||
int platform_isatty(int fd) {
|
||||
return isatty(fd);
|
||||
}
|
2
code.c
2
code.c
|
@ -401,7 +401,7 @@ static bool code_write_memory(code_t *code, uint8_t **datmem, size_t *sizedat, u
|
|||
|
||||
bool code_write(code_t *code, const char *filename, const char *lnofile) {
|
||||
prog_header_t code_header;
|
||||
FILE *fp = NULL;
|
||||
fs_file_t *fp = NULL;
|
||||
|
||||
code_create_header(code, &code_header, filename, lnofile);
|
||||
|
||||
|
|
215
conout.c
215
conout.c
|
@ -20,168 +20,20 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "gmqcc.h"
|
||||
|
||||
/*
|
||||
* isatty/STDERR_FILENO/STDOUT_FILNO
|
||||
* + some other things likewise.
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <io.h>
|
||||
/*
|
||||
* Windows and it's posix underscore bullshit. We simply fix this
|
||||
* with yay, another macro :P
|
||||
*/
|
||||
# define isatty _isatty
|
||||
#endif
|
||||
|
||||
#define GMQCC_IS_STDOUT(X) ((FILE*)((void*)X) == stdout)
|
||||
#define GMQCC_IS_STDERR(X) ((FILE*)((void*)X) == stderr)
|
||||
#define GMQCC_IS_STDOUT(X) ((fs_file_t*)((void*)X) == (fs_file_t*)stdout)
|
||||
#define GMQCC_IS_STDERR(X) ((fs_file_t*)((void*)X) == (fs_file_t*)stderr)
|
||||
#define GMQCC_IS_DEFINE(X) (GMQCC_IS_STDERR(X) || GMQCC_IS_STDOUT(X))
|
||||
|
||||
typedef struct {
|
||||
FILE *handle_err;
|
||||
FILE *handle_out;
|
||||
|
||||
int color_err;
|
||||
int color_out;
|
||||
fs_file_t *handle_err;
|
||||
fs_file_t *handle_out;
|
||||
int color_err;
|
||||
int color_out;
|
||||
} con_t;
|
||||
|
||||
/*
|
||||
* Doing colored output on windows is fucking stupid. The linux way is
|
||||
* the real way. So we emulate it on windows :)
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
* Windows doesn't have constants for FILENO, sadly but the docs tell
|
||||
* use the constant values.
|
||||
*/
|
||||
#undef STDERR_FILENO
|
||||
#undef STDOUT_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#define STDOUT_FILENO 1
|
||||
|
||||
enum {
|
||||
RESET = 0,
|
||||
BOLD = 1,
|
||||
BLACK = 30,
|
||||
RED,
|
||||
GREEN,
|
||||
YELLOW,
|
||||
BLUE,
|
||||
MAGENTA,
|
||||
CYAN,
|
||||
GRAY,
|
||||
WHITE = GRAY
|
||||
};
|
||||
|
||||
enum {
|
||||
WBLACK,
|
||||
WBLUE,
|
||||
WGREEN = 2,
|
||||
WRED = 4,
|
||||
WINTENSE = 8,
|
||||
WCYAN = WBLUE | WGREEN,
|
||||
WMAGENTA = WBLUE | WRED,
|
||||
WYELLOW = WGREEN | WRED,
|
||||
WWHITE = WBLUE | WGREEN | WRED
|
||||
};
|
||||
|
||||
static const int ansi2win[] = {
|
||||
WBLACK,
|
||||
WRED,
|
||||
WGREEN,
|
||||
WYELLOW,
|
||||
WBLUE,
|
||||
WMAGENTA,
|
||||
WCYAN,
|
||||
WWHITE
|
||||
};
|
||||
|
||||
static int win_fputs(FILE *h, const char *str) {
|
||||
/* state for translate */
|
||||
int acolor = 0;
|
||||
int wcolor = 0;
|
||||
int icolor = 0;
|
||||
int state = 0;
|
||||
|
||||
/* attributes */
|
||||
int intense = -1;
|
||||
int colors[] = {-1, -1 };
|
||||
int colorpos = 1;
|
||||
int length = 0;
|
||||
CONSOLE_SCREEN_BUFFER_INFO cinfo;
|
||||
GetConsoleScreenBufferInfo (
|
||||
(GMQCC_IS_STDOUT(h)) ?
|
||||
GetStdHandle(STD_OUTPUT_HANDLE) :
|
||||
GetStdHandle(STD_ERROR_HANDLE), &cinfo
|
||||
);
|
||||
icolor = cinfo.wAttributes;
|
||||
|
||||
while (*str) {
|
||||
if (*str == '\x1B')
|
||||
state = '\x1B';
|
||||
else if (state == '\x1B' && *str == '[')
|
||||
state = '[';
|
||||
else if (state == '[') {
|
||||
if (*str != 'm') {
|
||||
colors[colorpos] = *str;
|
||||
colorpos--;
|
||||
} else {
|
||||
int find;
|
||||
int mult;
|
||||
for (find = colorpos + 1, acolor = 0, mult = 1; find < 2; find++) {
|
||||
acolor += (colors[find] - 48) * mult;
|
||||
mult *= 10;
|
||||
}
|
||||
|
||||
/* convert to windows color */
|
||||
if (acolor == BOLD)
|
||||
intense = WINTENSE;
|
||||
else if (acolor == RESET) {
|
||||
intense = WBLACK;
|
||||
wcolor = icolor;
|
||||
}
|
||||
else if (BLACK <= acolor && acolor <= WHITE)
|
||||
wcolor = ansi2win[acolor - 30];
|
||||
else if (acolor == 90) {
|
||||
/* special gray really white man */
|
||||
wcolor = WWHITE;
|
||||
intense = WBLACK;
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute (
|
||||
(GMQCC_IS_STDOUT(h)) ?
|
||||
GetStdHandle(STD_OUTPUT_HANDLE) :
|
||||
GetStdHandle(STD_ERROR_HANDLE),
|
||||
|
||||
wcolor | intense | (icolor & 0xF0)
|
||||
);
|
||||
colorpos = 1;
|
||||
state = -1;
|
||||
}
|
||||
} else {
|
||||
fs_file_write(str, 1, 1, stdout);
|
||||
length ++;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
/* restore */
|
||||
SetConsoleTextAttribute(
|
||||
(GMQCC_IS_STDOUT(h)) ?
|
||||
GetStdHandle(STD_OUTPUT_HANDLE) :
|
||||
GetStdHandle(STD_ERROR_HANDLE),
|
||||
icolor
|
||||
);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We use standard files as default. These can be changed at any time
|
||||
* with con_change(F, F)
|
||||
|
@ -197,10 +49,8 @@ static con_t console;
|
|||
* checks.
|
||||
*/
|
||||
static void con_enablecolor(void) {
|
||||
if (console.handle_err == stderr || console.handle_err == stdout)
|
||||
console.color_err = !!(isatty(STDERR_FILENO));
|
||||
if (console.handle_out == stderr || console.handle_out == stdout)
|
||||
console.color_out = !!(isatty(STDOUT_FILENO));
|
||||
console.color_err = util_isatty(console.handle_err);
|
||||
console.color_out = util_isatty(console.handle_out);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -208,23 +58,8 @@ static void con_enablecolor(void) {
|
|||
* arguments. This colorizes for windows as well via translate
|
||||
* step.
|
||||
*/
|
||||
static int con_write(FILE *handle, const char *fmt, va_list va) {
|
||||
int ln;
|
||||
#ifndef _WIN32
|
||||
ln = vfprintf(handle, fmt, va);
|
||||
#else
|
||||
{
|
||||
char data[4096];
|
||||
memset(data, 0, sizeof(data));
|
||||
#ifdef _MSC_VER
|
||||
vsnprintf_s(data, sizeof(data), sizeof(data), fmt, va);
|
||||
#else
|
||||
vsnprintf(data, sizeof(data), fmt, va);
|
||||
#endif
|
||||
ln = (GMQCC_IS_DEFINE(handle)) ? win_fputs(handle, data) : fs_file_puts(handle, data);
|
||||
}
|
||||
#endif
|
||||
return ln;
|
||||
static int con_write(fs_file_t *handle, const char *fmt, va_list va) {
|
||||
return vfprintf((FILE*)handle, fmt, va);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -248,8 +83,8 @@ void con_color(int state) {
|
|||
}
|
||||
|
||||
void con_init() {
|
||||
console.handle_err = stderr;
|
||||
console.handle_out = stdout;
|
||||
console.handle_err = (fs_file_t*)stderr;
|
||||
console.handle_out = (fs_file_t*)stdout;
|
||||
con_enablecolor();
|
||||
}
|
||||
|
||||
|
@ -271,16 +106,16 @@ 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 (!out) out = (const char *)((!console.handle_out) ? (fs_file_t*)stdout : console.handle_out);
|
||||
if (!err) err = (const char *)((!console.handle_err) ? (fs_file_t*)stderr : console.handle_err);
|
||||
|
||||
if (GMQCC_IS_DEFINE(out)) {
|
||||
console.handle_out = GMQCC_IS_STDOUT(out) ? stdout : stderr;
|
||||
console.handle_out = (fs_file_t*)(GMQCC_IS_STDOUT(out) ? stdout : stderr);
|
||||
con_enablecolor();
|
||||
} else if (!(console.handle_out = fs_file_open(out, "w"))) return 0;
|
||||
|
||||
if (GMQCC_IS_DEFINE(err)) {
|
||||
console.handle_err = GMQCC_IS_STDOUT(err) ? stdout : stderr;
|
||||
console.handle_err = (fs_file_t*)(GMQCC_IS_STDOUT(err) ? stdout : stderr);
|
||||
con_enablecolor();
|
||||
} else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
|
||||
|
||||
|
@ -291,11 +126,11 @@ int con_change(const char *out, const char *err) {
|
|||
* Defaultizer because stdio.h shouldn't be used anywhere except here
|
||||
* and inside file.c To prevent mis-match of wrapper-interfaces.
|
||||
*/
|
||||
FILE *con_default_out() {
|
||||
return (console.handle_out = stdout);
|
||||
fs_file_t *con_default_out() {
|
||||
return (fs_file_t*)(console.handle_out = (fs_file_t*)stdout);
|
||||
}
|
||||
FILE *con_default_err() {
|
||||
return (console.handle_err = stderr);
|
||||
fs_file_t *con_default_err() {
|
||||
return (fs_file_t*)(console.handle_err = (fs_file_t*)stderr);
|
||||
}
|
||||
|
||||
int con_verr(const char *fmt, va_list va) {
|
||||
|
@ -339,10 +174,10 @@ static void con_vprintmsg_c(int level, const char *name, size_t line, size_t col
|
|||
CON_RED
|
||||
};
|
||||
|
||||
int err = !!(level == LVL_ERROR);
|
||||
int color = (err) ? console.color_err : console.color_out;
|
||||
int (*print) (const char *, ...) = (err) ? &con_err : &con_out;
|
||||
int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout;
|
||||
int err = !!(level == LVL_ERROR);
|
||||
int color = (err) ? console.color_err : console.color_out;
|
||||
int (*print) (const char *, ...) = (err) ? &con_err : &con_out;
|
||||
int (*vprint)(const char *, va_list) = (err) ? &con_verr : &con_vout;
|
||||
|
||||
if (color)
|
||||
print("\033[0;%dm%s:%d:%d: \033[0;%dm%s: \033[0m", CON_CYAN, name, (int)line, (int)column, sel[level], msgtype);
|
||||
|
|
30
exec.c
30
exec.c
|
@ -23,10 +23,9 @@
|
|||
*/
|
||||
#ifndef QCVM_LOOP
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
|
||||
|
@ -54,9 +53,9 @@ static void qcvmerror(qc_program_t *prog, const char *fmt, ...)
|
|||
|
||||
qc_program_t* prog_load(const char *filename, bool skipversion)
|
||||
{
|
||||
qc_program_t *prog;
|
||||
prog_header_t header;
|
||||
FILE *file = fs_file_open(filename, "rb");
|
||||
qc_program_t *prog;
|
||||
fs_file_t *file = fs_file_open(filename, "rb");
|
||||
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
@ -91,11 +90,11 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
|
|||
}
|
||||
|
||||
#define read_data(hdrvar, progvar, reserved) \
|
||||
if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
|
||||
if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
|
||||
loaderror("seek failed"); \
|
||||
goto error; \
|
||||
} \
|
||||
if (fs_file_read ( \
|
||||
if (fs_file_read ( \
|
||||
vec_add(prog->progvar, header.hdrvar.length + reserved), \
|
||||
sizeof(*prog->progvar), \
|
||||
header.hdrvar.length, \
|
||||
|
@ -352,7 +351,7 @@ static void trace_print_global(qc_program_t *prog, unsigned int glob, int vtype)
|
|||
done:
|
||||
if (len < (int)sizeof(spaces)-1) {
|
||||
spaces[sizeof(spaces)-1-len] = 0;
|
||||
fs_file_puts(stdout, spaces);
|
||||
fs_file_puts((fs_file_t*)stdout, spaces);
|
||||
spaces[sizeof(spaces)-1-len] = ' ';
|
||||
}
|
||||
}
|
||||
|
@ -877,17 +876,10 @@ static void prog_main_setparams(qc_program_t *prog) {
|
|||
arg->vector[2] = 0;
|
||||
switch (main_params[i].vtype) {
|
||||
case TYPE_VECTOR:
|
||||
#ifdef _MSC_VER
|
||||
(void)sscanf_s(main_params[i].value, " %f %f %f ",
|
||||
&arg->vector[0],
|
||||
&arg->vector[1],
|
||||
&arg->vector[2]);
|
||||
#else
|
||||
(void)sscanf(main_params[i].value, " %f %f %f ",
|
||||
&arg->vector[0],
|
||||
&arg->vector[1],
|
||||
&arg->vector[2]);
|
||||
#endif
|
||||
(void)util_sscanf(main_params[i].value, " %f %f %f ",
|
||||
&arg->vector[0],
|
||||
&arg->vector[1],
|
||||
&arg->vector[2]);
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
arg->_float = atof(main_params[i].value);
|
||||
|
|
264
fs.c
264
fs.c
|
@ -20,162 +20,76 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#define GMQCC_PLATFORM_HEADER
|
||||
#include "gmqcc.h"
|
||||
#include "platform.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
|
||||
#include <crtdbg.h> /* _CrtSetReportMode, _CRT_ASSERT */
|
||||
/* {{{ */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
fs_file_t *fs_file_open(const char *filename, const char *mode) {
|
||||
return (fs_file_t*)platform_fopen(filename, mode);
|
||||
}
|
||||
|
||||
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");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
size_t fs_file_read(void *buffer, size_t size, size_t count, fs_file_t *fp) {
|
||||
return platform_fread(buffer, size, count, (FILE*)fp);
|
||||
}
|
||||
|
||||
static void file_init() {
|
||||
static bool init = false;
|
||||
int fs_file_printf(fs_file_t *fp, const char *format, ...) {
|
||||
int rt;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
rt = platform_vfprintf((FILE*)fp, format, va);
|
||||
va_end (va);
|
||||
|
||||
if (init)
|
||||
return;
|
||||
return rt;
|
||||
}
|
||||
|
||||
_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 *fs_file_open(const char *filename, const char *mode) {
|
||||
FILE *handle = NULL;
|
||||
file_init();
|
||||
|
||||
return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
|
||||
}
|
||||
|
||||
size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
|
||||
file_init();
|
||||
return fread_s(buffer, size*count, size, count, fp);
|
||||
}
|
||||
|
||||
int fs_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 *fs_file_open(const char *filename, const char *mode) {
|
||||
return fopen(filename, mode);
|
||||
}
|
||||
|
||||
size_t fs_file_read(void *buffer, size_t size, size_t count, FILE *fp) {
|
||||
return fread(buffer, size, count, fp);
|
||||
}
|
||||
|
||||
int fs_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 fs_file_close(FILE *fp) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
fclose (fp);
|
||||
void fs_file_close(fs_file_t *fp) {
|
||||
platform_fclose((FILE*)fp);
|
||||
}
|
||||
|
||||
size_t fs_file_write (
|
||||
const void *buffer,
|
||||
size_t size,
|
||||
size_t count,
|
||||
FILE *fp
|
||||
fs_file_t *fp
|
||||
) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return fwrite(buffer, size, count, fp);
|
||||
return platform_fwrite(buffer, size, count, (FILE*)fp);
|
||||
}
|
||||
|
||||
int fs_file_error(FILE *fp) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return ferror(fp);
|
||||
int fs_file_error(fs_file_t *fp) {
|
||||
return platform_ferror((FILE*)fp);
|
||||
}
|
||||
|
||||
int fs_file_getc(FILE *fp) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return fgetc(fp);
|
||||
int fs_file_getc(fs_file_t *fp) {
|
||||
int get = platform_fgetc((FILE*)fp);
|
||||
return (get == EOF) ? FS_FILE_EOF : get;
|
||||
}
|
||||
|
||||
int fs_file_puts(FILE *fp, const char *str) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return fputs(str, fp);
|
||||
int fs_file_puts(fs_file_t *fp, const char *str) {
|
||||
return platform_fputs(str, (FILE*)fp);
|
||||
}
|
||||
|
||||
int fs_file_seek(FILE *fp, long int off, int whence) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return fseek(fp, off, whence);
|
||||
int fs_file_seek(fs_file_t *fp, long int off, int whence) {
|
||||
switch(whence) {
|
||||
case FS_FILE_SEEK_CUR: whence = SEEK_CUR; break;
|
||||
case FS_FILE_SEEK_SET: whence = SEEK_SET; break;
|
||||
case FS_FILE_SEEK_END: whence = SEEK_END; break;
|
||||
}
|
||||
return platform_fseek((FILE*)fp, off, whence);
|
||||
}
|
||||
|
||||
long int fs_file_tell(FILE *fp) {
|
||||
/* Invokes file_exception on windows if fp is null */
|
||||
return ftell(fp);
|
||||
long int fs_file_tell(fs_file_t *fp) {
|
||||
return platform_ftell((FILE*)fp);
|
||||
}
|
||||
|
||||
int fs_file_flush(fs_file_t *fp) {
|
||||
return platform_fflush((FILE*)fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements libc getline for systems that don't have it, which is
|
||||
* assmed all. This works the same as getline().
|
||||
*/
|
||||
int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
int fs_file_getline(char **lineptr, size_t *n, fs_file_t *stream) {
|
||||
int chr;
|
||||
int ret;
|
||||
char *pos;
|
||||
|
@ -201,7 +115,7 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
|||
pos = *n - chr + *lineptr;
|
||||
}
|
||||
|
||||
if (ferror(stream))
|
||||
if (fs_file_error(stream))
|
||||
return -1;
|
||||
if (c == EOF) {
|
||||
if (pos == *lineptr)
|
||||
|
@ -219,94 +133,18 @@ int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
|||
return (ret = pos - *lineptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we implement some directory functionality. Windows lacks dirent.h
|
||||
* this is such a pisss off, we implement it here.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
DIR *fs_dir_open(const char *name) {
|
||||
DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(name));
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
util_strncpy(dir->dd_name, name, strlen(name));
|
||||
return dir;
|
||||
}
|
||||
|
||||
int fs_dir_close(DIR *dir) {
|
||||
FindClose((HANDLE)dir->dd_handle);
|
||||
mem_d ((void*)dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dirent *fs_dir_read(DIR *dir) {
|
||||
WIN32_FIND_DATA info;
|
||||
struct dirent *data;
|
||||
int rets;
|
||||
|
||||
if (!dir->dd_handle) {
|
||||
char *dirname;
|
||||
if (*dir->dd_name) {
|
||||
size_t n = strlen(dir->dd_name);
|
||||
if ((dirname = (char*)mem_a(n + 5) /* 4 + 1 */)) {
|
||||
util_strncpy(dirname, dir->dd_name, n);
|
||||
util_strncpy(dirname + n, "\\*.*", 4); /* 4 + 1 */
|
||||
}
|
||||
} else {
|
||||
if (!(dirname = util_strdup("\\*.*")))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir->dd_handle = (long)FindFirstFile(dirname, &info);
|
||||
mem_d(dirname);
|
||||
rets = !(!dir->dd_handle);
|
||||
} else if (dir->dd_handle != -11) {
|
||||
rets = FindNextFile ((HANDLE)dir->dd_handle, &info);
|
||||
} else {
|
||||
rets = 0;
|
||||
}
|
||||
|
||||
if (!rets)
|
||||
return NULL;
|
||||
|
||||
if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
|
||||
util_strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
|
||||
data->d_name[FILENAME_MAX - 1] = '\0'; /* terminate */
|
||||
data->d_namlen = strlen(data->d_name);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int fs_dir_change(const char *path) {
|
||||
return !SetCurrentDirectory(path);
|
||||
}
|
||||
|
||||
int fs_dir_make(const char *path) {
|
||||
return !CreateDirectory(path, NULL);
|
||||
}
|
||||
#else
|
||||
# if !defined(__MINGW32__)
|
||||
# include <sys/stat.h> /* mkdir */
|
||||
|
||||
int fs_dir_make(const char *path) {
|
||||
return mkdir(path, 0700);
|
||||
}
|
||||
# else
|
||||
int fs_dir_make(const char *path) {
|
||||
return mkdir(path);
|
||||
}
|
||||
# endif /*! !defined(__MINGW32__) */
|
||||
|
||||
DIR *fs_dir_open(const char *name) {
|
||||
return opendir(name);
|
||||
int fs_dir_make(const char *path) {
|
||||
return platform_mkdir(path, 0700);
|
||||
}
|
||||
|
||||
int fs_dir_close(DIR *dir) {
|
||||
return closedir(dir);
|
||||
fs_dir_t *fs_dir_open(const char *name) {
|
||||
return (fs_dir_t*)platform_opendir(name);
|
||||
}
|
||||
|
||||
struct dirent *fs_dir_read(DIR *dir) {
|
||||
return readdir(dir);
|
||||
int fs_dir_close(fs_dir_t *dir) {
|
||||
return platform_closedir((DIR*)dir);
|
||||
}
|
||||
|
||||
#endif /*! defined(_WIN32) && !defined(__MINGW32__) */
|
||||
fs_dirent_t *fs_dir_read(fs_dir_t *dir) {
|
||||
return (fs_dirent_t*)platform_readdir((DIR*)dir);
|
||||
}
|
||||
|
|
56
ftepp.c
56
ftepp.c
|
@ -21,15 +21,16 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
#include "lexer.h"
|
||||
|
||||
#define HT_MACROS 1024
|
||||
|
||||
typedef struct {
|
||||
bool on;
|
||||
bool was_on;
|
||||
|
@ -85,22 +86,14 @@ static uint32_t ftepp_predef_randval = 0;
|
|||
|
||||
/* __DATE__ */
|
||||
static char *ftepp_predef_date(lex_file *context) {
|
||||
struct tm *itime = NULL;
|
||||
time_t rtime;
|
||||
char *value = (char*)mem_a(82);
|
||||
/* 82 is enough for strftime but we also have " " in our string */
|
||||
const struct tm *itime = NULL;
|
||||
char *value = (char*)mem_a(82);
|
||||
time_t rtime;
|
||||
|
||||
(void)context;
|
||||
|
||||
/* get time */
|
||||
time (&rtime);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
localtime_s(itime, &rtime);
|
||||
#else
|
||||
itime = localtime(&rtime);
|
||||
#endif
|
||||
|
||||
itime = util_localtime(&rtime);
|
||||
strftime(value, 82, "\"%b %d %Y\"", itime);
|
||||
|
||||
return value;
|
||||
|
@ -108,22 +101,14 @@ static char *ftepp_predef_date(lex_file *context) {
|
|||
|
||||
/* __TIME__ */
|
||||
static char *ftepp_predef_time(lex_file *context) {
|
||||
struct tm *itime = NULL;
|
||||
time_t rtime;
|
||||
char *value = (char*)mem_a(82);
|
||||
/* 82 is enough for strftime but we also have " " in our string */
|
||||
const struct tm *itime = NULL;
|
||||
char *value = (char*)mem_a(82);
|
||||
time_t rtime;
|
||||
|
||||
(void)context;
|
||||
|
||||
/* get time */
|
||||
time (&rtime);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
localtime_s(itime, &rtime);
|
||||
#else
|
||||
itime = localtime(&rtime);
|
||||
#endif
|
||||
|
||||
itime = util_localtime(&rtime);
|
||||
strftime(value, 82, "\"%X\"", itime);
|
||||
|
||||
return value;
|
||||
|
@ -180,27 +165,14 @@ static char *ftepp_predef_randomlast(lex_file *context) {
|
|||
/* __TIMESTAMP__ */
|
||||
static char *ftepp_predef_timestamp(lex_file *context) {
|
||||
struct stat finfo;
|
||||
char *find;
|
||||
const char *find;
|
||||
char *value;
|
||||
size_t size;
|
||||
#ifdef _MSC_VER
|
||||
char buffer[64];
|
||||
#endif
|
||||
|
||||
if (stat(context->name, &finfo))
|
||||
return util_strdup("\"<failed to determine timestamp>\"");
|
||||
|
||||
/*
|
||||
* ctime and its fucking annoying newline char, no worries, we're
|
||||
* professionals here.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_VER
|
||||
find = ctime(&finfo.st_mtime);
|
||||
#else
|
||||
ctime_s(buffer, sizeof(buffer), &finfo.st_mtime);
|
||||
find = buffer;
|
||||
#endif
|
||||
|
||||
find = util_ctime(&finfo.st_mtime);
|
||||
value = (char*)mem_a(strlen(find) + 1);
|
||||
memcpy(&value[1], find, (size = strlen(find)) - 1);
|
||||
|
||||
|
@ -1303,7 +1275,7 @@ static void unescape(const char *str, char *out) {
|
|||
|
||||
static char *ftepp_include_find_path(const char *file, const char *pathfile)
|
||||
{
|
||||
FILE *fp;
|
||||
fs_file_t *fp;
|
||||
char *filename = NULL;
|
||||
const char *last_slash;
|
||||
size_t len;
|
||||
|
|
183
gmqcc.h
183
gmqcc.h
|
@ -24,7 +24,8 @@
|
|||
#ifndef GMQCC_HDR
|
||||
#define GMQCC_HDR
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h> /* TODO: remove this */
|
||||
#include <stddef.h>
|
||||
#include <time.h> /* TODO: remove?*/
|
||||
|
||||
/*
|
||||
* Disable some over protective warnings in visual studio because fixing them is a waste
|
||||
|
@ -252,46 +253,7 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \
|
|||
# endif
|
||||
#endif /*! !defined (PLATFORM_BYTE_ORDER) */
|
||||
|
||||
/*
|
||||
* On windows systems where we're not compiling with MING32 we need a
|
||||
* little extra help on dependinces for implementing our own dirent.h
|
||||
* in fs.c.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
# define _WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
|
||||
struct dirent {
|
||||
long d_ino;
|
||||
unsigned short d_reclen;
|
||||
unsigned short d_namlen;
|
||||
char d_name[FILENAME_MAX];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct _finddata_t dd_dta;
|
||||
struct dirent dd_dir;
|
||||
long dd_handle;
|
||||
int dd_stat;
|
||||
char dd_name[1];
|
||||
} DIR;
|
||||
/*
|
||||
* Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well
|
||||
* which is not hard at all.
|
||||
*/
|
||||
# ifdef S_ISDIR
|
||||
# undef S_ISDIR
|
||||
# endif /*! S_ISDIR */
|
||||
# define S_ISDIR(X) ((X)&_S_IFDIR)
|
||||
#else
|
||||
# include <dirent.h>
|
||||
#endif /*! _WIN32 && !defined(__MINGW32__) */
|
||||
|
||||
/*===================================================================*/
|
||||
/*=========================== stat.c ================================*/
|
||||
/*===================================================================*/
|
||||
/* stat.c */
|
||||
void stat_info (void);
|
||||
char *stat_mem_strdup (const char *, size_t, const char *, bool);
|
||||
void *stat_mem_reallocate(void *, size_t, size_t, const char *);
|
||||
|
@ -307,9 +269,7 @@ void *stat_mem_allocate (size_t, size_t, const char *);
|
|||
#define util_strdup(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false)
|
||||
#define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true)
|
||||
|
||||
/*===================================================================*/
|
||||
/*=========================== util.c ================================*/
|
||||
/*===================================================================*/
|
||||
/* util.c */
|
||||
|
||||
/*
|
||||
* Microsoft implements against the spec versions of ctype.h. Which
|
||||
|
@ -329,10 +289,9 @@ void *stat_mem_allocate (size_t, size_t, const char *);
|
|||
#define util_isprint(a) (((unsigned)(a)-0x20) < 0x5F)
|
||||
#define util_isspace(a) (((a) >= 9 && (a) <= 13) || (a) == ' ')
|
||||
|
||||
bool util_filexists (const char *);
|
||||
bool util_strupper (const char *);
|
||||
bool util_strdigit (const char *);
|
||||
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_strtononcmd (const char *, char *, size_t);
|
||||
|
@ -343,18 +302,18 @@ uint16_t util_crc16(uint16_t crc, const char *data, size_t len);
|
|||
void util_seed(uint32_t);
|
||||
uint32_t util_rand(void);
|
||||
|
||||
/*
|
||||
* String functions (formatting, copying, concatenating, errors). These are wrapped
|
||||
* to use the MSVC _safe_ versions when using MSVC, plus some implementations of
|
||||
* these are non-conformant or don't exist such as asprintf and snprintf, which are
|
||||
* not supported in C90, but do exist in C99.
|
||||
*/
|
||||
int util_vasprintf(char **ret, const char *fmt, va_list);
|
||||
int util_asprintf (char **ret, const char *fmt, ...);
|
||||
int util_snprintf (char *src, size_t bytes, const char *format, ...);
|
||||
char *util_strcat (char *dest, const char *src);
|
||||
char *util_strncpy (char *dest, const char *src, size_t num);
|
||||
const char *util_strerror (int num);
|
||||
int util_asprintf (char **ret, const char *fmt, ...);
|
||||
int util_sscanf (const char *str, const char *format, ...);
|
||||
char *util_strncpy (char *dest, const char *src, size_t n);
|
||||
char *util_strncat (char *dest, const char *src, size_t n);
|
||||
char *util_strcat (char *dest, const char *src);
|
||||
const char *util_strerror(int err);
|
||||
|
||||
const struct tm *util_localtime(const time_t *timer);
|
||||
const char *util_ctime (const time_t *timer);
|
||||
|
||||
typedef struct fs_file_s fs_file_t;
|
||||
bool util_isatty (fs_file_t *);
|
||||
|
||||
/*
|
||||
* A flexible vector implementation: all vector pointers contain some
|
||||
|
@ -391,13 +350,6 @@ void _util_vec_grow(void **a, size_t i, size_t s);
|
|||
#define vec_append(A,N,S) ((void)(memcpy(vec_add((A), (N)), (S), (N) * sizeof(*(S)))))
|
||||
#define vec_remove(A,I,N) ((void)(memmove((A)+(I),(A)+((I)+(N)),sizeof(*(A))*(vec_meta(A)->used-(I)-(N))),vec_meta(A)->used-=(N)))
|
||||
|
||||
typedef struct correct_trie_s {
|
||||
void *value;
|
||||
struct correct_trie_s *entries;
|
||||
} correct_trie_t;
|
||||
|
||||
correct_trie_t* correct_trie_new(void);
|
||||
|
||||
typedef struct hash_table_s {
|
||||
size_t size;
|
||||
struct hash_node_t **table;
|
||||
|
@ -445,34 +397,48 @@ void util_htrm (hash_table_t *ht, const char *key, void (*cb)(void*));
|
|||
void *util_htget (hash_table_t *ht, const char *key);
|
||||
void *util_htgeth(hash_table_t *ht, const char *key, size_t hash);
|
||||
|
||||
/*===================================================================*/
|
||||
/*============================ file.c ===============================*/
|
||||
/*===================================================================*/
|
||||
/* file handling */
|
||||
void fs_file_close (FILE *);
|
||||
int fs_file_error (FILE *);
|
||||
int fs_file_getc (FILE *);
|
||||
int fs_file_printf (FILE *, const char *, ...);
|
||||
int fs_file_puts (FILE *, const char *);
|
||||
int fs_file_seek (FILE *, long int, int);
|
||||
long int fs_file_tell (FILE *);
|
||||
int util_snprintf(char *str, size_t, const char *fmt, ...);
|
||||
|
||||
size_t fs_file_read (void *, size_t, size_t, FILE *);
|
||||
size_t fs_file_write (const void *, size_t, size_t, FILE *);
|
||||
|
||||
FILE *fs_file_open (const char *, const char *);
|
||||
int fs_file_getline(char **, size_t *, FILE *);
|
||||
/* fs.c */
|
||||
#define FS_FILE_SEEK_SET 0
|
||||
#define FS_FILE_SEEK_CUR 1
|
||||
#define FS_FILE_SEEK_END 2
|
||||
#define FS_FILE_EOF -1
|
||||
|
||||
typedef struct fs_dir_s fs_dir_t;
|
||||
/*typedef struct fs_file_s fs_file_t;*/
|
||||
typedef struct dirent fs_dirent_t;
|
||||
|
||||
void fs_file_close (fs_file_t *);
|
||||
int fs_file_error (fs_file_t *);
|
||||
int fs_file_getc (fs_file_t *);
|
||||
int fs_file_printf (fs_file_t *, const char *, ...);
|
||||
int fs_file_puts (fs_file_t *, const char *);
|
||||
int fs_file_seek (fs_file_t *, long int, int);
|
||||
long fs_file_tell (fs_file_t *);
|
||||
int fs_file_flush (fs_file_t *);
|
||||
|
||||
size_t fs_file_read (void *, size_t, size_t, fs_file_t *);
|
||||
size_t fs_file_write (const void *, size_t, size_t, fs_file_t *);
|
||||
|
||||
fs_file_t *fs_file_open (const char *, const char *);
|
||||
int fs_file_getline(char **, size_t *, fs_file_t *);
|
||||
|
||||
/* directory handling */
|
||||
int fs_dir_make (const char *);
|
||||
DIR *fs_dir_open (const char *);
|
||||
int fs_dir_close (DIR *);
|
||||
struct dirent *fs_dir_read (DIR *);
|
||||
fs_dir_t *fs_dir_open (const char *);
|
||||
int fs_dir_close (fs_dir_t *);
|
||||
fs_dirent_t *fs_dir_read (fs_dir_t *);
|
||||
|
||||
|
||||
/*===================================================================*/
|
||||
/*=========================== correct.c =============================*/
|
||||
/*===================================================================*/
|
||||
/* correct.c */
|
||||
typedef struct correct_trie_s {
|
||||
void *value;
|
||||
struct correct_trie_s *entries;
|
||||
} correct_trie_t;
|
||||
|
||||
correct_trie_t* correct_trie_new(void);
|
||||
|
||||
typedef struct {
|
||||
char ***edits;
|
||||
size_t **lens;
|
||||
|
@ -484,9 +450,8 @@ char *correct_str (correction_t *, correct_trie_t*, const char *);
|
|||
void correct_init(correction_t *);
|
||||
void correct_free(correction_t *);
|
||||
|
||||
/*===================================================================*/
|
||||
/*=========================== code.c ================================*/
|
||||
/*===================================================================*/
|
||||
|
||||
/* code.c */
|
||||
|
||||
/* Note: if you change the order, fix type_sizeof in ir.c */
|
||||
enum {
|
||||
|
@ -783,9 +748,7 @@ void code_push_statement(code_t *, prog_section_statement_t *stmt, lex_ctx_
|
|||
void code_pop_statement (code_t *);
|
||||
|
||||
|
||||
/*===================================================================*/
|
||||
/*============================ con.c ================================*/
|
||||
/*===================================================================*/
|
||||
/* conout.c */
|
||||
enum {
|
||||
CON_BLACK = 30,
|
||||
CON_RED,
|
||||
|
@ -804,8 +767,8 @@ enum {
|
|||
LVL_ERROR
|
||||
};
|
||||
|
||||
FILE *con_default_out(void);
|
||||
FILE *con_default_err(void);
|
||||
fs_file_t *con_default_out(void);
|
||||
fs_file_t *con_default_err(void);
|
||||
|
||||
void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap);
|
||||
void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...);
|
||||
|
@ -833,10 +796,8 @@ bool GMQCC_WARN compile_warning (lex_ctx_t ctx, int warntype, const char *fmt, .
|
|||
bool GMQCC_WARN vcompile_warning(lex_ctx_t ctx, int warntype, const char *fmt, va_list ap);
|
||||
void compile_show_werrors(void);
|
||||
|
||||
/*===================================================================*/
|
||||
/*============================= ir.c ================================*/
|
||||
/*===================================================================*/
|
||||
|
||||
/* ir.c */
|
||||
/* TODO: cleanup */
|
||||
enum store_types {
|
||||
store_global,
|
||||
store_local, /* local, assignable for now, should get promoted later */
|
||||
|
@ -849,9 +810,7 @@ typedef struct {
|
|||
qcfloat_t x, y, z;
|
||||
} vec3_t;
|
||||
|
||||
/*===================================================================*/
|
||||
/*============================= exec.c ==============================*/
|
||||
/*===================================================================*/
|
||||
/* exec.c */
|
||||
|
||||
/* TODO: cleanup */
|
||||
/*
|
||||
|
@ -944,9 +903,7 @@ qcany_t* prog_getedict (qc_program_t *prog, qcint_t e);
|
|||
qcint_t prog_tempstring(qc_program_t *prog, const char *_str);
|
||||
|
||||
|
||||
/*===================================================================*/
|
||||
/*===================== parser.c commandline ========================*/
|
||||
/*===================================================================*/
|
||||
/* parser.c */
|
||||
struct parser_s;
|
||||
struct parser_s *parser_create (void);
|
||||
bool parser_compile_file (struct parser_s *parser, const char *);
|
||||
|
@ -954,9 +911,7 @@ bool parser_compile_string(struct parser_s *parser, const char *, co
|
|||
bool parser_finish (struct parser_s *parser, const char *);
|
||||
void parser_cleanup (struct parser_s *parser);
|
||||
|
||||
/*===================================================================*/
|
||||
/*====================== ftepp.c commandline ========================*/
|
||||
/*===================================================================*/
|
||||
/* ftepp.c */
|
||||
struct ftepp_s;
|
||||
struct ftepp_s *ftepp_create (void);
|
||||
bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename);
|
||||
|
@ -967,9 +922,7 @@ void ftepp_flush (struct ftepp_s *ftepp);
|
|||
void ftepp_add_define (struct ftepp_s *ftepp, const char *source, const char *name);
|
||||
void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, const char *value);
|
||||
|
||||
/*===================================================================*/
|
||||
/*======================= main.c commandline ========================*/
|
||||
/*===================================================================*/
|
||||
/* main.c */
|
||||
|
||||
#if 1
|
||||
/* Helpers to allow for a whole lot of flags. Otherwise we'd limit
|
||||
|
@ -987,16 +940,12 @@ typedef uint32_t longbit;
|
|||
#define LONGBIT_SET(B, I) ((B) = (I))
|
||||
#endif
|
||||
|
||||
/*===================================================================*/
|
||||
/*============================= utf8.c ==============================*/
|
||||
/*===================================================================*/
|
||||
/* utf.8 */
|
||||
typedef long utf8ch_t;
|
||||
int utf8_from(char *, utf8ch_t);
|
||||
int utf8_to(utf8ch_t *, const unsigned char *, size_t);
|
||||
|
||||
/*===================================================================*/
|
||||
/*============================= opts.c ==============================*/
|
||||
/*===================================================================*/
|
||||
/* opts.c */
|
||||
typedef struct {
|
||||
const char *name;
|
||||
longbit bit;
|
||||
|
|
11
include.mk
11
include.mk
|
@ -13,11 +13,14 @@ CC ?= clang
|
|||
LDFLAGS +=
|
||||
LIBS += -lm
|
||||
|
||||
#common objects
|
||||
COMMON = ansi.o util.o stat.o fs.o opts.o conout.o
|
||||
|
||||
#objects
|
||||
OBJ_C = main.o lexer.o parser.o fs.o stat.o util.o code.o ast.o ir.o conout.o ftepp.o opts.o utf8.o correct.o fold.o intrin.o
|
||||
OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o
|
||||
OBJ_T = test.o util.o opts.o conout.o fs.o stat.o
|
||||
OBJ_X = exec-standalone.o util.o opts.o conout.o fs.o stat.o
|
||||
OBJ_C = $(COMMON) main.o lexer.o parser.o code.o ast.o ir.o ftepp.o utf8.o correct.o fold.o intrin.o
|
||||
OBJ_P = $(COMMON) pak.o
|
||||
OBJ_T = $(COMMON) test.o
|
||||
OBJ_X = $(COMMON) exec-standalone.o
|
||||
|
||||
#gource flags
|
||||
GOURCEFLAGS = \
|
||||
|
|
10
ir.c
10
ir.c
|
@ -3977,10 +3977,6 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
|
|||
|
||||
#define IND_BUFSZ 1024
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
|
||||
#endif
|
||||
|
||||
static const char *qc_opname(int op)
|
||||
{
|
||||
if (op < 0) return "<INVALID>";
|
||||
|
@ -4039,7 +4035,7 @@ void ir_function_dump(ir_function *f, char *ind,
|
|||
return;
|
||||
}
|
||||
oprintf("%sfunction %s\n", ind, f->name);
|
||||
strncat(ind, "\t", IND_BUFSZ-1);
|
||||
util_strncat(ind, "\t", IND_BUFSZ-1);
|
||||
if (vec_size(f->locals))
|
||||
{
|
||||
oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
|
||||
|
@ -4135,7 +4131,7 @@ void ir_block_dump(ir_block* b, char *ind,
|
|||
{
|
||||
size_t i;
|
||||
oprintf("%s:%s\n", ind, b->label);
|
||||
strncat(ind, "\t", IND_BUFSZ-1);
|
||||
util_strncat(ind, "\t", IND_BUFSZ-1);
|
||||
|
||||
if (b->instr && b->instr[0])
|
||||
oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1));
|
||||
|
@ -4169,7 +4165,7 @@ void ir_instr_dump(ir_instr *in, char *ind,
|
|||
return;
|
||||
}
|
||||
|
||||
strncat(ind, "\t", IND_BUFSZ-1);
|
||||
util_strncat(ind, "\t", IND_BUFSZ-1);
|
||||
|
||||
if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
|
||||
ir_value_dump(in->_ops[0], oprintf);
|
||||
|
|
53
lexer.c
53
lexer.c
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "gmqcc.h"
|
||||
#include "lexer.h"
|
||||
|
||||
/*
|
||||
* List of Keywords
|
||||
*/
|
||||
|
@ -179,8 +180,8 @@ static void lex_token_new(lex_file *lex)
|
|||
|
||||
lex_file* lex_open(const char *file)
|
||||
{
|
||||
lex_file *lex;
|
||||
FILE *in = fs_file_open(file, "rb");
|
||||
lex_file *lex;
|
||||
fs_file_t *in = fs_file_open(file, "rb");
|
||||
|
||||
if (!in) {
|
||||
lexerror(NULL, "open failed: '%s'\n", file);
|
||||
|
@ -273,11 +274,11 @@ static int lex_fgetc(lex_file *lex)
|
|||
}
|
||||
if (lex->open_string) {
|
||||
if (lex->open_string_pos >= lex->open_string_length)
|
||||
return EOF;
|
||||
return FS_FILE_EOF;
|
||||
lex->column++;
|
||||
return lex->open_string[lex->open_string_pos++];
|
||||
}
|
||||
return EOF;
|
||||
return FS_FILE_EOF;
|
||||
}
|
||||
|
||||
/* Get or put-back data
|
||||
|
@ -493,7 +494,7 @@ static bool lex_try_pragma(lex_file *lex)
|
|||
goto unroll;
|
||||
|
||||
lex->line = line;
|
||||
while (ch != '\n' && ch != EOF)
|
||||
while (ch != '\n' && ch != FS_FILE_EOF)
|
||||
ch = lex_getch(lex);
|
||||
vec_free(command);
|
||||
vec_free(param);
|
||||
|
@ -573,7 +574,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
do
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && util_isspace(ch)) {
|
||||
while (ch != FS_FILE_EOF && util_isspace(ch)) {
|
||||
if (ch == '\n') {
|
||||
if (lex_try_pragma(lex))
|
||||
continue;
|
||||
|
@ -613,7 +614,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
lex_tokench(lex, ' ');
|
||||
}
|
||||
|
||||
while (ch != EOF && ch != '\n') {
|
||||
while (ch != FS_FILE_EOF && ch != '\n') {
|
||||
if (lex->flags.preprocessing)
|
||||
lex_tokench(lex, ' '); /* ch); */
|
||||
ch = lex_getch(lex);
|
||||
|
@ -638,7 +639,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
lex_tokench(lex, ' ');
|
||||
}
|
||||
|
||||
while (ch != EOF)
|
||||
while (ch != FS_FILE_EOF)
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
if (ch == '*') {
|
||||
|
@ -671,7 +672,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
ch = '/';
|
||||
break;
|
||||
}
|
||||
} while (ch != EOF && util_isspace(ch));
|
||||
} while (ch != FS_FILE_EOF && util_isspace(ch));
|
||||
|
||||
if (haswhite) {
|
||||
lex_endtoken(lex);
|
||||
|
@ -687,7 +688,7 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
|
|||
int ch;
|
||||
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && isident(ch))
|
||||
while (ch != FS_FILE_EOF && isident(ch))
|
||||
{
|
||||
lex_tokench(lex, ch);
|
||||
ch = lex_getch(lex);
|
||||
|
@ -707,7 +708,7 @@ static int lex_parse_frame(lex_file *lex)
|
|||
lex_token_new(lex);
|
||||
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && ch != '\n' && util_isspace(ch))
|
||||
while (ch != FS_FILE_EOF && ch != '\n' && util_isspace(ch))
|
||||
ch = lex_getch(lex);
|
||||
|
||||
if (ch == '\n')
|
||||
|
@ -768,7 +769,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
|
|||
char u8buf[8]; /* way more than enough */
|
||||
int u8len, uc;
|
||||
|
||||
while (ch != EOF)
|
||||
while (ch != FS_FILE_EOF)
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
if (ch == quote)
|
||||
|
@ -777,18 +778,18 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
|
|||
if (lex->flags.preprocessing && ch == '\\') {
|
||||
lex_tokench(lex, ch);
|
||||
ch = lex_getch(lex);
|
||||
if (ch == EOF) {
|
||||
if (ch == FS_FILE_EOF) {
|
||||
lexerror(lex, "unexpected end of file");
|
||||
lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
|
||||
lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
|
||||
return (lex->tok.ttype = TOKEN_ERROR);
|
||||
}
|
||||
lex_tokench(lex, ch);
|
||||
}
|
||||
else if (ch == '\\') {
|
||||
ch = lex_getch(lex);
|
||||
if (ch == EOF) {
|
||||
if (ch == FS_FILE_EOF) {
|
||||
lexerror(lex, "unexpected end of file");
|
||||
lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
|
||||
lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
|
||||
return (lex->tok.ttype = TOKEN_ERROR);
|
||||
}
|
||||
|
||||
|
@ -911,7 +912,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
|
|||
lex_tokench(lex, ch);
|
||||
}
|
||||
lexerror(lex, "unexpected end of file within string constant");
|
||||
lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
|
||||
lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
|
||||
return (lex->tok.ttype = TOKEN_ERROR);
|
||||
}
|
||||
|
||||
|
@ -1032,7 +1033,7 @@ int lex_do(lex_file *lex)
|
|||
if (lex->eof)
|
||||
return (lex->tok.ttype = TOKEN_FATAL);
|
||||
|
||||
if (ch == EOF) {
|
||||
if (ch == FS_FILE_EOF) {
|
||||
lex->eof = true;
|
||||
return (lex->tok.ttype = TOKEN_EOF);
|
||||
}
|
||||
|
@ -1069,7 +1070,7 @@ int lex_do(lex_file *lex)
|
|||
if (!strcmp(v, "framevalue"))
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && util_isspace(ch) && ch != '\n')
|
||||
while (ch != FS_FILE_EOF && util_isspace(ch) && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
|
||||
if (!util_isdigit(ch)) {
|
||||
|
@ -1149,7 +1150,7 @@ int lex_do(lex_file *lex)
|
|||
vec_free(lex->frames);
|
||||
/* skip line (fteqcc does it too) */
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && ch != '\n')
|
||||
while (ch != FS_FILE_EOF && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
@ -1163,7 +1164,7 @@ int lex_do(lex_file *lex)
|
|||
{
|
||||
/* skip line */
|
||||
ch = lex_getch(lex);
|
||||
while (ch != EOF && ch != '\n')
|
||||
while (ch != FS_FILE_EOF && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
@ -1473,14 +1474,10 @@ int lex_do(lex_file *lex)
|
|||
lex_endtoken(lex);
|
||||
|
||||
lex->tok.ttype = TOKEN_CHARCONST;
|
||||
/* It's a vector if we can successfully scan 3 floats */
|
||||
#ifdef _MSC_VER
|
||||
if (sscanf_s(lex->tok.value, " %f %f %f ",
|
||||
|
||||
/* It's a vector if we can successfully scan 3 floats */
|
||||
if (util_sscanf(lex->tok.value, " %f %f %f ",
|
||||
&lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
|
||||
#else
|
||||
if (sscanf(lex->tok.value, " %f %f %f ",
|
||||
&lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
|
||||
#endif
|
||||
|
||||
{
|
||||
lex->tok.ttype = TOKEN_VECTORCONST;
|
||||
|
|
2
lexer.h
2
lexer.h
|
@ -105,7 +105,7 @@ typedef struct {
|
|||
} frame_macro;
|
||||
|
||||
typedef struct lex_file_s {
|
||||
FILE *file;
|
||||
fs_file_t *file;
|
||||
const char *open_string;
|
||||
size_t open_string_length;
|
||||
size_t open_string_pos;
|
||||
|
|
12
main.c
12
main.c
|
@ -531,7 +531,7 @@ static bool options_parse(int argc, char **argv) {
|
|||
}
|
||||
|
||||
/* returns the line number, or -1 on error */
|
||||
static bool progs_nextline(char **out, size_t *alen,FILE *src) {
|
||||
static bool progs_nextline(char **out, size_t *alen, fs_file_t *src) {
|
||||
int len;
|
||||
char *line;
|
||||
char *start;
|
||||
|
@ -562,7 +562,7 @@ int main(int argc, char **argv) {
|
|||
bool opts_output_free = false;
|
||||
bool operators_free = false;
|
||||
bool progs_src = false;
|
||||
FILE *outfile = NULL;
|
||||
fs_file_t *outfile = NULL;
|
||||
struct parser_s *parser = NULL;
|
||||
struct ftepp_s *ftepp = NULL;
|
||||
|
||||
|
@ -667,10 +667,10 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (!vec_size(items)) {
|
||||
FILE *src;
|
||||
char *line = NULL;
|
||||
size_t linelen = 0;
|
||||
bool hasline = false;
|
||||
fs_file_t *src;
|
||||
char *line = NULL;
|
||||
size_t linelen = 0;
|
||||
bool hasline = false;
|
||||
|
||||
progs_src = true;
|
||||
|
||||
|
|
235
msvc.c
Normal file
235
msvc.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* Copyright (C) 2012, 2013
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#define GMQCC_PLATFORM_HEADER
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#define CTIME_BUFFER 64
|
||||
#define GETENV_BUFFER 4096
|
||||
#define STRERROR_BUFFER 128
|
||||
|
||||
static void **platform_mem_pool = NULL;
|
||||
static void platform_mem_atexit() {
|
||||
size_t i;
|
||||
for (i = 0; i < vec_size(platform_mem_pool); i++)
|
||||
mem_d(platform_mem_pool[i]);
|
||||
vec_free(platform_mem_pool);
|
||||
}
|
||||
|
||||
static void *platform_mem_allocate(size_t bytes) {
|
||||
void *mem = NULL;
|
||||
if (!platform_mem_pool) {
|
||||
atexit(&platform_mem_atexit);
|
||||
vec_push(platform_mem_pool, NULL);
|
||||
}
|
||||
|
||||
mem = mem_a(bytes);
|
||||
vec_push(platform_mem_pool, mem);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
int platform_vsnprintf(char *buffer, size_t bytes, const char *format, va_list arg) {
|
||||
vsnprintf_s(buffer, bytes, bytes, format, arg);
|
||||
}
|
||||
|
||||
int platform_vsscanf(const char *str, const char *format, va_list va) {
|
||||
return vsscanf_s(str, format, va);
|
||||
}
|
||||
|
||||
const struct tm *platform_localtime(const time_t *timer) {
|
||||
struct tm *t;
|
||||
t = (struct tm*)platform_mem_allocate(sizeof(struct tm));
|
||||
localtime_s(&t, timer);
|
||||
return t;
|
||||
}
|
||||
|
||||
const char *platform_ctime(const time_t *timer) {
|
||||
char *buffer = (char *)platform_mem_allocate(CTIME_BUFFER);
|
||||
ctime_s(buffer, CTIME_BUFFER, timer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *platform_strncat(char *dest, const char *src, size_t num) {
|
||||
return strncat_s(dest, num, src, _TRUNCATE);
|
||||
}
|
||||
|
||||
const char *platform_tmpnam(char *str) {
|
||||
return tmpnam_s(str, L_tmpnam);
|
||||
}
|
||||
|
||||
const char *platform_getenv(char *var) {
|
||||
char *buffer = (char *)platform_mem_allocate(GETENV_BUFFER);
|
||||
size_t size;
|
||||
getenv_s(&size, buffer, GETENV_BUFFER, var);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: this isn't exactly 'accurate' for MSVC but it seems to work,
|
||||
* at least to some extent.
|
||||
*/
|
||||
int platform_vasprintf(char **dat, const char *fmt, va_list args) {
|
||||
int ret;
|
||||
int len;
|
||||
char *tmp = NULL;
|
||||
|
||||
if ((len = _vscprintf(fmt, args)) < 0) {
|
||||
*dat = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = (char*)mem_a(len + 1);
|
||||
if ((ret = _vsnprintf_s(tmp, len+1, len+1, fmt, args)) != len) {
|
||||
mem_d(tmp);
|
||||
*dat = NULL;
|
||||
return -1;
|
||||
}
|
||||
*dat = tmp;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *platform_strcat(char *dest, const char *src) {
|
||||
strcat_s(dest, strlen(src), src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *platform_strncpy(char *dest, const char *src, size_t num) {
|
||||
strncpy_s(dest, num, src, num);
|
||||
return dest;
|
||||
}
|
||||
|
||||
const char *platform_strerror(int err) {
|
||||
char *buffer = (char*)platform_mem_allocate(STRERROR_BUFFER);
|
||||
strerror_s(buffer, STRERROR_BUFFER, err);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
FILE *platform_fopen(const char *filename, const char *mode) {
|
||||
FILE *handle;
|
||||
return (fopen_s(&handle, filename, mode) != 0) ? NULL : handle;
|
||||
}
|
||||
|
||||
size_t platform_fread(void *ptr, size_t size, size_t count, FILE *stream) {
|
||||
return fread_s(ptr, size, size, count, stream);
|
||||
}
|
||||
|
||||
size_t platform_fwrite(const void *ptr, size_t size, size_t count, FILE *stream) {
|
||||
return fwrite(ptr, size, count, stream);
|
||||
}
|
||||
|
||||
int platform_fflush(FILE *stream) {
|
||||
return fflush(stream);
|
||||
}
|
||||
|
||||
int platform_vfprintf(FILE *stream, const char *format, va_list arg) {
|
||||
return vfprintf_s(stream, format, arg);
|
||||
}
|
||||
|
||||
int platform_fclose(FILE *stream) {
|
||||
return fclose(stream);
|
||||
}
|
||||
|
||||
int platform_ferror(FILE *stream) {
|
||||
return ferror(stream);
|
||||
}
|
||||
|
||||
int platform_fgetc(FILE *stream) {
|
||||
return fgetc(stream);
|
||||
}
|
||||
|
||||
int platform_fputs(const char *str, FILE *stream) {
|
||||
return fputs(str, stream);
|
||||
}
|
||||
|
||||
int platform_fseek(FILE *stream, long offset, int origin) {
|
||||
return fseek(stream, offset, origin);
|
||||
}
|
||||
|
||||
long platform_ftell(FILE *stream) {
|
||||
return ftell(stream);
|
||||
}
|
||||
|
||||
int platform_mkdir(const char *path, int mode) {
|
||||
return mkdir(path, mode);
|
||||
}
|
||||
|
||||
DIR *platform_opendir(const char *path) {
|
||||
DIR *dir = (DIR*)mem_a(sizeof(DIR) + strlen(path));
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
platform_strncpy(dir->dd_name, path, strlen(path));
|
||||
return dir;
|
||||
}
|
||||
|
||||
int platform_closedir(DIR *dir) {
|
||||
FindClose((HANDLE)dir->dd_handle);
|
||||
mem_d((void*)dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dirent *platform_readdir(DIR *dir) {
|
||||
WIN32_FIND_DATA info;
|
||||
struct dirent *data;
|
||||
int ret;
|
||||
|
||||
if (!dir->dd_handle) {
|
||||
char *dirname;
|
||||
if (*dir->dd_name) {
|
||||
size_t n = strlen(dir->dd_name);
|
||||
if ((dir = (char*)mem_a(n+5))) {
|
||||
platform_strncpy(dirname, dir->dd_name, n);
|
||||
platform_strncpy(dirname + n, "\\*.*", 4);
|
||||
}
|
||||
} else {
|
||||
if (!(dirname = util_strdup("\\*.*")))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir->dd_handle = (long)FindFirstFile(dirname, &info);
|
||||
mem_d(dirname);
|
||||
ret = !(!dir->dd_handle);
|
||||
} else if (dir->dd_handle != -11) {
|
||||
ret = FindNextFile((HANDLE)dir->dd_handle, &info);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
if ((data = (struct dirent*)mem_a(sizeof(struct dirent)))) {
|
||||
platform_strncpy(data->d_name, info.cFileName, FILENAME_MAX - 1);
|
||||
data->d_name[FILENAME_MAX - 1] = '\0';
|
||||
data->d_namelen = strlen(data->d_name);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int platform_istty(int fd) {
|
||||
return _isatty(fd);
|
||||
}
|
6
opts.c
6
opts.c
|
@ -213,7 +213,7 @@ static char *opts_ini_next(const char *s, char c) {
|
|||
}
|
||||
|
||||
static size_t opts_ini_parse (
|
||||
FILE *filehandle,
|
||||
fs_file_t *filehandle,
|
||||
char *(*loadhandle)(const char *, const char *, const char *),
|
||||
char **errorhandle
|
||||
) {
|
||||
|
@ -230,7 +230,7 @@ static size_t opts_ini_parse (
|
|||
char *read_name;
|
||||
char *read_value;
|
||||
|
||||
while (fs_file_getline(&line, &linesize, filehandle) != EOF) {
|
||||
while (fs_file_getline(&line, &linesize, filehandle) != FS_FILE_EOF) {
|
||||
parse_beg = line;
|
||||
|
||||
/* handle BOM */
|
||||
|
@ -380,7 +380,7 @@ void opts_ini_init(const char *file) {
|
|||
*/
|
||||
char *error = NULL;
|
||||
size_t line;
|
||||
FILE *ini;
|
||||
fs_file_t *ini;
|
||||
|
||||
if (!file) {
|
||||
/* try ini */
|
||||
|
|
22
pak.c
22
pak.c
|
@ -124,7 +124,7 @@ static void pak_tree_build(const char *entry) {
|
|||
typedef struct {
|
||||
pak_directory_t *directories;
|
||||
pak_header_t header;
|
||||
FILE *handle;
|
||||
fs_file_t *handle;
|
||||
bool insert;
|
||||
} pak_file_t;
|
||||
|
||||
|
@ -162,7 +162,7 @@ static pak_file_t *pak_open_read(const char *file) {
|
|||
* Time to read in the directory handles and prepare the directories
|
||||
* vector. We're going to be reading some the file inwards soon.
|
||||
*/
|
||||
fs_file_seek(pak->handle, pak->header.diroff, SEEK_SET);
|
||||
fs_file_seek(pak->handle, pak->header.diroff, FS_FILE_SEEK_SET);
|
||||
|
||||
/*
|
||||
* Read in all directories from the PAK file. These are considered
|
||||
|
@ -266,7 +266,7 @@ static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdi
|
|||
pak_directory_t *dir = NULL;
|
||||
unsigned char *dat = NULL;
|
||||
char *local = NULL;
|
||||
FILE *out = NULL;
|
||||
fs_file_t *out = NULL;
|
||||
|
||||
if (!pak_exists(pak, file, &dir)) {
|
||||
return false;
|
||||
|
@ -295,7 +295,7 @@ static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdi
|
|||
mem_d(local);
|
||||
|
||||
/* read */
|
||||
if (fs_file_seek (pak->handle, dir->pos, SEEK_SET) != 0)
|
||||
if (fs_file_seek (pak->handle, dir->pos, FS_FILE_SEEK_SET) != 0)
|
||||
goto err;
|
||||
|
||||
fs_file_read (dat, 1, dir->len, pak->handle);
|
||||
|
@ -333,7 +333,7 @@ static bool pak_insert_one(pak_file_t *pak, const char *file) {
|
|||
pak_directory_t dir;
|
||||
unsigned char *dat;
|
||||
long len;
|
||||
FILE *fp;
|
||||
fs_file_t *fp;
|
||||
|
||||
/*
|
||||
* We don't allow insertion on files that already exist within the
|
||||
|
@ -351,9 +351,9 @@ static bool pak_insert_one(pak_file_t *pak, const char *file) {
|
|||
* the directory entry, and the actual contents of the file
|
||||
* to the PAK file itself.
|
||||
*/
|
||||
if (fs_file_seek(fp, 0, SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0))
|
||||
if (fs_file_seek(fp, 0, FS_FILE_SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0))
|
||||
goto err;
|
||||
if (fs_file_seek(fp, 0, SEEK_SET) != 0)
|
||||
if (fs_file_seek(fp, 0, FS_FILE_SEEK_SET) != 0)
|
||||
goto err;
|
||||
|
||||
dir.len = len;
|
||||
|
@ -438,18 +438,17 @@ static bool pak_close(pak_file_t *pak) {
|
|||
pak->header.diroff = tell;
|
||||
|
||||
/* patch header */
|
||||
if (fs_file_seek (pak->handle, 0, SEEK_SET) != 0)
|
||||
if (fs_file_seek (pak->handle, 0, FS_FILE_SEEK_SET) != 0)
|
||||
goto err;
|
||||
|
||||
fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle);
|
||||
|
||||
/* write directories */
|
||||
if (fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET) != 0)
|
||||
if (fs_file_seek (pak->handle, pak->header.diroff, FS_FILE_SEEK_SET) != 0)
|
||||
goto err;
|
||||
|
||||
for (itr = 0; itr < vec_size(pak->directories); itr++) {
|
||||
for (itr = 0; itr < vec_size(pak->directories); itr++)
|
||||
fs_file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle);
|
||||
}
|
||||
}
|
||||
|
||||
vec_free (pak->directories);
|
||||
|
@ -496,6 +495,7 @@ static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out,
|
|||
return true;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
int main(int argc, char **argv) {
|
||||
bool extract = true;
|
||||
char *redirout = (char*)stdout;
|
||||
|
|
3
parser.c
3
parser.c
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
#define PARSER_HT_LOCALS 2
|
||||
|
@ -5912,7 +5913,7 @@ parser_t *parser_create()
|
|||
}
|
||||
}
|
||||
if (!parser->assign_op) {
|
||||
printf("internal error: initializing parser: failed to find assign operator\n");
|
||||
con_err("internal error: initializing parser: failed to find assign operator\n");
|
||||
mem_d(parser);
|
||||
return NULL;
|
||||
}
|
||||
|
|
573
platform.h
Normal file
573
platform.h
Normal file
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* Copyright (C) 2012, 2013
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef GMQCC_PLATFORM_HDR
|
||||
#define GMQCC_PLATFORM_HDR
|
||||
|
||||
#ifndef GMQCC_PLATFORM_HEADER
|
||||
# error "This header shouldn't be included!"
|
||||
#endif
|
||||
|
||||
#undef GMQCC_PLATFORM_HEADER
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef STDERR_FILENO
|
||||
# define STDERR_FILENO 2
|
||||
# endif
|
||||
# ifndef STDOUT_FILENO
|
||||
# define STDOUT_FILENO 1
|
||||
# endif
|
||||
# ifndef __MINGW32__
|
||||
# define _WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
|
||||
struct dirent {
|
||||
long d_ino;
|
||||
unsigned short d_reclen;
|
||||
unsigned short d_namlen;
|
||||
char d_name[FILENAME_MAX];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct _finddata_t dd_dta;
|
||||
struct dirent dd_dir;
|
||||
long dd_handle;
|
||||
int dd_stat;
|
||||
char dd_name[1];
|
||||
} DIR;
|
||||
|
||||
# ifdef S_ISDIR
|
||||
# undef S_ISDIR
|
||||
# endif /*! S_ISDIR */
|
||||
# define S_ISDIR(X) ((X)&_S_IFDIR)
|
||||
# else
|
||||
# include <dirent.h>
|
||||
# endif /*!__MINGW32__*/
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
/*
|
||||
* Function: platform_vsnprintf
|
||||
* Write formatted output using a pointer to a lis of arguments.
|
||||
*
|
||||
* Parameters:
|
||||
* buffer - Storage location for output.
|
||||
* bytes - Maximum number of characters to write.
|
||||
* format - Format specification.
|
||||
* arg - Variable argument list.
|
||||
*
|
||||
* Returns:
|
||||
* The number of characters written if the number of characters to write
|
||||
* is less than or equal to `bytes`; if the number of characters to write
|
||||
* is greater than `bytes`, this function returns -1 indicating that the
|
||||
* output has been truncated. The return value does not include the
|
||||
* terminating null, if one is written.
|
||||
*
|
||||
* Remarks:
|
||||
* Function takes pointer to an argument list, then formats the data,
|
||||
* and writes up to `bytes` characters to the memory pointed to by
|
||||
* `buffer`. If there is room at the end (that is, if the number of
|
||||
* character to write is less than `bytes`), the buffer will be null-terminated.
|
||||
*/
|
||||
int platform_vsnprintf(char *buffer, size_t bytes, const char *format, va_list arg);
|
||||
|
||||
/*
|
||||
* Function: platform_vsscanf
|
||||
* Reads formatted data from a string.
|
||||
*
|
||||
* Parameters:
|
||||
* buffer - Stored data to read.
|
||||
* format - Format specification.
|
||||
* arg - Variable argument list.
|
||||
*
|
||||
* Returns:
|
||||
* The number of fields that are successfully converted and assigned;
|
||||
* the return value does not include fields that were read but not
|
||||
* assigned. A return vlaue of 0 indicated that no fields were assigned.
|
||||
* The return value if EOF for error or if the end of the string is
|
||||
* reached before the first conversion.
|
||||
*
|
||||
* Remarks:
|
||||
* Reads data from `buffer` into the locations that are given by each
|
||||
* argument in the `arg` argument list. Every argument in the list must
|
||||
* be a pointer to a variable that has a type that corresponds to a
|
||||
* type specifier in `format`. The `format` argument controls th
|
||||
* interpretation of the input fields and has the same form and function
|
||||
* as the `format` argument for the *scanf* function. If copying takes
|
||||
* place between strings that overlap, the behaviour is undefined.
|
||||
*/
|
||||
int platform_vsscanf(const char *buffer, const char *format, va_list arg);
|
||||
|
||||
/*
|
||||
* Function: platform_localtime
|
||||
* Convert a time value and correct for the local time zone.
|
||||
*
|
||||
* Parameters
|
||||
* timer - Pointer to stored time.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to a structure result, or NULL if the date passed to
|
||||
* the function is before midnight, January 1, 1970.
|
||||
*/
|
||||
const struct tm *platform_localtime(const time_t *timer);
|
||||
|
||||
/*
|
||||
* Function: platform_ctime
|
||||
* Convert a time value to a string and adjust for local time zone
|
||||
* settings.
|
||||
*
|
||||
* Parameters:
|
||||
* timer - Pointer to stored time.
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the character string result. NULL will be returned if time
|
||||
* represents a date before midnight, January 1, 1970, UTC.
|
||||
*
|
||||
* Remarks:
|
||||
* Converts a time value stored as a `time_t` value into a chracter string.
|
||||
* The `timer` value is usually obtained from a call to *time*, which returns
|
||||
* the number of seconds since midnight, January 1, 1970 UTC. The return
|
||||
* value of the string contains exactly 26 characters. A 24-hour clock is used.
|
||||
* All fields have constant width. The newline chracter and the null character
|
||||
* occupy the last two positions of the string. The converted character string
|
||||
* is also adjusted according to the local time zone settings.
|
||||
*/
|
||||
const char *platform_ctime(const time_t *timer);
|
||||
|
||||
/*
|
||||
* Function: platform_strncat
|
||||
* Append characters of a string.
|
||||
*
|
||||
* Parameters:
|
||||
* dest - Null terminated destination string
|
||||
* src - Source string
|
||||
* num - Number of characters to append
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the destination string. No return value is used to indicate
|
||||
* an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Function appends, at mode, the first `num` characters of `src` to
|
||||
* `dest`. The initial character of `src` overwrites the terminating
|
||||
* null chracter of `dest`. If a null character appears in `src` before
|
||||
* `num` chracters are appended, `platform_strncat` appends all chracters
|
||||
* from `src`, up to the null chracter. If `num` is greater than the
|
||||
* length of `src`, the length of `src` is used in place of `num`.
|
||||
*/
|
||||
char *platform_strncat(char *dest, const char *src, size_t num);
|
||||
|
||||
/*
|
||||
* Function: platform_tmpnam
|
||||
* Generates names you can use to create temporary files.
|
||||
*
|
||||
* Parameters:
|
||||
* str - Pointer that will hold the generated name and will be identical
|
||||
* to the name returned by the function. This is a convenient way
|
||||
* to save the generated name.
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the name generate or *NULL* if there is a failure. Failure
|
||||
* can occur if you attempt more than TMP_MAX calls.
|
||||
*
|
||||
* Remarks:
|
||||
* Returns a name unique in the current workign directory.
|
||||
*/
|
||||
const char *platform_tmpnam(char *str);
|
||||
|
||||
/*
|
||||
* Function: platform_getenv
|
||||
* Get a value from the current enviroment.
|
||||
*
|
||||
* Parameters:
|
||||
* var - Enviroment variable name
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the enviroment table entry containing `var. It's not
|
||||
* safe to modify the value of the enviroment variable using the returned
|
||||
* pointer. The return value is *NULL* if `var` is not found in the
|
||||
* enviroment table.
|
||||
*/
|
||||
const char *platform_getenv(char *var);
|
||||
|
||||
/*
|
||||
* Function: platform_vasprintf
|
||||
* Print to allocated string
|
||||
*
|
||||
* Parameters:
|
||||
* dat - Pointer to pointer to store allocated data.
|
||||
* fmt - Format specification.
|
||||
* args - Variable argument list.
|
||||
*
|
||||
* Returns:
|
||||
* Number of character written, -1 is used to indicate an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Allocate a string large enough to hold the output including
|
||||
* the terminating null character than write formatted output
|
||||
* to it using format specification.
|
||||
*/
|
||||
int platform_vasprintf(char **dat, const char *fmt, va_list args);
|
||||
|
||||
/*
|
||||
* Function: platform_vfprintf
|
||||
* Write formatted output using a pointer to a list of arguments.
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to stream.
|
||||
* format - Format specification.
|
||||
* atrg - Variable argument list.
|
||||
*
|
||||
* Returns:
|
||||
* Number of characters written, not including the terminating null
|
||||
* character, or a negitive value if an output error occurs. -1 is
|
||||
* also used to indicate an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Takes a pointer to an argument list, then formats and writes the
|
||||
* given data to `stream`.
|
||||
*/
|
||||
int platform_vfprintf(FILE *stream, const char *format, va_list arg);
|
||||
|
||||
/*
|
||||
* Function: platform_strcat
|
||||
* Append characters of a string.
|
||||
*
|
||||
* Parameters:
|
||||
* dest - Null terminated destination string
|
||||
* src - Source string
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the destination string. No return value is used to indicate
|
||||
* an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Appens `src` to `dest` and terminates with resulting null character.
|
||||
* The initial character of `src` overwrites the terminating null
|
||||
* character of `dest`. The behaviour of platform_strcat is undefined
|
||||
* if the source and destination string overlap.
|
||||
*/
|
||||
char *platform_strcat(char *dest, const char *src);
|
||||
|
||||
/*
|
||||
* Function: platform_strncpy
|
||||
* Copys characters of one string to another.
|
||||
*
|
||||
* Parameters:
|
||||
* dest - Destination string.
|
||||
* src - Source string.
|
||||
* num - Number of characters to be copied.
|
||||
*
|
||||
* Returns:
|
||||
* `dest`. No return value is reserved to indicate an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Copies the initial characters of `src` to `dest` and returns `dest`.
|
||||
* If `num` is less than or equal to the length of `src1 a null character
|
||||
* is not appended automatically to the copied string. If `num` is greater
|
||||
* than the length of `src`, the destination string is padded with null
|
||||
* characters up to length `num`. The behaviour of this function is undefined
|
||||
* if the source and destination strings overlap.
|
||||
*/
|
||||
char *platform_strncpy(char *dest, const char *src, size_t num);
|
||||
|
||||
/*
|
||||
* Function: platform_strerror
|
||||
* Get a system error message
|
||||
*
|
||||
* Parameters:
|
||||
* err - Error number.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the error message
|
||||
*/
|
||||
const char *platform_strerror(int err);
|
||||
|
||||
/*
|
||||
* Function: platform_fopen
|
||||
* Opens a file
|
||||
*
|
||||
* Parameters:
|
||||
* filename - File name.
|
||||
* mode - Kind of access that's enabled.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the open file. A null pointer value indicates an error.
|
||||
*/
|
||||
FILE *platform_fopen(const char *filename, const char *mode);
|
||||
|
||||
/*
|
||||
* Function: platform_fread
|
||||
* Reads data from a stream
|
||||
*
|
||||
* Parameters:
|
||||
* ptr - Storage location for data.
|
||||
* size - Item size in bytes.
|
||||
* count - Maximum number of items to be read.
|
||||
* stream - Pointer to stream
|
||||
*
|
||||
* Returns:
|
||||
* The number of full items actually read, which may be less than `count`
|
||||
* if an error occurs or if the end of the file is encountered before
|
||||
* reaching `count`. If `size` or `count` is 0, `platform_fread`
|
||||
* returns 0 and the buffer contents are unchanged.
|
||||
*/
|
||||
size_t platform_fread(void *ptr, size_t size, size_t count, FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_fwrite
|
||||
* Writes data to a stream
|
||||
*
|
||||
* Parameters:
|
||||
* ptr - Pointer to data to be written.
|
||||
* size - Item size in bytes.
|
||||
* count - Maximum number of items to be read.
|
||||
* stream - Pointer to stream
|
||||
*
|
||||
* Returns:
|
||||
* The number of full items actually written, which may be less than
|
||||
* `count` if an error occurs. Also, if an error occurs, the
|
||||
* file-position indicator cannot be determined.
|
||||
*
|
||||
* Remarks:
|
||||
* Writes up to `count` items, of `size` length each, from `ptr` to the
|
||||
* output stream. The file pointer associated with stream (if there is one)
|
||||
* is incremented by the number of bytes actually written.
|
||||
*/
|
||||
size_t platform_fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_fflush
|
||||
* Flushes a stream
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to stream
|
||||
*
|
||||
* Returns:
|
||||
* 0 value if the buffer was succesffuly flushed. The value 0 is also
|
||||
* returned in cases in which the specified stream has no buffer or is
|
||||
* open for reading only. A return value of *EOF* indicates an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Flushes a stream. If the file associated with stream is open for output,
|
||||
* platform_fflush writes to that file the contents of the buffer
|
||||
* associated with the stream. If the stream is open for input,
|
||||
* platform_fflush clears the contents of the buffer. platform_fflush
|
||||
* negates the effect of any prior call to ungetc against stream. Also,
|
||||
* platform_fflush(NULL) flushes all streams opened for output.
|
||||
* The stream remains open after the call. platform_fflush has no effect
|
||||
* on an unbuffered stream.
|
||||
*/
|
||||
int platform_fflush(FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_fclose
|
||||
* Closes a stream.
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to stream.
|
||||
*
|
||||
* Returns:
|
||||
* 0 value. *EOF* is used to indicate an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Closes a stream.
|
||||
*/
|
||||
int platform_fclose(FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_ferror
|
||||
* Tests for an error on a stream.
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to stream.
|
||||
*
|
||||
* Returns:
|
||||
* If not error has occured on `stream`, 0 value is returned, otherwise
|
||||
* it returns a nonzero value.
|
||||
*
|
||||
* Remarks:
|
||||
* Tests for a reading or writing error on the file associated with `stream`.
|
||||
* If an error has occured, the error indicator for the stream remains set
|
||||
* until the stream is closed or rewound.
|
||||
*/
|
||||
int platform_ferror(FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_fgetc
|
||||
* Read a character from a stream.
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to a stream.
|
||||
*
|
||||
* Returns:
|
||||
* The chracter read as an int or EOF to indicate an error or end-of-file.
|
||||
*
|
||||
* Remarks:
|
||||
* Reads a single chracter from the current position of the file associated
|
||||
* with `stream`. Than increments that position. If the steam is at the end
|
||||
* of the file, the end-of-file indicator for the stream is set.
|
||||
*/
|
||||
int platform_fgetc(FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_fputs
|
||||
* Write a string to a stream
|
||||
*
|
||||
* Parameters:
|
||||
* str - Output string.
|
||||
* stream - Pointer to stream.
|
||||
*
|
||||
* Returns:
|
||||
* Non-negative value if successful. EOF is used to indicate an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Copies `str` to the output stream at the current position.
|
||||
*/
|
||||
int platform_fputs(const char *str, FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_fseek
|
||||
* Moves the file pointer to a specified location.
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to stream.
|
||||
* offset - Number of bytes from origin to offset.
|
||||
* origin - Initital position.
|
||||
*
|
||||
* Returns:
|
||||
* 0 value, nonzero values are used to indicate an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Moves the file pointer (if any) associated with stream to a new
|
||||
* location that is offset bytes from origin.
|
||||
* The next operation on the stream takes place at the new location.
|
||||
* On a stream open for update, the next operation can be either a
|
||||
* read or a write.
|
||||
*/
|
||||
int platform_fseek(FILE *stream, long offset, int origin);
|
||||
|
||||
/*
|
||||
* Function: platform_ftell
|
||||
* Gets the current position of a file pointer
|
||||
*
|
||||
* Parameters:
|
||||
* stream - Pointer to stream
|
||||
*
|
||||
* Returns:
|
||||
* Current file position. May not reflect physical byte offset, e.g
|
||||
* systems where read-mode does carriage return-linefeed translation.
|
||||
* -1 value is used to indivate an error.
|
||||
*/
|
||||
long platform_ftell(FILE *stream);
|
||||
|
||||
/*
|
||||
* Function: platform_mkdir
|
||||
* Make a directory
|
||||
*
|
||||
* Parameters:
|
||||
* path - Path to create
|
||||
* mode - The mode of the directory (implementation defined)
|
||||
*
|
||||
* Returns:
|
||||
* 0 value. -1 value is used to indicate an error. On error no
|
||||
* directory shall be created.
|
||||
*
|
||||
* Remarks:
|
||||
* Shall create a new empty directory with with the name path specified
|
||||
* by argument `path.
|
||||
*/
|
||||
int platform_mkdir(const char *path, int mode);
|
||||
|
||||
/*
|
||||
* Function: platform_opendir
|
||||
* Open a directory
|
||||
*
|
||||
* Parameters:
|
||||
* path - Path to the directory to open
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to an object of type *DIR*. A null pointer value indicates
|
||||
* an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Shall open a directory stream corresponding to the directory named by
|
||||
* the `path` argument. The directory stream is positioned at the first entry.
|
||||
*/
|
||||
DIR *platform_opendir(const char *path);
|
||||
|
||||
/*
|
||||
* Function: platform_closedir
|
||||
* Close a directory stream
|
||||
*
|
||||
* Parameters:
|
||||
* dir - Pointer to directory stream
|
||||
*
|
||||
* Returns:
|
||||
* 0 value. A -1 value indicated an error.
|
||||
*
|
||||
* Remarks:
|
||||
* Shall close the directory stream referred to by the argument
|
||||
* `dir`. Upon return, the value of `dir` may no longer point to
|
||||
* an accessible object of the type *DIR*.
|
||||
*/
|
||||
int platform_closedir(DIR *dir);
|
||||
|
||||
/*
|
||||
* Function: platform_readdir
|
||||
* Read directory
|
||||
*
|
||||
* Parameters:
|
||||
* dir - Pointer to directory stream
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to an object of type `struct dirent`. A null pointer value
|
||||
* indicates an error.
|
||||
*
|
||||
* Remarks:
|
||||
* When the end of the directory is encountered, a null pointer is
|
||||
* returned.
|
||||
*/
|
||||
struct dirent *platform_readdir(DIR *dir);
|
||||
|
||||
/*
|
||||
* Function: platform_isatty
|
||||
* Determines whether a file descriptor is associated with a character
|
||||
* device.
|
||||
*
|
||||
* Returns:
|
||||
* A nonzero value if the descriptor is associated with a character
|
||||
* device. Otherwise `platform_isatty` returns 0.
|
||||
*/
|
||||
int platform_isatty(int fd);
|
||||
|
||||
#endif
|
90
test.c
90
test.c
|
@ -20,12 +20,12 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#define GMQCC_PLATFORM_HEADER /* TODO: eliminate! */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
#include "platform.h"
|
||||
|
||||
static const char *task_bins[] = {
|
||||
"./gmqcc",
|
||||
|
@ -53,15 +53,15 @@ static const char *task_bins[] = {
|
|||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
typedef struct {
|
||||
FILE *handles[3];
|
||||
int pipes [3];
|
||||
fs_file_t *handles[3];
|
||||
int pipes [3];
|
||||
|
||||
int stderr_fd;
|
||||
int stdout_fd;
|
||||
int pid;
|
||||
} popen_t;
|
||||
|
||||
static FILE ** task_popen(const char *command, const char *mode) {
|
||||
static fs_file_t **task_popen(const char *command, const char *mode) {
|
||||
int inhandle [2];
|
||||
int outhandle [2];
|
||||
int errhandle [2];
|
||||
|
@ -103,9 +103,9 @@ static FILE ** task_popen(const char *command, const char *mode) {
|
|||
data->pipes [1] = outhandle[0];
|
||||
data->pipes [2] = errhandle[0];
|
||||
|
||||
data->handles[0] = fdopen(inhandle [1], "w");
|
||||
data->handles[1] = fdopen(outhandle[0], mode);
|
||||
data->handles[2] = fdopen(errhandle[0], mode);
|
||||
data->handles[0] = (fs_file_t*)fdopen(inhandle [1], "w");
|
||||
data->handles[1] = (fs_file_t*)fdopen(outhandle[0], mode);
|
||||
data->handles[2] = (fs_file_t*)fdopen(errhandle[0], mode);
|
||||
|
||||
/* sigh */
|
||||
vec_free(argv);
|
||||
|
@ -137,7 +137,7 @@ task_popen_error_0:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int task_pclose(FILE **handles) {
|
||||
static int task_pclose(fs_file_t **handles) {
|
||||
popen_t *data = (popen_t*)handles;
|
||||
int status = 0;
|
||||
|
||||
|
@ -153,22 +153,17 @@ static int task_pclose(FILE **handles) {
|
|||
}
|
||||
#else
|
||||
typedef struct {
|
||||
FILE *handles[3];
|
||||
char name_err[L_tmpnam];
|
||||
char name_out[L_tmpnam];
|
||||
fs_file_t *handles[3];
|
||||
char name_err[L_tmpnam];
|
||||
char name_out[L_tmpnam];
|
||||
} popen_t;
|
||||
|
||||
static FILE **task_popen(const char *command, const char *mode) {
|
||||
static fs_file_t **task_popen(const char *command, const char *mode) {
|
||||
char *cmd = NULL;
|
||||
popen_t *open = (popen_t*)mem_a(sizeof(popen_t));
|
||||
|
||||
#ifndef _MSC_VER
|
||||
tmpnam(open->name_err);
|
||||
tmpnam(open->name_out);
|
||||
#else
|
||||
tmpnam_s(open->name_err, L_tmpnam);
|
||||
tmpnam_s(open->name_out, L_tmpnam);
|
||||
#endif
|
||||
util_tmpnam(open->name_err);
|
||||
util_tmpnam(open->name_out);
|
||||
|
||||
(void)mode; /* excluded */
|
||||
|
||||
|
@ -184,10 +179,12 @@ static int task_pclose(FILE **handles) {
|
|||
return open->handles;
|
||||
}
|
||||
|
||||
static int task_pclose(FILE **files) {
|
||||
static int task_pclose(fs_file_t **files) {
|
||||
popen_t *open = ((popen_t*)files);
|
||||
|
||||
fs_file_close(files[1]);
|
||||
fs_file_close(files[2]);
|
||||
|
||||
remove(open->name_err);
|
||||
remove(open->name_out);
|
||||
|
||||
|
@ -363,7 +360,7 @@ static bool task_template_generate(task_template_t *tmpl, char tag, const char *
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) {
|
||||
static bool task_template_parse(const char *file, task_template_t *tmpl, fs_file_t *fp, size_t *pad) {
|
||||
char *data = NULL;
|
||||
char *back = NULL;
|
||||
size_t size = 0;
|
||||
|
@ -373,7 +370,7 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *f
|
|||
return false;
|
||||
|
||||
/* top down parsing */
|
||||
while (fs_file_getline(&back, &size, fp) != EOF) {
|
||||
while (fs_file_getline(&back, &size, fp) != FS_FILE_EOF) {
|
||||
/* skip whitespace */
|
||||
data = back;
|
||||
if (*data && (*data == ' ' || *data == '\t'))
|
||||
|
@ -504,7 +501,7 @@ static task_template_t *task_template_compile(const char *file, const char *dir,
|
|||
/* a page should be enough */
|
||||
char fullfile[4096];
|
||||
size_t filepadd = 0;
|
||||
FILE *tempfile = NULL;
|
||||
fs_file_t *tempfile = NULL;
|
||||
task_template_t *tmpl = NULL;
|
||||
|
||||
util_snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file);
|
||||
|
@ -659,9 +656,9 @@ static void task_template_destroy(task_template_t *tmpl) {
|
|||
*/
|
||||
typedef struct {
|
||||
task_template_t *tmpl;
|
||||
FILE **runhandles;
|
||||
FILE *stderrlog;
|
||||
FILE *stdoutlog;
|
||||
fs_file_t **runhandles;
|
||||
fs_file_t *stderrlog;
|
||||
fs_file_t *stdoutlog;
|
||||
char *stdoutlogfile;
|
||||
char *stderrlogfile;
|
||||
bool compiled;
|
||||
|
@ -675,8 +672,8 @@ static task_t *task_tasks = NULL;
|
|||
*/
|
||||
static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
||||
bool success = true;
|
||||
DIR *dir;
|
||||
struct dirent *files;
|
||||
fs_dir_t *dir;
|
||||
fs_dirent_t *files;
|
||||
struct stat directory;
|
||||
char buffer[4096];
|
||||
size_t found = 0;
|
||||
|
@ -733,7 +730,7 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
if (strcmp(files->d_name + strlen(files->d_name) - 5, ".tmpl") == 0) {
|
||||
task_template_t *tmpl = task_template_compile(files->d_name, directories[i], pad);
|
||||
char buf[4096]; /* one page should be enough */
|
||||
char *qcflags = NULL;
|
||||
const char *qcflags = NULL;
|
||||
task_t task;
|
||||
|
||||
found ++;
|
||||
|
@ -754,16 +751,7 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
* to test compile flags for all tests. This needs to be
|
||||
* BEFORE other flags (so that the .tmpl can override them)
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
{
|
||||
char buffer[4096];
|
||||
size_t size;
|
||||
getenv_s(&size, buffer, sizeof(buffer), "QCFLAGS");
|
||||
qcflags = buffer;
|
||||
}
|
||||
#else
|
||||
qcflags = getenv("QCFLAGS");
|
||||
#endif
|
||||
qcflags = platform_getenv("QCFLAGS");
|
||||
|
||||
/*
|
||||
* Generate the command required to open a pipe to a process
|
||||
|
@ -881,9 +869,9 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
* left behind from a previous invoke of the test-suite.
|
||||
*/
|
||||
static void task_precleanup(const char *curdir) {
|
||||
DIR *dir;
|
||||
struct dirent *files;
|
||||
char buffer[4096];
|
||||
fs_dir_t *dir;
|
||||
fs_dirent_t *files;
|
||||
char buffer[4096];
|
||||
|
||||
dir = fs_dir_open(curdir);
|
||||
|
||||
|
@ -949,7 +937,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
bool success = true;
|
||||
bool process = true;
|
||||
int retval = EXIT_SUCCESS;
|
||||
FILE *execute;
|
||||
fs_file_t *execute;
|
||||
char buffer[4096];
|
||||
task_template_t *tmpl = task_tasks[i].tmpl;
|
||||
|
||||
|
@ -973,7 +961,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
);
|
||||
}
|
||||
|
||||
execute = popen(buffer, "r");
|
||||
execute = (fs_file_t*)popen(buffer, "r");
|
||||
if (!execute)
|
||||
return false;
|
||||
} else if (!strcmp(tmpl->proceduretype, "-pp")) {
|
||||
|
@ -1006,7 +994,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
size_t size = 0;
|
||||
size_t compare = 0;
|
||||
|
||||
while (fs_file_getline(&data, &size, execute) != EOF) {
|
||||
while (fs_file_getline(&data, &size, execute) != FS_FILE_EOF) {
|
||||
if (!strcmp(data, "No main function found\n")) {
|
||||
con_err("test failure: `%s` (No main function found) [%s]\n",
|
||||
tmpl->description,
|
||||
|
@ -1015,7 +1003,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
if (!process)
|
||||
fs_file_close(execute);
|
||||
else
|
||||
pclose(execute);
|
||||
pclose((FILE*)execute);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1075,7 +1063,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
}
|
||||
|
||||
if (process)
|
||||
retval = pclose(execute);
|
||||
retval = pclose((FILE*)execute);
|
||||
else
|
||||
fs_file_close(execute);
|
||||
|
||||
|
@ -1139,7 +1127,7 @@ static size_t task_schedualize(size_t *pad) {
|
|||
* Read data from stdout first and pipe that stuff into a log file
|
||||
* then we do the same for stderr.
|
||||
*/
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != FS_FILE_EOF) {
|
||||
fs_file_puts(task_tasks[i].stdoutlog, data);
|
||||
|
||||
if (strstr(data, "failed to open file")) {
|
||||
|
@ -1147,7 +1135,7 @@ static size_t task_schedualize(size_t *pad) {
|
|||
execute = false;
|
||||
}
|
||||
}
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != FS_FILE_EOF) {
|
||||
/*
|
||||
* If a string contains an error we just dissalow execution
|
||||
* of it in the vm.
|
||||
|
@ -1162,7 +1150,7 @@ static size_t task_schedualize(size_t *pad) {
|
|||
}
|
||||
|
||||
fs_file_puts (task_tasks[i].stderrlog, data);
|
||||
fflush(task_tasks[i].stderrlog); /* fast flush for read */
|
||||
fs_file_flush(task_tasks[i].stderrlog); /* fast flush for read */
|
||||
}
|
||||
|
||||
if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
|
||||
|
|
184
util.c
184
util.c
|
@ -21,10 +21,13 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#define GMQCC_PLATFORM_HEADER
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
#include "platform.h"
|
||||
|
||||
/*
|
||||
* Initially this was handled with a table in the gmqcc.h header, but
|
||||
|
@ -224,163 +227,64 @@ size_t util_optimizationtostr(const char *in, char *out, size_t outsz) {
|
|||
return util_strtransform(in, out, outsz, "_ ", 'a'-'A');
|
||||
}
|
||||
|
||||
/*
|
||||
* Portable implementation of vasprintf/asprintf. Assumes vsnprintf
|
||||
* exists, otherwise compiler error.
|
||||
*
|
||||
* TODO: fix for MSVC ....
|
||||
*/
|
||||
int util_vasprintf(char **dat, const char *fmt, va_list args) {
|
||||
int ret;
|
||||
int len;
|
||||
char *tmp = NULL;
|
||||
int util_snprintf(char *str, size_t size, const char *fmt, ...) {
|
||||
va_list arg;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* For visual studio _vsnprintf doesn't tell you the length of a
|
||||
* formatted string if it overflows. However there is a MSVC
|
||||
* intrinsic (which is documented wrong) called _vcsprintf which
|
||||
* will return the required amount to allocate.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
if ((len = _vscprintf(fmt, args)) < 0) {
|
||||
*dat = NULL;
|
||||
return -1;
|
||||
}
|
||||
va_start(arg, fmt);
|
||||
ret = platform_vsnprintf(str, size, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
tmp = (char*)mem_a(len + 1);
|
||||
if ((ret = _vsnprintf_s(tmp, len+1, len+1, fmt, args)) != len) {
|
||||
mem_d(tmp);
|
||||
*dat = NULL;
|
||||
return -1;
|
||||
}
|
||||
*dat = tmp;
|
||||
return len;
|
||||
#else
|
||||
/*
|
||||
* For everything else we have a decent conforming vsnprintf that
|
||||
* returns the number of bytes needed. We give it a try though on
|
||||
* a short buffer, since efficiently speaking, it could be nice to
|
||||
* above a second vsnprintf call.
|
||||
*/
|
||||
char buf[128];
|
||||
va_list cpy;
|
||||
va_copy(cpy, args);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, cpy);
|
||||
va_end (cpy);
|
||||
|
||||
if (len < (int)sizeof(buf)) {
|
||||
*dat = util_strdup(buf);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* not large enough ... */
|
||||
tmp = (char*)mem_a(len + 1);
|
||||
if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
|
||||
mem_d(tmp);
|
||||
*dat = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dat = tmp;
|
||||
return len;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int util_asprintf(char **ret, const char *fmt, ...) {
|
||||
va_list args;
|
||||
int read;
|
||||
|
||||
va_start(args, fmt);
|
||||
read = util_vasprintf(ret, fmt, args);
|
||||
read = platform_vasprintf(ret, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are various re-implementations (wrapping the real ones) of
|
||||
* string functions that MSVC considers unsafe. We wrap these up and
|
||||
* use the safe variations on MSVC.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
static char **util_strerror_allocated() {
|
||||
static char **data = NULL;
|
||||
return data;
|
||||
}
|
||||
int util_sscanf(const char *str, const char *format, ...) {
|
||||
va_list args;
|
||||
int read;
|
||||
|
||||
static void util_strerror_cleanup(void) {
|
||||
size_t i;
|
||||
char **data = util_strerror_allocated();
|
||||
for (i = 0; i < vec_size(data); i++)
|
||||
mem_d(data[i]);
|
||||
vec_free(data);
|
||||
}
|
||||
va_start(args, format);
|
||||
read = platform_vsscanf(str, format, args);
|
||||
va_end(args);
|
||||
|
||||
const char *util_strerror(int num) {
|
||||
char *allocated = NULL;
|
||||
static bool install = false;
|
||||
static size_t tries = 0;
|
||||
char **vector = util_strerror_allocated();
|
||||
return read;
|
||||
}
|
||||
|
||||
/* try installing cleanup handler */
|
||||
while (!install) {
|
||||
if (tries == 32)
|
||||
return "(unknown)";
|
||||
char *util_strncpy(char *dest, const char *src, size_t n) {
|
||||
return platform_strncpy(dest, src, n);
|
||||
}
|
||||
char *util_strncat(char *dest, const char *src, size_t n) {
|
||||
return platform_strncat(dest, src, n);
|
||||
}
|
||||
char *util_strcat(char *dest, const char *src) {
|
||||
return platform_strcat(dest, src);
|
||||
}
|
||||
const char *util_strerror(int err) {
|
||||
return platform_strerror(err);
|
||||
}
|
||||
|
||||
install = !atexit(&util_strerror_cleanup);
|
||||
tries ++;
|
||||
}
|
||||
|
||||
allocated = (char*)mem_a(4096); /* A page must be enough */
|
||||
strerror_s(allocated, 4096, num);
|
||||
|
||||
vec_push(vector, allocated);
|
||||
return (const char *)allocated;
|
||||
}
|
||||
|
||||
int util_snprintf(char *src, size_t bytes, const char *format, ...) {
|
||||
int rt;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
|
||||
rt = vsprintf_s(src, bytes, format, va);
|
||||
va_end (va);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
char *util_strcat(char *dest, const char *src) {
|
||||
strcat_s(dest, strlen(src), src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *util_strncpy(char *dest, const char *src, size_t num) {
|
||||
strncpy_s(dest, num, src, num);
|
||||
return dest;
|
||||
}
|
||||
#else
|
||||
const char *util_strerror(int num) {
|
||||
return strerror(num);
|
||||
}
|
||||
|
||||
int util_snprintf(char *src, size_t bytes, const char *format, ...) {
|
||||
int rt;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
rt = vsnprintf(src, bytes, format, va);
|
||||
va_end (va);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
char *util_strcat(char *dest, const char *src) {
|
||||
return strcat(dest, src);
|
||||
}
|
||||
|
||||
char *util_strncpy(char *dest, const char *src, size_t num) {
|
||||
return strncpy(dest, src, num);
|
||||
}
|
||||
|
||||
#endif /*! _MSC_VER */
|
||||
const struct tm *util_localtime(const time_t *timer) {
|
||||
return platform_localtime(timer);
|
||||
}
|
||||
const char *util_ctime(const time_t *timer) {
|
||||
return platform_ctime(timer);
|
||||
}
|
||||
|
||||
bool util_isatty(fs_file_t *file) {
|
||||
if (file == (fs_file_t*)stdout) return !!platform_isatty(STDOUT_FILENO);
|
||||
if (file == (fs_file_t*)stderr) return !!platform_isatty(STDERR_FILENO);
|
||||
return false;
|
||||
}
|
||||
|
||||
void util_seed(uint32_t value) {
|
||||
srand((int)value);
|
||||
|
|
Loading…
Reference in a new issue