Major cleanup of platform/fs stuff

This commit is contained in:
Dale Weiler 2015-01-13 21:18:47 -05:00
parent 5b9e0a62ab
commit 2c421c3b71
15 changed files with 207 additions and 1055 deletions

View file

@ -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
View file

@ -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
View file

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

View file

@ -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
View file

@ -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
View file

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

View file

@ -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
View file

@ -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
View file

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

View file

@ -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
View file

@ -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
View file

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

View file

@ -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
View file

@ -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
View file

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