From: Wolfgang (Blub) Bumiller Date: Mon, 25 Jun 2012 21:58:47 +0000 (+0200) Subject: executor: loader X-Git-Tag: 0.1-rc1~371^2~21 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=e328446044e71ef500ef1383cd1418490d6b621c;p=xonotic%2Fgmqcc.git executor: loader --- diff --git a/Makefile b/Makefile index a0d6cc9..a7b2ac1 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ OBJ = lex.o \ OBJ_A = test/ast-test.o OBJ_I = test/ir-test.o OBJ_C = main.o +OBJ_X = exec.o util.o #default is compiler only default: gmqcc @@ -39,6 +40,8 @@ test_ast: $(OBJ_A) $(OBJ) $(CC) -o $@ $^ $(CFLAGS) test_ir: $(OBJ_I) $(OBJ) $(CC) -o $@ $^ $(CFLAGS) +qcvm: $(OBJ_X) + $(CC) -o $@ $^ $(CFLAGS) test: test_ast test_ir # compiler target diff --git a/exec.c b/exec.c new file mode 100644 index 0000000..3f383ed --- /dev/null +++ b/exec.c @@ -0,0 +1,156 @@ +#include "gmqcc.h" + +#define QCVM_EXECUTOR + +/* darkplaces has (or will have) a 64 bit prog loader + * where the 32 bit qc program is autoconverted on load. + * Since we may want to support that as well, let's redefine + * float and int here. + */ +typedef float qcfloat; +typedef int32_t qcint; + +typedef char qcfloat_size_is_correct [sizeof(qcfloat) == 4 ?1:-1]; +typedef char qcint_size_is_correct [sizeof(int) == 4 ?1:-1]; + +typedef struct { + uint32_t offset; + uint32_t length; +} prog_section; + +typedef struct { + uint32_t version; + uint16_t crc16; + uint16_t skip; + + prog_section statements; + prog_section defs; + prog_section fields; + prog_section functions; + prog_section strings; + prog_section globals; + uint32_t entfield; +} prog_header; + +typedef prog_section_both prog_def; +typedef prog_section_function prog_function; +typedef prog_section_statement prog_statement; + +typedef struct { + char *filename; + + prog_statement *code; + prog_def *defs; + prog_def *fields; + prog_function *functions; + char *strings; + qcint *globals; + qcint *entitydata; +} qc_program; + +qc_program* prog_load(const char *filename) +{ + qc_program *prog; + prog_header header; + FILE *file; + + file = fopen(filename, "rb"); + if (!file) + return NULL; + + if (fread(&header, sizeof(header), 1, file) != 1) { + perror("read"); + fclose(file); + return NULL; + } + + if (header.version != 6) { + printf("header says this is a version %i progs, we need version 6\n", + header.version); + fclose(file); + return NULL; + } + + prog = (qc_program*)mem_a(sizeof(qc_program)); + if (!prog) { + fclose(file); + printf("failed to allocate program data\n"); + return NULL; + } + memset(prog, 0, sizeof(*prog)); + + prog->filename = util_strdup(filename); + if (!prog->filename) + goto error; +#define read_data(hdrvar, progvar, type) \ + if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ + perror("fseek"); \ + goto error; \ + } \ + prog->progvar = (type*)mem_a(header.hdrvar.length * sizeof(*prog->progvar)); \ + if (!prog->progvar) \ + goto error; \ + if (fread(prog->progvar, sizeof(*prog->progvar), header.hdrvar.length, file) \ + != header.hdrvar.length) { \ + perror("read"); \ + goto error; \ + } +#define read_data1(x, y) read_data(x, x, y) + + read_data (statements, code, prog_statement); + read_data1(defs, prog_def); + read_data1(fields, prog_def); + read_data1(functions, prog_function); + read_data1(strings, char); + read_data1(globals, qcint); + + fclose(file); + + return prog; + +error: + if (prog->filename) mem_d(prog->filename); + if (prog->code) mem_d(prog->code); + if (prog->defs) mem_d(prog->defs); + if (prog->fields) mem_d(prog->fields); + if (prog->functions) mem_d(prog->functions); + if (prog->strings) mem_d(prog->strings); + if (prog->globals) mem_d(prog->globals); + if (prog->entitydata) mem_d(prog->entitydata); + mem_d(prog); + return NULL; +} + +void prog_delete(qc_program *prog) +{ + if (prog->filename) mem_d(prog->filename); + if (prog->code) mem_d(prog->code); + if (prog->defs) mem_d(prog->defs); + if (prog->fields) mem_d(prog->fields); + if (prog->functions) mem_d(prog->functions); + if (prog->strings) mem_d(prog->strings); + if (prog->globals) mem_d(prog->globals); + if (prog->entitydata) mem_d(prog->entitydata); + mem_d(prog); +} + +#if defined(QCVM_EXECUTOR) +int main(int argc, char **argv) +{ + qc_program *prog; + + if (argc != 2) { + printf("usage: %s prog.dat\n", argv[0]); + exit(1); + } + + prog = prog_load(argv[1]); + if (!prog) { + printf("failed to load program '%s'\n", argv[1]); + exit(1); + } + + prog_delete(prog); + return 0; +} +#endif