mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-22 10:41:43 +00:00
Major cleanup of platform/fs stuff
This commit is contained in:
parent
5b9e0a62ab
commit
2c421c3b71
15 changed files with 207 additions and 1055 deletions
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
|||
CC ?= clang
|
||||
CFLAGS = -MD -Wall -Wextra -pedantic-errors
|
||||
CFLAGS = -MD -std=gnu99 -Wall -Wextra -pedantic-errors -g3
|
||||
LDFLAGS = -lm
|
||||
|
||||
CSRCS = ansi.c ast.c code.c conout.c fold.c fs.c ftepp.c hash.c intrin.c ir.c lexer.c main.c opts.c parser.c stat.c utf8.c util.c
|
||||
|
|
110
ansi.c
110
ansi.c
|
@ -20,37 +20,12 @@
|
|||
* 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"
|
||||
#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_getenv(const char *var) {
|
||||
return getenv(var);
|
||||
}
|
||||
|
||||
int platform_vasprintf(char **dat, const char *fmt, va_list args) {
|
||||
int ret;
|
||||
int len;
|
||||
|
@ -80,88 +55,3 @@ int platform_vasprintf(char **dat, const char *fmt, va_list args) {
|
|||
*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);
|
||||
}
|
||||
|
|
42
code.c
42
code.c
|
@ -393,14 +393,14 @@ 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;
|
||||
fs_file_t *fp = NULL;
|
||||
FILE *fp = NULL;
|
||||
|
||||
code_create_header(code, &code_header, filename, lnofile);
|
||||
|
||||
if (lnofile) {
|
||||
uint32_t version = 1;
|
||||
|
||||
fp = fs_file_open(lnofile, "wb");
|
||||
fp = fopen(lnofile, "wb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
|
@ -408,39 +408,39 @@ bool code_write(code_t *code, const char *filename, const char *lnofile) {
|
|||
util_endianswap(code->linenums, vec_size(code->linenums), sizeof(code->linenums[0]));
|
||||
util_endianswap(code->columnnums, vec_size(code->columnnums), sizeof(code->columnnums[0]));
|
||||
|
||||
if (fs_file_write("LNOF", 4, 1, fp) != 1 ||
|
||||
fs_file_write(&version, sizeof(version), 1, fp) != 1 ||
|
||||
fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
|
||||
fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
|
||||
fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
|
||||
fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
|
||||
fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums) ||
|
||||
fs_file_write(code->columnnums, sizeof(code->columnnums[0]), vec_size(code->columnnums), fp) != vec_size(code->columnnums))
|
||||
if (fwrite("LNOF", 4, 1, fp) != 1 ||
|
||||
fwrite(&version, sizeof(version), 1, fp) != 1 ||
|
||||
fwrite(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 ||
|
||||
fwrite(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 ||
|
||||
fwrite(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 ||
|
||||
fwrite(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 ||
|
||||
fwrite(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums) ||
|
||||
fwrite(code->columnnums, sizeof(code->columnnums[0]), vec_size(code->columnnums), fp) != vec_size(code->columnnums))
|
||||
{
|
||||
con_err("failed to write lno file\n");
|
||||
}
|
||||
|
||||
fs_file_close(fp);
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
fp = fs_file_open(filename, "wb");
|
||||
fp = fopen(filename, "wb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
if (1 != fs_file_write(&code_header, sizeof(prog_header_t) , 1 , fp) ||
|
||||
vec_size(code->statements) != fs_file_write(code->statements, sizeof(prog_section_statement_t), vec_size(code->statements), fp) ||
|
||||
vec_size(code->defs) != fs_file_write(code->defs, sizeof(prog_section_def_t) , vec_size(code->defs) , fp) ||
|
||||
vec_size(code->fields) != fs_file_write(code->fields, sizeof(prog_section_field_t) , vec_size(code->fields) , fp) ||
|
||||
vec_size(code->functions) != fs_file_write(code->functions, sizeof(prog_section_function_t) , vec_size(code->functions) , fp) ||
|
||||
vec_size(code->globals) != fs_file_write(code->globals, sizeof(int32_t) , vec_size(code->globals) , fp) ||
|
||||
vec_size(code->chars) != fs_file_write(code->chars, 1 , vec_size(code->chars) , fp))
|
||||
if (1 != fwrite(&code_header, sizeof(prog_header_t) , 1 , fp) ||
|
||||
vec_size(code->statements) != fwrite(code->statements, sizeof(prog_section_statement_t), vec_size(code->statements), fp) ||
|
||||
vec_size(code->defs) != fwrite(code->defs, sizeof(prog_section_def_t) , vec_size(code->defs) , fp) ||
|
||||
vec_size(code->fields) != fwrite(code->fields, sizeof(prog_section_field_t) , vec_size(code->fields) , fp) ||
|
||||
vec_size(code->functions) != fwrite(code->functions, sizeof(prog_section_function_t) , vec_size(code->functions) , fp) ||
|
||||
vec_size(code->globals) != fwrite(code->globals, sizeof(int32_t) , vec_size(code->globals) , fp) ||
|
||||
vec_size(code->chars) != fwrite(code->chars, 1 , vec_size(code->chars) , fp))
|
||||
{
|
||||
fs_file_close(fp);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
fs_file_close(fp);
|
||||
fclose(fp);
|
||||
code_stats(filename, lnofile, code, &code_header);
|
||||
return true;
|
||||
}
|
||||
|
|
84
conout.c
84
conout.c
|
@ -23,21 +23,17 @@
|
|||
#include <stdio.h>
|
||||
#include "gmqcc.h"
|
||||
|
||||
#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_STDOUT(X) ((X) == stdout)
|
||||
#define GMQCC_IS_STDERR(X) ((X) == stderr)
|
||||
#define GMQCC_IS_DEFINE(X) (GMQCC_IS_STDERR(X) || GMQCC_IS_STDOUT(X))
|
||||
|
||||
typedef struct {
|
||||
fs_file_t *handle_err;
|
||||
fs_file_t *handle_out;
|
||||
int color_err;
|
||||
int color_out;
|
||||
FILE *handle_err;
|
||||
FILE *handle_out;
|
||||
int color_err;
|
||||
int color_out;
|
||||
} con_t;
|
||||
|
||||
/*
|
||||
* We use standard files as default. These can be changed at any time
|
||||
* with con_change(F, F)
|
||||
*/
|
||||
static con_t console;
|
||||
|
||||
/*
|
||||
|
@ -58,8 +54,8 @@ static void con_enablecolor(void) {
|
|||
* arguments. This colorizes for windows as well via translate
|
||||
* step.
|
||||
*/
|
||||
static int con_write(fs_file_t *handle, const char *fmt, va_list va) {
|
||||
return vfprintf((FILE*)handle, fmt, va);
|
||||
static int con_write(FILE *handle, const char *fmt, va_list va) {
|
||||
return vfprintf(handle, fmt, va);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -68,9 +64,9 @@ static int con_write(fs_file_t *handle, const char *fmt, va_list va) {
|
|||
|
||||
void con_close() {
|
||||
if (!GMQCC_IS_DEFINE(console.handle_err))
|
||||
fs_file_close(console.handle_err);
|
||||
fclose(console.handle_err);
|
||||
if (!GMQCC_IS_DEFINE(console.handle_out))
|
||||
fs_file_close(console.handle_out);
|
||||
fclose(console.handle_out);
|
||||
}
|
||||
|
||||
void con_color(int state) {
|
||||
|
@ -83,54 +79,26 @@ void con_color(int state) {
|
|||
}
|
||||
|
||||
void con_init() {
|
||||
console.handle_err = (fs_file_t*)stderr;
|
||||
console.handle_out = (fs_file_t*)stdout;
|
||||
console.handle_err = stderr;
|
||||
console.handle_out = stdout;
|
||||
con_enablecolor();
|
||||
}
|
||||
|
||||
void con_reset() {
|
||||
con_close();
|
||||
con_init ();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is clever, say you want to change the console to use two
|
||||
* files for out/err. You pass in two strings, it will properly
|
||||
* close the existing handles (if they're not std* handles) and
|
||||
* open them. Now say you want TO use stdout and stderr, this
|
||||
* allows you to do that so long as you cast them to (char*).
|
||||
* Say you need stdout for out, but want a file for error, you can
|
||||
* do this too, just cast the stdout for (char*) and stick to a
|
||||
* string for the error file.
|
||||
*/
|
||||
int con_change(const char *out, const char *err) {
|
||||
con_close();
|
||||
|
||||
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 = (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 = (fs_file_t*)(GMQCC_IS_STDOUT(err) ? stdout : stderr);
|
||||
con_enablecolor();
|
||||
} else if (!(console.handle_err = fs_file_open(err, "w"))) return 0;
|
||||
|
||||
return 1;
|
||||
con_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Defaultizer because stdio.h shouldn't be used anywhere except here
|
||||
* and inside file.c To prevent mis-match of wrapper-interfaces.
|
||||
*/
|
||||
fs_file_t *con_default_out() {
|
||||
return (fs_file_t*)(console.handle_out = (fs_file_t*)stdout);
|
||||
FILE *con_default_out() {
|
||||
return console.handle_out = stdout;
|
||||
}
|
||||
fs_file_t *con_default_err() {
|
||||
return (fs_file_t*)(console.handle_err = (fs_file_t*)stderr);
|
||||
|
||||
FILE *con_default_err() {
|
||||
return console.handle_err = stderr;
|
||||
}
|
||||
|
||||
int con_verr(const char *fmt, va_list va) {
|
||||
|
@ -145,20 +113,20 @@ int con_vout(const char *fmt, va_list va) {
|
|||
* to be used.
|
||||
*/
|
||||
int con_err(const char *fmt, ...) {
|
||||
va_list va;
|
||||
int ln = 0;
|
||||
va_list va;
|
||||
int ln = 0;
|
||||
va_start(va, fmt);
|
||||
con_verr(fmt, va);
|
||||
va_end (va);
|
||||
return ln;
|
||||
va_end(va);
|
||||
return ln;
|
||||
}
|
||||
int con_out(const char *fmt, ...) {
|
||||
va_list va;
|
||||
int ln = 0;
|
||||
va_list va;
|
||||
int ln = 0;
|
||||
va_start(va, fmt);
|
||||
con_vout(fmt, va);
|
||||
va_end (va);
|
||||
return ln;
|
||||
va_end (va);
|
||||
return ln;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
20
exec.c
20
exec.c
|
@ -56,7 +56,7 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
|
|||
prog_header_t header;
|
||||
qc_program_t *prog;
|
||||
size_t i;
|
||||
fs_file_t *file = fs_file_open(filename, "rb");
|
||||
FILE *file = fopen(filename, "rb");
|
||||
|
||||
/* we need all those in order to support INSTR_STATE: */
|
||||
bool has_self = false,
|
||||
|
@ -68,9 +68,9 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
|
|||
if (!file)
|
||||
return NULL;
|
||||
|
||||
if (fs_file_read(&header, sizeof(header), 1, file) != 1) {
|
||||
if (fread(&header, sizeof(header), 1, file) != 1) {
|
||||
loaderror("failed to read header from '%s'", filename);
|
||||
fs_file_close(file);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -78,13 +78,13 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
|
|||
|
||||
if (!skipversion && header.version != 6) {
|
||||
loaderror("header says this is a version %i progs, we need version 6\n", header.version);
|
||||
fs_file_close(file);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prog = (qc_program_t*)mem_a(sizeof(qc_program_t));
|
||||
if (!prog) {
|
||||
fs_file_close(file);
|
||||
fclose(file);
|
||||
fprintf(stderr, "failed to allocate program data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -100,11 +100,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 (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
|
||||
loaderror("seek failed"); \
|
||||
goto error; \
|
||||
} \
|
||||
if (fs_file_read ( \
|
||||
if (fread( \
|
||||
vec_add(prog->progvar, header.hdrvar.length + reserved), \
|
||||
sizeof(*prog->progvar), \
|
||||
header.hdrvar.length, \
|
||||
|
@ -130,7 +130,7 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
|
|||
util_swap_functions (prog->functions);
|
||||
util_swap_globals (prog->globals);
|
||||
|
||||
fs_file_close(file);
|
||||
fclose(file);
|
||||
|
||||
/* profile counters */
|
||||
memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code));
|
||||
|
@ -190,7 +190,7 @@ error:
|
|||
vec_free(prog->entitypool);
|
||||
mem_d(prog);
|
||||
|
||||
fs_file_close(file);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,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((fs_file_t*)stdout, spaces);
|
||||
fputs(spaces, stdout);
|
||||
spaces[sizeof(spaces)-1-len] = ' ';
|
||||
}
|
||||
}
|
||||
|
|
89
fs.c
89
fs.c
|
@ -20,76 +20,9 @@
|
|||
* 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"
|
||||
|
||||
fs_file_t *fs_file_open(const char *filename, const char *mode) {
|
||||
return (fs_file_t*)platform_fopen(filename, mode);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
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,
|
||||
fs_file_t *fp
|
||||
) {
|
||||
return platform_fwrite(buffer, size, count, (FILE*)fp);
|
||||
}
|
||||
|
||||
int fs_file_error(fs_file_t *fp) {
|
||||
return platform_ferror((FILE*)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(fs_file_t *fp, const char *str) {
|
||||
return platform_fputs(str, (FILE*)fp);
|
||||
}
|
||||
|
||||
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(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, fs_file_t *stream) {
|
||||
int fs_file_getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
int chr;
|
||||
int ret;
|
||||
char *pos;
|
||||
|
@ -105,7 +38,7 @@ int fs_file_getline(char **lineptr, size_t *n, fs_file_t *stream) {
|
|||
pos = *lineptr;
|
||||
|
||||
for (;;) {
|
||||
int c = fs_file_getc(stream);
|
||||
int c = getc(stream);
|
||||
|
||||
if (chr < 2) {
|
||||
*n += (*n > 16) ? *n : 64;
|
||||
|
@ -115,7 +48,7 @@ int fs_file_getline(char **lineptr, size_t *n, fs_file_t *stream) {
|
|||
pos = *n - chr + *lineptr;
|
||||
}
|
||||
|
||||
if (fs_file_error(stream))
|
||||
if (ferror(stream))
|
||||
return -1;
|
||||
if (c == EOF) {
|
||||
if (pos == *lineptr)
|
||||
|
@ -132,19 +65,3 @@ int fs_file_getline(char **lineptr, size_t *n, fs_file_t *stream) {
|
|||
*pos = '\0';
|
||||
return (ret = pos - *lineptr);
|
||||
}
|
||||
|
||||
int fs_dir_make(const char *path) {
|
||||
return platform_mkdir(path, 0700);
|
||||
}
|
||||
|
||||
fs_dir_t *fs_dir_open(const char *name) {
|
||||
return (fs_dir_t*)platform_opendir(name);
|
||||
}
|
||||
|
||||
int fs_dir_close(fs_dir_t *dir) {
|
||||
return platform_closedir((DIR*)dir);
|
||||
}
|
||||
|
||||
fs_dirent_t *fs_dir_read(fs_dir_t *dir) {
|
||||
return (fs_dirent_t*)platform_readdir((DIR*)dir);
|
||||
}
|
||||
|
|
6
ftepp.c
6
ftepp.c
|
@ -1323,7 +1323,7 @@ static void unescape(const char *str, char *out) {
|
|||
|
||||
static char *ftepp_include_find_path(const char *file, const char *pathfile)
|
||||
{
|
||||
fs_file_t *fp;
|
||||
FILE *fp;
|
||||
char *filename = NULL;
|
||||
const char *last_slash;
|
||||
size_t len;
|
||||
|
@ -1343,9 +1343,9 @@ static char *ftepp_include_find_path(const char *file, const char *pathfile)
|
|||
memcpy(vec_add(filename, len+1), file, len);
|
||||
vec_last(filename) = 0;
|
||||
|
||||
fp = fs_file_open(filename, "rb");
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp) {
|
||||
fs_file_close(fp);
|
||||
fclose(fp);
|
||||
return filename;
|
||||
}
|
||||
vec_free(filename);
|
||||
|
|
39
gmqcc.h
39
gmqcc.h
|
@ -26,6 +26,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define GMQCC_VERSION_MAJOR 0
|
||||
|
@ -233,9 +234,7 @@ 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 *);
|
||||
bool util_isatty(FILE *);
|
||||
size_t hash(const char *key);
|
||||
|
||||
/*
|
||||
|
@ -326,34 +325,7 @@ int util_snprintf(char *str, size_t, const char *fmt, ...);
|
|||
|
||||
|
||||
/* 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 *);
|
||||
|
||||
int fs_dir_make (const char *);
|
||||
fs_dir_t *fs_dir_open (const char *);
|
||||
int fs_dir_close (fs_dir_t *);
|
||||
fs_dirent_t *fs_dir_read (fs_dir_t *);
|
||||
int fs_file_getline(char **, size_t *, FILE *);
|
||||
|
||||
/* code.c */
|
||||
|
||||
|
@ -676,8 +648,8 @@ enum {
|
|||
LVL_ERROR
|
||||
};
|
||||
|
||||
fs_file_t *con_default_out(void);
|
||||
fs_file_t *con_default_err(void);
|
||||
FILE *con_default_out(void);
|
||||
FILE *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, ...);
|
||||
|
@ -688,7 +660,6 @@ void con_close (void);
|
|||
void con_init (void);
|
||||
void con_reset (void);
|
||||
void con_color (int);
|
||||
int con_change(const char *, const char *);
|
||||
int con_verr (const char *, va_list);
|
||||
int con_vout (const char *, va_list);
|
||||
int con_err (const char *, ...);
|
||||
|
|
46
lexer.c
46
lexer.c
|
@ -99,7 +99,7 @@ static int lex_getch(lex_file *lex);
|
|||
lex_file* lex_open(const char *file)
|
||||
{
|
||||
lex_file *lex;
|
||||
fs_file_t *in = fs_file_open(file, "rb");
|
||||
FILE *in = fopen(file, "rb");
|
||||
uint32_t read;
|
||||
|
||||
if (!in) {
|
||||
|
@ -109,7 +109,7 @@ lex_file* lex_open(const char *file)
|
|||
|
||||
lex = (lex_file*)mem_a(sizeof(*lex));
|
||||
if (!lex) {
|
||||
fs_file_close(in);
|
||||
fclose(in);
|
||||
lexerror(NULL, "out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ void lex_close(lex_file *lex)
|
|||
vec_free(lex->modelname);
|
||||
|
||||
if (lex->file)
|
||||
fs_file_close(lex->file);
|
||||
fclose(lex->file);
|
||||
|
||||
vec_free(lex->tok.value);
|
||||
|
||||
|
@ -201,15 +201,15 @@ static int lex_fgetc(lex_file *lex)
|
|||
{
|
||||
if (lex->file) {
|
||||
lex->column++;
|
||||
return fs_file_getc(lex->file);
|
||||
return fgetc(lex->file);
|
||||
}
|
||||
if (lex->open_string) {
|
||||
if (lex->open_string_pos >= lex->open_string_length)
|
||||
return FS_FILE_EOF;
|
||||
return EOF;
|
||||
lex->column++;
|
||||
return lex->open_string[lex->open_string_pos++];
|
||||
}
|
||||
return FS_FILE_EOF;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Get or put-back data
|
||||
|
@ -424,7 +424,7 @@ static bool lex_try_pragma(lex_file *lex)
|
|||
goto unroll;
|
||||
|
||||
lex->line = line;
|
||||
while (ch != '\n' && ch != FS_FILE_EOF)
|
||||
while (ch != '\n' && ch != EOF)
|
||||
ch = lex_getch(lex);
|
||||
vec_free(command);
|
||||
vec_free(param);
|
||||
|
@ -504,7 +504,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
do
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
while (ch != FS_FILE_EOF && util_isspace(ch)) {
|
||||
while (ch != EOF && util_isspace(ch)) {
|
||||
if (ch == '\n') {
|
||||
if (lex_try_pragma(lex))
|
||||
continue;
|
||||
|
@ -540,7 +540,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
lex_tokench(lex, ' ');
|
||||
}
|
||||
|
||||
while (ch != FS_FILE_EOF && ch != '\n') {
|
||||
while (ch != EOF && ch != '\n') {
|
||||
if (lex->flags.preprocessing)
|
||||
lex_tokench(lex, ' '); /* ch); */
|
||||
ch = lex_getch(lex);
|
||||
|
@ -561,7 +561,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
lex_tokench(lex, ' ');
|
||||
}
|
||||
|
||||
while (ch != FS_FILE_EOF)
|
||||
while (ch != EOF)
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
if (ch == '*') {
|
||||
|
@ -590,7 +590,7 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
|
|||
ch = '/';
|
||||
break;
|
||||
}
|
||||
} while (ch != FS_FILE_EOF && util_isspace(ch));
|
||||
} while (ch != EOF && util_isspace(ch));
|
||||
|
||||
if (haswhite) {
|
||||
lex_endtoken(lex);
|
||||
|
@ -606,7 +606,7 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
|
|||
int ch;
|
||||
|
||||
ch = lex_getch(lex);
|
||||
while (ch != FS_FILE_EOF && isident(ch))
|
||||
while (ch != EOF && isident(ch))
|
||||
{
|
||||
lex_tokench(lex, ch);
|
||||
ch = lex_getch(lex);
|
||||
|
@ -626,7 +626,7 @@ static int lex_parse_frame(lex_file *lex)
|
|||
lex_token_new(lex);
|
||||
|
||||
ch = lex_getch(lex);
|
||||
while (ch != FS_FILE_EOF && ch != '\n' && util_isspace(ch))
|
||||
while (ch != EOF && ch != '\n' && util_isspace(ch))
|
||||
ch = lex_getch(lex);
|
||||
|
||||
if (ch == '\n')
|
||||
|
@ -688,7 +688,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 != FS_FILE_EOF)
|
||||
while (ch != EOF)
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
if (ch == quote)
|
||||
|
@ -697,18 +697,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 == FS_FILE_EOF) {
|
||||
if (ch == EOF) {
|
||||
lexerror(lex, "unexpected end of file");
|
||||
lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
|
||||
lex_ungetch(lex, 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 == FS_FILE_EOF) {
|
||||
if (ch == EOF) {
|
||||
lexerror(lex, "unexpected end of file");
|
||||
lex_ungetch(lex, FS_FILE_EOF); /* next token to be TOKEN_EOF */
|
||||
lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
|
||||
return (lex->tok.ttype = TOKEN_ERROR);
|
||||
}
|
||||
|
||||
|
@ -846,7 +846,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, FS_FILE_EOF); /* next token to be TOKEN_EOF */
|
||||
lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
|
||||
return (lex->tok.ttype = TOKEN_ERROR);
|
||||
}
|
||||
|
||||
|
@ -963,7 +963,7 @@ int lex_do(lex_file *lex)
|
|||
if (lex->eof)
|
||||
return (lex->tok.ttype = TOKEN_FATAL);
|
||||
|
||||
if (ch == FS_FILE_EOF) {
|
||||
if (ch == EOF) {
|
||||
lex->eof = true;
|
||||
return (lex->tok.ttype = TOKEN_EOF);
|
||||
}
|
||||
|
@ -1000,7 +1000,7 @@ int lex_do(lex_file *lex)
|
|||
if (!strcmp(v, "framevalue"))
|
||||
{
|
||||
ch = lex_getch(lex);
|
||||
while (ch != FS_FILE_EOF && util_isspace(ch) && ch != '\n')
|
||||
while (ch != EOF && util_isspace(ch) && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
|
||||
if (!util_isdigit(ch)) {
|
||||
|
@ -1080,7 +1080,7 @@ int lex_do(lex_file *lex)
|
|||
vec_free(lex->frames);
|
||||
/* skip line (fteqcc does it too) */
|
||||
ch = lex_getch(lex);
|
||||
while (ch != FS_FILE_EOF && ch != '\n')
|
||||
while (ch != EOF && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
@ -1094,7 +1094,7 @@ int lex_do(lex_file *lex)
|
|||
{
|
||||
/* skip line */
|
||||
ch = lex_getch(lex);
|
||||
while (ch != FS_FILE_EOF && ch != '\n')
|
||||
while (ch != EOF && ch != '\n')
|
||||
ch = lex_getch(lex);
|
||||
return lex_do(lex);
|
||||
}
|
||||
|
|
2
lexer.h
2
lexer.h
|
@ -107,7 +107,7 @@ typedef struct {
|
|||
} frame_macro;
|
||||
|
||||
typedef struct lex_file_s {
|
||||
fs_file_t *file;
|
||||
FILE *file;
|
||||
const char *open_string;
|
||||
size_t open_string_length;
|
||||
size_t open_string_pos;
|
||||
|
|
22
main.c
22
main.c
|
@ -223,14 +223,6 @@ static bool options_parse(int argc, char **argv) {
|
|||
opts_set(opts.flags, EMULATE_STATE, true);
|
||||
continue;
|
||||
}
|
||||
if (options_long_gcc("redirout", &argc, &argv, &redirout)) {
|
||||
con_change(redirout, redirerr);
|
||||
continue;
|
||||
}
|
||||
if (options_long_gcc("redirerr", &argc, &argv, &redirerr)) {
|
||||
con_change(redirout, redirerr);
|
||||
continue;
|
||||
}
|
||||
if (options_long_gcc("config", &argc, &argv, &argarg)) {
|
||||
config = argarg;
|
||||
continue;
|
||||
|
@ -532,7 +524,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, fs_file_t *src) {
|
||||
static bool progs_nextline(char **out, size_t *alen, FILE *src) {
|
||||
int len;
|
||||
char *line;
|
||||
char *start;
|
||||
|
@ -562,7 +554,7 @@ int main(int argc, char **argv) {
|
|||
int retval = 0;
|
||||
bool operators_free = false;
|
||||
bool progs_src = false;
|
||||
fs_file_t *outfile = NULL;
|
||||
FILE *outfile = NULL;
|
||||
struct parser_s *parser = NULL;
|
||||
struct ftepp_s *ftepp = NULL;
|
||||
|
||||
|
@ -626,7 +618,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) {
|
||||
if (opts_output_wasset) {
|
||||
outfile = fs_file_open(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
|
||||
outfile = fopen(OPTS_OPTION_STR(OPTION_OUTPUT), "wb");
|
||||
if (!outfile) {
|
||||
con_err("failed to open `%s` for writing\n", OPTS_OPTION_STR(OPTION_OUTPUT));
|
||||
retval = 1;
|
||||
|
@ -667,14 +659,14 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (!vec_size(items)) {
|
||||
fs_file_t *src;
|
||||
FILE *src;
|
||||
char *line = NULL;
|
||||
size_t linelen = 0;
|
||||
bool hasline = false;
|
||||
|
||||
progs_src = true;
|
||||
|
||||
src = fs_file_open(OPTS_OPTION_STR(OPTION_PROGSRC), "rb");
|
||||
src = fopen(OPTS_OPTION_STR(OPTION_PROGSRC), "rb");
|
||||
if (!src) {
|
||||
con_err("failed to open `%s` for reading\n", OPTS_OPTION_STR(OPTION_PROGSRC));
|
||||
retval = 1;
|
||||
|
@ -697,7 +689,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
fs_file_close(src);
|
||||
fclose(src);
|
||||
mem_d(line);
|
||||
}
|
||||
|
||||
|
@ -729,7 +721,7 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
out = ftepp_get(ftepp);
|
||||
if (out)
|
||||
fs_file_printf(outfile, "%s", out);
|
||||
fprintf(outfile, "%s", out);
|
||||
ftepp_flush(ftepp);
|
||||
}
|
||||
else {
|
||||
|
|
18
opts.c
18
opts.c
|
@ -216,7 +216,7 @@ static char *opts_ini_next(const char *s, char c) {
|
|||
}
|
||||
|
||||
static size_t opts_ini_parse (
|
||||
fs_file_t *filehandle,
|
||||
FILE *filehandle,
|
||||
char *(*loadhandle)(const char *, const char *, const char *, char **),
|
||||
char **errorhandle,
|
||||
char **parse_file
|
||||
|
@ -234,7 +234,7 @@ static size_t opts_ini_parse (
|
|||
char *read_name;
|
||||
char *read_value;
|
||||
|
||||
while (fs_file_getline(&line, &linesize, filehandle) != FS_FILE_EOF) {
|
||||
while (fs_file_getline(&line, &linesize, filehandle) != EOF) {
|
||||
parse_beg = line;
|
||||
|
||||
/* handle BOM */
|
||||
|
@ -330,7 +330,7 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
|
|||
if (!strcmp(section, "includes")) {
|
||||
static const char *include_error_beg = "failed to open file `";
|
||||
static const char *include_error_end = "' for inclusion";
|
||||
fs_file_t *file = fs_file_open(value, "r");
|
||||
FILE *file = fopen(value, "r");
|
||||
found = true;
|
||||
if (!file) {
|
||||
vec_append(error, strlen(include_error_beg), include_error_beg);
|
||||
|
@ -342,7 +342,7 @@ static char *opts_ini_load(const char *section, const char *name, const char *va
|
|||
/* Change the file name */
|
||||
mem_d(*parse_file);
|
||||
*parse_file = util_strdup(value);
|
||||
fs_file_close(file);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,15 +423,15 @@ void opts_ini_init(const char *file) {
|
|||
char *error = NULL;
|
||||
char *parse_file = NULL;
|
||||
size_t line;
|
||||
fs_file_t *ini;
|
||||
FILE *ini;
|
||||
|
||||
if (!file) {
|
||||
/* try ini */
|
||||
if (!(ini = fs_file_open((file = "gmqcc.ini"), "r")))
|
||||
if (!(ini = fopen((file = "gmqcc.ini"), "r")))
|
||||
/* try cfg */
|
||||
if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r")))
|
||||
if (!(ini = fopen((file = "gmqcc.cfg"), "r")))
|
||||
return;
|
||||
} else if (!(ini = fs_file_open(file, "r")))
|
||||
} else if (!(ini = fopen(file, "r")))
|
||||
return;
|
||||
|
||||
con_out("found ini file `%s`\n", file);
|
||||
|
@ -444,5 +444,5 @@ void opts_ini_init(const char *file) {
|
|||
}
|
||||
mem_d(parse_file);
|
||||
|
||||
fs_file_close(ini);
|
||||
fclose(ini);
|
||||
}
|
||||
|
|
523
platform.h
523
platform.h
|
@ -24,531 +24,14 @@
|
|||
#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>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.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;
|
||||
# else
|
||||
# include <dirent.h>
|
||||
# endif /*!__MINGW32__*/
|
||||
|
||||
# ifndef S_ISDIR
|
||||
# define S_ISDIR(X) ((X)&_S_IFDIR)
|
||||
# endif
|
||||
#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_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(const 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
|
||||
|
|
205
test.c
205
test.c
|
@ -20,48 +20,33 @@
|
|||
* 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 <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gmqcc.h"
|
||||
#include "platform.h"
|
||||
|
||||
static const char *task_bins[] = {
|
||||
"./gmqcc",
|
||||
"./qcvm"
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO: Windows version
|
||||
* this implements a unique bi-directional popen-like function that
|
||||
* allows reading data from both stdout and stderr. And writing to
|
||||
* stdin :)
|
||||
*
|
||||
* Example of use:
|
||||
* FILE *handles[3] = task_popen("ls", "-l", "r");
|
||||
* if (!handles) { perror("failed to open stdin/stdout/stderr to ls");
|
||||
* // handles[0] = stdin
|
||||
* // handles[1] = stdout
|
||||
* // handles[2] = stderr
|
||||
*
|
||||
* task_pclose(handles); // to close
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
typedef struct {
|
||||
fs_file_t *handles[3];
|
||||
int pipes [3];
|
||||
|
||||
FILE *handles[3];
|
||||
int pipes[3];
|
||||
int stderr_fd;
|
||||
int stdout_fd;
|
||||
int pid;
|
||||
} popen_t;
|
||||
|
||||
static fs_file_t **task_popen(const char *command, const char *mode) {
|
||||
static FILE **task_popen(const char *command, const char *mode) {
|
||||
int inhandle [2];
|
||||
int outhandle [2];
|
||||
int errhandle [2];
|
||||
|
@ -95,17 +80,15 @@ static fs_file_t **task_popen(const char *command, const char *mode) {
|
|||
|
||||
if ((data->pid = fork()) > 0) {
|
||||
/* parent */
|
||||
close(inhandle [0]);
|
||||
close(inhandle [0]);
|
||||
close(outhandle [1]);
|
||||
close(errhandle [1]);
|
||||
|
||||
data->pipes [0] = inhandle [1];
|
||||
data->pipes [1] = outhandle[0];
|
||||
data->pipes [2] = errhandle[0];
|
||||
|
||||
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);
|
||||
data->pipes[0] = inhandle [1];
|
||||
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);
|
||||
|
||||
/* sigh */
|
||||
vec_free(argv);
|
||||
|
@ -137,7 +120,7 @@ task_popen_error_0:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int task_pclose(fs_file_t **handles) {
|
||||
static int task_pclose(FILE **handles) {
|
||||
popen_t *data = (popen_t*)handles;
|
||||
int status = 0;
|
||||
|
||||
|
@ -151,51 +134,6 @@ static int task_pclose(fs_file_t **handles) {
|
|||
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
typedef struct {
|
||||
fs_file_t *handles[3];
|
||||
char name_err[L_tmpnam];
|
||||
char name_out[L_tmpnam];
|
||||
} popen_t;
|
||||
|
||||
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));
|
||||
|
||||
tmpnam(open->name_err);
|
||||
tmpnam(open->name_out);
|
||||
|
||||
(void)mode; /* excluded */
|
||||
|
||||
util_asprintf(&cmd, "%s -redirout=%s -redirerr=%s", command, open->name_out, open->name_err);
|
||||
|
||||
system(cmd); /* HACK */
|
||||
open->handles[0] = NULL;
|
||||
open->handles[1] = fs_file_open(open->name_out, "r");
|
||||
open->handles[2] = fs_file_open(open->name_err, "r");
|
||||
|
||||
mem_d(cmd);
|
||||
|
||||
return open->handles;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
mem_d(open);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
# define popen _popen
|
||||
# define pclose _pclose
|
||||
#endif /*! _WIN32 */
|
||||
|
||||
#define TASK_COMPILE 0
|
||||
#define TASK_EXECUTE 1
|
||||
|
@ -361,7 +299,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, fs_file_t *fp, size_t *pad) {
|
||||
static bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size_t *pad) {
|
||||
char *data = NULL;
|
||||
char *back = NULL;
|
||||
size_t size = 0;
|
||||
|
@ -371,7 +309,7 @@ static bool task_template_parse(const char *file, task_template_t *tmpl, fs_file
|
|||
return false;
|
||||
|
||||
/* top down parsing */
|
||||
while (fs_file_getline(&back, &size, fp) != FS_FILE_EOF) {
|
||||
while (fs_file_getline(&back, &size, fp) != EOF) {
|
||||
/* skip whitespace */
|
||||
data = back;
|
||||
if (*data && (*data == ' ' || *data == '\t'))
|
||||
|
@ -502,12 +440,12 @@ 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;
|
||||
fs_file_t *tempfile = NULL;
|
||||
FILE *tempfile = NULL;
|
||||
task_template_t *tmpl = NULL;
|
||||
|
||||
util_snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file);
|
||||
|
||||
tempfile = fs_file_open(fullfile, "r");
|
||||
tempfile = fopen(fullfile, "r");
|
||||
tmpl = (task_template_t*)mem_a(sizeof(task_template_t));
|
||||
task_template_nullify(tmpl);
|
||||
|
||||
|
@ -604,7 +542,7 @@ static task_template_t *task_template_compile(const char *file, const char *dir,
|
|||
}
|
||||
|
||||
success:
|
||||
fs_file_close(tempfile);
|
||||
fclose(tempfile);
|
||||
return tmpl;
|
||||
|
||||
failure:
|
||||
|
@ -613,7 +551,7 @@ failure:
|
|||
* so the check to see if it's not null here is required.
|
||||
*/
|
||||
if (tempfile)
|
||||
fs_file_close(tempfile);
|
||||
fclose(tempfile);
|
||||
mem_d (tmpl);
|
||||
|
||||
return NULL;
|
||||
|
@ -657,12 +595,12 @@ static void task_template_destroy(task_template_t *tmpl) {
|
|||
*/
|
||||
typedef struct {
|
||||
task_template_t *tmpl;
|
||||
fs_file_t **runhandles;
|
||||
fs_file_t *stderrlog;
|
||||
fs_file_t *stdoutlog;
|
||||
char *stdoutlogfile;
|
||||
char *stderrlogfile;
|
||||
bool compiled;
|
||||
FILE **runhandles;
|
||||
FILE *stderrlog;
|
||||
FILE *stdoutlog;
|
||||
char *stdoutlogfile;
|
||||
char *stderrlogfile;
|
||||
bool compiled;
|
||||
} task_t;
|
||||
|
||||
static task_t *task_tasks = NULL;
|
||||
|
@ -673,8 +611,8 @@ static task_t *task_tasks = NULL;
|
|||
*/
|
||||
static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
||||
bool success = true;
|
||||
fs_dir_t *dir;
|
||||
fs_dirent_t *files;
|
||||
DIR *dir;
|
||||
struct dirent *files;
|
||||
struct stat directory;
|
||||
char buffer[4096];
|
||||
size_t found = 0;
|
||||
|
@ -683,16 +621,16 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
size_t i;
|
||||
|
||||
vec_push(directories, claim);
|
||||
dir = fs_dir_open(claim);
|
||||
dir = opendir(claim);
|
||||
|
||||
/*
|
||||
* Generate a list of subdirectories since we'll be checking them too
|
||||
* for tmpl files.
|
||||
*/
|
||||
while ((files = fs_dir_read(dir))) {
|
||||
while ((files = readdir(dir))) {
|
||||
util_asprintf(&claim, "%s/%s", curdir, files->d_name);
|
||||
if (stat(claim, &directory) == -1) {
|
||||
fs_dir_close(dir);
|
||||
closedir(dir);
|
||||
mem_d(claim);
|
||||
return false;
|
||||
}
|
||||
|
@ -704,7 +642,7 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
claim = NULL;
|
||||
}
|
||||
}
|
||||
fs_dir_close(dir);
|
||||
closedir(dir);
|
||||
|
||||
/*
|
||||
* Now do all the work, by touching all the directories inside
|
||||
|
@ -712,9 +650,9 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
* use to run the tests.
|
||||
*/
|
||||
for (i = 0; i < vec_size(directories); i++) {
|
||||
dir = fs_dir_open(directories[i]);
|
||||
dir = opendir(directories[i]);
|
||||
|
||||
while ((files = fs_dir_read(dir))) {
|
||||
while ((files = readdir(dir))) {
|
||||
util_snprintf(buffer, sizeof(buffer), "%s/%s", directories[i], files->d_name);
|
||||
if (stat(buffer, &directory) == -1) {
|
||||
con_err("internal error: stat failed, aborting\n");
|
||||
|
@ -752,7 +690,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)
|
||||
*/
|
||||
qcflags = platform_getenv("QCFLAGS");
|
||||
qcflags = getenv("QCFLAGS");
|
||||
|
||||
/*
|
||||
* Generate the command required to open a pipe to a process
|
||||
|
@ -843,23 +781,21 @@ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
|
|||
*/
|
||||
util_snprintf(buf, sizeof(buf), "%s.stdout", tmpl->tempfilename);
|
||||
task.stdoutlogfile = util_strdup(buf);
|
||||
if (!(task.stdoutlog = fs_file_open(buf, "w"))) {
|
||||
if (!(task.stdoutlog = fopen(buf, "w"))) {
|
||||
con_err("error opening %s for stdout\n", buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
util_snprintf(buf, sizeof(buf), "%s.stderr", tmpl->tempfilename);
|
||||
task.stderrlogfile = util_strdup(buf);
|
||||
if (!(task.stderrlog = fs_file_open(buf, "w"))) {
|
||||
if (!(task.stderrlog = fopen(buf, "w"))) {
|
||||
con_err("error opening %s for stderr\n", buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
vec_push(task_tasks, task);
|
||||
}
|
||||
}
|
||||
|
||||
fs_dir_close(dir);
|
||||
closedir(dir);
|
||||
mem_d(directories[i]); /* free claimed memory */
|
||||
}
|
||||
vec_free(directories);
|
||||
|
@ -872,13 +808,13 @@ 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) {
|
||||
fs_dir_t *dir;
|
||||
fs_dirent_t *files;
|
||||
DIR *dir;
|
||||
struct dirent *files;
|
||||
char buffer[4096];
|
||||
|
||||
dir = fs_dir_open(curdir);
|
||||
dir = opendir(curdir);
|
||||
|
||||
while ((files = fs_dir_read(dir))) {
|
||||
while ((files = readdir(dir))) {
|
||||
if (strstr(files->d_name, "TMP") ||
|
||||
strstr(files->d_name, ".stdout") ||
|
||||
strstr(files->d_name, ".stderr") ||
|
||||
|
@ -890,7 +826,7 @@ static void task_precleanup(const char *curdir) {
|
|||
}
|
||||
}
|
||||
|
||||
fs_dir_close(dir);
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void task_destroy(void) {
|
||||
|
@ -905,8 +841,8 @@ static void task_destroy(void) {
|
|||
* Close any open handles to files or processes here. It's mighty
|
||||
* annoying to have to do all this cleanup work.
|
||||
*/
|
||||
if (task_tasks[i].stdoutlog) fs_file_close (task_tasks[i].stdoutlog);
|
||||
if (task_tasks[i].stderrlog) fs_file_close (task_tasks[i].stderrlog);
|
||||
if (task_tasks[i].stdoutlog) fclose(task_tasks[i].stdoutlog);
|
||||
if (task_tasks[i].stderrlog) fclose(task_tasks[i].stderrlog);
|
||||
|
||||
/*
|
||||
* Only remove the log files if the test actually compiled otherwise
|
||||
|
@ -941,7 +877,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
bool success = true;
|
||||
bool process = true;
|
||||
int retval = EXIT_SUCCESS;
|
||||
fs_file_t *execute;
|
||||
FILE *execute;
|
||||
char buffer[4096];
|
||||
task_template_t *tmpl = task_tasks[i].tmpl;
|
||||
|
||||
|
@ -965,7 +901,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
);
|
||||
}
|
||||
|
||||
execute = (fs_file_t*)popen(buffer, "r");
|
||||
execute = popen(buffer, "r");
|
||||
if (!execute)
|
||||
return false;
|
||||
} else if (!strcmp(tmpl->proceduretype, "-pp")) {
|
||||
|
@ -973,9 +909,8 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
* we're preprocessing, which means we need to read int
|
||||
* the produced file and do some really weird shit.
|
||||
*/
|
||||
if (!(execute = fs_file_open(tmpl->tempfilename, "r")))
|
||||
if (!(execute = fopen(tmpl->tempfilename, "r")))
|
||||
return false;
|
||||
|
||||
process = false;
|
||||
} else {
|
||||
/*
|
||||
|
@ -983,9 +918,8 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
* in runhandles[2] (stderr) since that is where the compiler
|
||||
* puts it's errors.
|
||||
*/
|
||||
if (!(execute = fs_file_open(task_tasks[i].stderrlogfile, "r")))
|
||||
if (!(execute = fopen(task_tasks[i].stderrlogfile, "r")))
|
||||
return false;
|
||||
|
||||
process = false;
|
||||
}
|
||||
|
||||
|
@ -998,14 +932,14 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
size_t size = 0;
|
||||
size_t compare = 0;
|
||||
|
||||
while (fs_file_getline(&data, &size, execute) != FS_FILE_EOF) {
|
||||
while (fs_file_getline(&data, &size, execute) != EOF) {
|
||||
if (!strcmp(data, "No main function found\n")) {
|
||||
con_err("test failure: `%s` (No main function found) [%s]\n",
|
||||
tmpl->description,
|
||||
tmpl->rulesfile
|
||||
);
|
||||
if (!process)
|
||||
fs_file_close(execute);
|
||||
fclose(execute);
|
||||
else
|
||||
pclose((FILE*)execute);
|
||||
return false;
|
||||
|
@ -1069,7 +1003,7 @@ static bool task_trymatch(size_t i, char ***line) {
|
|||
if (process)
|
||||
retval = pclose((FILE*)execute);
|
||||
else
|
||||
fs_file_close(execute);
|
||||
fclose(execute);
|
||||
|
||||
return success && retval == EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -1132,15 +1066,15 @@ 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]) != FS_FILE_EOF) {
|
||||
fs_file_puts(task_tasks[i].stdoutlog, data);
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[1]) != EOF) {
|
||||
fputs(data, task_tasks[i].stdoutlog);
|
||||
|
||||
if (strstr(data, "failed to open file")) {
|
||||
task_tasks[i].compiled = false;
|
||||
execute = false;
|
||||
}
|
||||
}
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != FS_FILE_EOF) {
|
||||
while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
|
||||
/*
|
||||
* If a string contains an error we just dissalow execution
|
||||
* of it in the vm.
|
||||
|
@ -1154,8 +1088,8 @@ static size_t task_schedualize(size_t *pad) {
|
|||
task_tasks[i].compiled = false;
|
||||
}
|
||||
|
||||
fs_file_puts (task_tasks[i].stderrlog, data);
|
||||
fs_file_flush(task_tasks[i].stderrlog); /* fast flush for read */
|
||||
fputs(data, task_tasks[i].stderrlog);
|
||||
fflush(task_tasks[i].stderrlog); /* fast flush for read */
|
||||
}
|
||||
|
||||
if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
|
||||
|
@ -1363,10 +1297,8 @@ static bool parsecmd(const char *optname, int *argc_, char ***argv_, char **out,
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bool succeed = false;
|
||||
char *redirout = (char*)stdout;
|
||||
char *redirerr = (char*)stderr;
|
||||
char *defs = NULL;
|
||||
bool succeed = false;
|
||||
char *defs = NULL;
|
||||
|
||||
con_init();
|
||||
OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = 16;
|
||||
|
@ -1380,14 +1312,8 @@ int main(int argc, char **argv) {
|
|||
--argc;
|
||||
|
||||
if (argv[0][0] == '-') {
|
||||
if (parsecmd("redirout", &argc, &argv, &redirout, 1, false))
|
||||
if (parsecmd("defs", &argc, &argv, &defs, 1, false))
|
||||
continue;
|
||||
if (parsecmd("redirerr", &argc, &argv, &redirerr, 1, false))
|
||||
continue;
|
||||
if (parsecmd("defs", &argc, &argv, &defs, 1, false))
|
||||
continue;
|
||||
|
||||
con_change(redirout, redirerr);
|
||||
|
||||
if (!strcmp(argv[0]+1, "debug")) {
|
||||
OPTS_OPTION_BOOL(OPTION_DEBUG) = true;
|
||||
|
@ -1406,7 +1332,6 @@ int main(int argc, char **argv) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
con_change(redirout, redirerr);
|
||||
succeed = test_perform("tests", defs);
|
||||
|
||||
return (succeed) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
|
|
54
util.c
54
util.c
|
@ -21,8 +21,8 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#define GMQCC_PLATFORM_HEADER
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gmqcc.h"
|
||||
#include "platform.h"
|
||||
|
||||
|
@ -586,62 +586,68 @@ size_t util_optimizationtostr(const char *in, char *out, size_t outsz) {
|
|||
|
||||
int util_snprintf(char *str, size_t size, const char *fmt, ...) {
|
||||
va_list arg;
|
||||
int ret;
|
||||
|
||||
int ret;
|
||||
va_start(arg, fmt);
|
||||
ret = platform_vsnprintf(str, size, fmt, arg);
|
||||
ret = vsnprintf(str, size, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int util_asprintf(char **ret, const char *fmt, ...) {
|
||||
va_list args;
|
||||
int read;
|
||||
|
||||
int read;
|
||||
va_start(args, fmt);
|
||||
read = platform_vasprintf(ret, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
va_end(args);
|
||||
return read;
|
||||
}
|
||||
|
||||
int util_sscanf(const char *str, const char *format, ...) {
|
||||
va_list args;
|
||||
int read;
|
||||
|
||||
int read;
|
||||
va_start(args, format);
|
||||
read = platform_vsscanf(str, format, args);
|
||||
read = vsscanf(str, format, args);
|
||||
va_end(args);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
char *util_strncpy(char *dest, const char *src, size_t n) {
|
||||
return platform_strncpy(dest, src, n);
|
||||
return strncpy(dest, src, n);
|
||||
}
|
||||
|
||||
char *util_strncat(char *dest, const char *src, size_t n) {
|
||||
return platform_strncat(dest, src, n);
|
||||
return strncat(dest, src, n);
|
||||
}
|
||||
|
||||
char *util_strcat(char *dest, const char *src) {
|
||||
return platform_strcat(dest, src);
|
||||
return strcat(dest, src);
|
||||
}
|
||||
|
||||
const char *util_strerror(int err) {
|
||||
return platform_strerror(err);
|
||||
return strerror(err);
|
||||
}
|
||||
|
||||
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);
|
||||
return localtime(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);
|
||||
const char *util_ctime(const time_t *timer) {
|
||||
return ctime(timer);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
bool util_isatty(FILE *file) {
|
||||
if (file == stdout) return !!isatty(STDOUT_FILENO);
|
||||
if (file == stderr) return !!isatty(STDERR_FILENO);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bool util_isatty(FILE *file) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A small noncryptographic PRNG based on:
|
||||
* http://burtleburtle.net/bob/rand/smallprng.html
|
||||
|
|
Loading…
Reference in a new issue