9 static void loaderror(const char *fmt, ...)
16 printf(": %s\n", strerror(err));
19 qc_program* prog_load(const char *filename)
25 file = fopen(filename, "rb");
29 if (fread(&header, sizeof(header), 1, file) != 1) {
30 loaderror("failed to read header from '%s'", filename);
35 if (header.version != 6) {
36 loaderror("header says this is a version %i progs, we need version 6\n", header.version);
41 prog = (qc_program*)mem_a(sizeof(qc_program));
44 printf("failed to allocate program data\n");
47 memset(prog, 0, sizeof(*prog));
49 prog->entityfields = header.entfield;
51 prog->filename = util_strdup(filename);
52 if (!prog->filename) {
53 loaderror("failed to store program name");
57 #define read_data(hdrvar, progvar, type) \
58 if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \
59 loaderror("seek failed"); \
62 prog->progvar##_alloc = header.hdrvar.length; \
63 prog->progvar##_count = header.hdrvar.length; \
64 prog->progvar = (type*)mem_a(header.hdrvar.length * sizeof(*prog->progvar)); \
67 if (fread(prog->progvar, sizeof(*prog->progvar), header.hdrvar.length, file) \
68 != header.hdrvar.length) { \
69 loaderror("read failed"); \
72 #define read_data1(x, y) read_data(x, x, y)
74 read_data (statements, code, prog_statement);
75 read_data1(defs, prog_def);
76 read_data1(fields, prog_def);
77 read_data1(functions, prog_function);
78 read_data1(strings, char);
79 read_data1(globals, qcint);
83 /* profile counters */
84 if (!qc_program_profile_resize(prog, prog->code_count))
87 /* Add tempstring area */
88 prog->tempstring_start = prog->strings_count;
89 prog->tempstring_at = prog->strings_count;
90 if (!qc_program_strings_resize(prog, prog->strings_count + 16*1024))
96 if (prog->filename) mem_d(prog->filename);
97 if (prog->code) mem_d(prog->code);
98 if (prog->defs) mem_d(prog->defs);
99 if (prog->fields) mem_d(prog->fields);
100 if (prog->functions) mem_d(prog->functions);
101 if (prog->strings) mem_d(prog->strings);
102 if (prog->globals) mem_d(prog->globals);
103 if (prog->entitydata) mem_d(prog->entitydata);
108 void prog_delete(qc_program *prog)
110 if (prog->filename) mem_d(prog->filename);
111 MEM_VECTOR_CLEAR(prog, code);
112 MEM_VECTOR_CLEAR(prog, defs);
113 MEM_VECTOR_CLEAR(prog, fields);
114 MEM_VECTOR_CLEAR(prog, functions);
115 MEM_VECTOR_CLEAR(prog, strings);
116 MEM_VECTOR_CLEAR(prog, globals);
117 MEM_VECTOR_CLEAR(prog, entitydata);
118 MEM_VECTOR_CLEAR(prog, localstack);
119 MEM_VECTOR_CLEAR(prog, stack);
120 MEM_VECTOR_CLEAR(prog, profile);
124 /***********************************************************************
128 char* prog_getstring(qc_program *prog, qcint str)
130 if (str < 0 || str >= prog->strings_count)
131 return "<<<invalid string>>>";
132 return prog->strings + str;
135 prog_def* prog_entfield(qc_program *prog, qcint off)
138 for (i = 0; i < prog->fields_count; ++i) {
139 if (prog->fields[i].offset == off)
140 return (prog->fields + i);
145 prog_def* prog_getdef(qc_program *prog, qcint off)
148 for (i = 0; i < prog->defs_count; ++i) {
149 if (prog->defs[i].offset == off)
150 return (prog->defs + i);
155 qcany* prog_getedict(qc_program *prog, qcint e)
157 return (qcany*)(prog->entitydata + (prog->entityfields + e));
160 qcint prog_tempstring(qc_program *prog, const char *_str)
162 /* we don't access it, but the macro-generated functions don't use
165 char *str = (char*)_str;
167 size_t len = strlen(str);
168 size_t at = prog->tempstring_at;
170 /* when we reach the end we start over */
171 if (at + len >= prog->strings_count)
172 at = prog->tempstring_start;
174 /* when it doesn't fit, reallocate */
175 if (at + len >= prog->strings_count)
177 prog->strings_count = at;
178 if (!qc_program_strings_append(prog, str, len+1)) {
179 prog->vmerror = VMERR_TEMPSTRING_ALLOC;
185 /* when it fits, just copy */
186 memcpy(prog->strings + at, str, len+1);
187 prog->tempstring_at += len+1;
191 static void trace_print_global(qc_program *prog, unsigned int glob, int vtype)
193 static char spaces[16+1] = " ";
201 def = prog_getdef(prog, glob);
202 value = (qcany*)(&prog->globals[glob]);
205 len = printf("[%s] ", prog_getstring(prog, def->name));
209 len = printf("[#%u] ", glob);
217 len += printf("%i,", value->_int);
220 len += printf("'%g %g %g',", value->vector[0],
225 len += printf("\"%s\",", prog_getstring(prog, value->string));
229 len += printf("%g,", value->_float);
235 spaces[16-len] = ' ';
239 static void prog_print_statement(qc_program *prog, prog_statement *st)
241 if (st->opcode >= (sizeof(asm_instr)/sizeof(asm_instr[0]))) {
242 printf("<illegal instruction %d>\n", st->opcode);
245 printf("%-12s", asm_instr[st->opcode].m);
246 if (st->opcode >= INSTR_IF &&
247 st->opcode <= INSTR_IFNOT)
249 trace_print_global(prog, st->o1.u1, TYPE_FLOAT);
250 printf("%d\n", st->o2.s1);
252 else if (st->opcode >= INSTR_CALL0 &&
253 st->opcode <= INSTR_CALL8)
257 else if (st->opcode == INSTR_GOTO)
259 printf("%i\n", st->o1.s1);
263 int t[3] = { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT };
267 t[1] = t[2] = TYPE_VECTOR;
270 t[0] = t[2] = TYPE_VECTOR;
273 t[0] = t[1] = TYPE_VECTOR;
279 t[0] = t[1] = t[2] = TYPE_VECTOR;
283 t[0] = t[1] = TYPE_STRING;
286 t[0] = t[1] = TYPE_VECTOR; t[2] = -1;
289 t[0] = t[1] = TYPE_STRING; t[2] = -1;
292 if (t[0] >= 0) trace_print_global(prog, st->o1.u1, t[0]);
293 if (t[1] >= 0) trace_print_global(prog, st->o2.u1, t[1]);
294 if (t[2] >= 0) trace_print_global(prog, st->o3.u1, t[2]);
299 static qcint prog_enterfunction(qc_program *prog, prog_function *func)
302 prog_function *cur = NULL;
304 if (prog->stack_count)
305 cur = prog->stack[prog->stack_count-1].function;
308 st.localsp = prog->localstack_count;
309 st.stmt = prog->statement;
314 qcint *globals = prog->globals + cur->firstlocal;
315 if (!qc_program_localstack_append(prog, globals, cur->locals))
317 printf("out of memory\n");
322 if (!qc_program_stack_add(prog, st)) {
323 printf("out of memory\n");
330 static qcint prog_leavefunction(qc_program *prog)
332 qc_exec_stack st = prog->stack[prog->stack_count-1];
333 if (!qc_program_stack_remove(prog, prog->stack_count-1)) {
334 printf("out of memory\n");
338 if (st.localsp != prog->localstack_count) {
339 if (!qc_program_localstack_resize(prog, st.localsp)) {
340 printf("out of memory\n");
348 bool prog_exec(qc_program *prog, prog_function *func, size_t flags, long maxjumps)
353 st = prog->code + prog_enterfunction(prog, func);
360 #define QCVM_PROFILE 0
362 # include "execloop.h"
367 #define QCVM_PROFILE 0
369 # include "execloop.h"
374 #define QCVM_PROFILE 1
376 # include "execloop.h"
379 case (VMXF_TRACE|VMXF_PROFILE):
381 #define QCVM_PROFILE 1
383 # include "execloop.h"
389 prog->localstack_count = 0;
390 prog->stack_count = 0;
394 /***********************************************************************
395 * main for when building the standalone executor
398 #if defined(QCVM_EXECUTOR)
399 int main(int argc, char **argv)
406 printf("usage: %s file\n", argv[0]);
410 prog = prog_load(argv[1]);
412 printf("failed to load program '%s'\n", argv[1]);
416 for (i = 1; i < prog->functions_count; ++i) {
417 const char *name = prog_getstring(prog, prog->functions[i].name);
418 printf("Found function: %s\n", name);
419 if (!strcmp(name, "main"))
424 prog_exec(prog, &prog->functions[fnmain], VMXF_TRACE, JUMPS_DEFAULT);
427 printf("No main function found\n");