/*
- * Copyright (C) 2012, 2013
+ * Copyright (C) 2012, 2013, 2014
* Wolfgang Bumiller
* Dale Weiler
*
*/
#ifndef QCVM_LOOP
#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
#include "gmqcc.h"
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
- printf(": %s\n", platform_strerror(err));
+ printf(": %s\n", util_strerror(err));
}
static void qcvmerror(qc_program_t *prog, const char *fmt, ...)
qc_program_t* prog_load(const char *filename, bool skipversion)
{
- qc_program_t *prog;
prog_header_t header;
- FILE *file = fs_file_open(filename, "rb");
+ qc_program_t *prog;
+ size_t i;
+ fs_file_t *file = fs_file_open(filename, "rb");
+
+ /* we need all those in order to support INSTR_STATE: */
+ bool has_self = false,
+ has_time = false,
+ has_think = false,
+ has_nextthink = false,
+ has_frame = false;
if (!file)
return NULL;
return NULL;
}
+ util_swap_header(&header);
+
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);
read_data1(strings);
read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */
+ util_swap_statements (prog->code);
+ util_swap_defs_fields(prog->defs);
+ util_swap_defs_fields(prog->fields);
+ util_swap_functions (prog->functions);
+ util_swap_globals (prog->globals);
+
fs_file_close(file);
/* profile counters */
memset(vec_add(prog->entitydata, prog->entityfields), 0, prog->entityfields * sizeof(prog->entitydata[0]));
prog->entities = 1;
+ /* cache some globals and fields from names */
+ for (i = 0; i < vec_size(prog->defs); ++i) {
+ const char *name = prog_getstring(prog, prog->defs[i].name);
+ if (!strcmp(name, "self")) {
+ prog->cached_globals.self = prog->defs[i].offset;
+ has_self = true;
+ }
+ else if (!strcmp(name, "time")) {
+ prog->cached_globals.time = prog->defs[i].offset;
+ has_time = true;
+ }
+ }
+ for (i = 0; i < vec_size(prog->fields); ++i) {
+ const char *name = prog_getstring(prog, prog->fields[i].name);
+ if (!strcmp(name, "think")) {
+ prog->cached_fields.think = prog->fields[i].offset;
+ has_think = true;
+ }
+ else if (!strcmp(name, "nextthink")) {
+ prog->cached_fields.nextthink = prog->fields[i].offset;
+ has_nextthink = true;
+ }
+ else if (!strcmp(name, "frame")) {
+ prog->cached_fields.frame = prog->fields[i].offset;
+ has_frame = true;
+ }
+ }
+ if (has_self && has_time && has_think && has_nextthink && has_frame)
+ prog->supports_state = true;
+
return prog;
error:
done:
if (len < (int)sizeof(spaces)-1) {
spaces[sizeof(spaces)-1-len] = 0;
- fs_file_puts(stdout, spaces);
+ fs_file_puts((fs_file_t*)stdout, spaces);
spaces[sizeof(spaces)-1-len] = ' ';
}
}
* main for when building the standalone executor
*/
-#if defined(QCVM_EXECUTOR)
#include <math.h>
const char *type_name[TYPE_COUNT] = {
qcany_t str;
CheckArgs(1);
num = GetArg(0);
- platform_snprintf(buffer, sizeof(buffer), "%g", num->_float);
+ util_snprintf(buffer, sizeof(buffer), "%g", num->_float);
str.string = prog_tempstring(prog, buffer);
Return(str);
return 0;
qcany_t str;
CheckArgs(1);
num = GetArg(0);
- platform_snprintf(buffer, sizeof(buffer), "'%g %g %g'", num->vector[0], num->vector[1], num->vector[2]);
+ util_snprintf(buffer, sizeof(buffer), "'%g %g %g'", num->vector[0], num->vector[1], num->vector[2]);
str.string = prog_tempstring(prog, buffer);
Return(str);
return 0;
qcany_t str;
CheckArgs(1);
num = GetArg(0);
- platform_snprintf(buffer, sizeof(buffer), "%i", num->_int);
+ util_snprintf(buffer, sizeof(buffer), "%i", num->_int);
str.string = prog_tempstring(prog, buffer);
Return(str);
return 0;
return 0;
}
+static int qc_pow(qc_program_t *prog) {
+ qcany_t *base, *exp, out;
+ CheckArgs(2);
+ base = GetArg(0);
+ exp = GetArg(1);
+ out._float = powf(base->_float, exp->_float);
+ Return(out);
+ return 0;
+}
+
static prog_builtin_t qc_builtins[] = {
NULL,
&qc_print, /* 1 */
&qc_strcmp, /* 11 */
&qc_normalize, /* 12 */
&qc_sqrt, /* 13 */
- &qc_floor /* 14 */
+ &qc_floor, /* 14 */
+ &qc_pow /* 15 */
};
static const char *arg0 = NULL;
arg->vector[2] = 0;
switch (main_params[i].vtype) {
case TYPE_VECTOR:
- (void)platform_sscanf(main_params[i].value, " %f %f %f ",
+ (void)util_sscanf(main_params[i].value, " %f %f %f ",
&arg->vector[0],
&arg->vector[1],
&arg->vector[2]);
}
}
-void prog_disasm_function(qc_program_t *prog, size_t id);
+static void prog_disasm_function(qc_program_t *prog, size_t id);
int main(int argc, char **argv) {
size_t i;
if (argc < 2) {
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
while (argc > 1) {
!strcmp(argv[1], "--help"))
{
usage();
- exit(0);
+ exit(EXIT_SUCCESS);
}
else if (!strcmp(argv[1], "-v")) {
++opts_v;
++opts_v;
else {
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
}
--argc;
!strcmp(argv[1], "--version"))
{
version();
- exit(0);
+ exit(EXIT_SUCCESS);
}
else if (!strcmp(argv[1], "-trace")) {
--argc;
++argv;
if (argc <= 1) {
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
vec_push(dis_list, argv[1]);
--argc;
++argv;
if (argc < 2) {
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
p.value = argv[1];
if (progsfile) {
fprintf(stderr, "only 1 program file may be specified\n");
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
progsfile = argv[1];
--argc;
{
fprintf(stderr, "unknown parameter: %s\n", argv[1]);
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if (!progsfile) {
fprintf(stderr, "must specify a program to execute\n");
usage();
- exit(1);
+ exit(EXIT_FAILURE);
}
prog = prog_load(progsfile, noexec);
if (!prog) {
fprintf(stderr, "failed to load program '%s'\n", progsfile);
- exit(1);
+ exit(EXIT_FAILURE);
}
prog->builtins = qc_builtins;
if (opts_printfuns) {
for (i = 0; i < vec_size(prog->functions); ++i) {
int32_t a;
- printf("Function: %-16s taking %i parameters:(",
+ printf("Function: %-16s taking %u parameters:(",
prog_getstring(prog, prog->functions[i].name),
(unsigned int)prog->functions[i].nargs);
for (a = 0; a < prog->functions[i].nargs; ++a) {
return 0;
}
-void prog_disasm_function(qc_program_t *prog, size_t id) {
+static void prog_disasm_function(qc_program_t *prog, size_t id) {
prog_section_function_t *fdef = prog->functions + id;
prog_section_statement_t *st;
++st;
}
}
-#endif
#else /* !QCVM_LOOP */
/*
* Everything from here on is not including into the compilation of the
break;
case INSTR_STATE:
- qcvmerror(prog, "`%s` tried to execute a STATE operation", prog->filename);
+ {
+ qcfloat_t *nextthink;
+ qcfloat_t *time;
+ qcfloat_t *frame;
+ if (!prog->supports_state) {
+ qcvmerror(prog, "`%s` tried to execute a STATE operation but misses its defs!", prog->filename);
+ goto cleanup;
+ }
+ ed = prog_getedict(prog, prog->globals[prog->cached_globals.self]);
+ ((qcint_t*)ed)[prog->cached_fields.think] = OPB->function;
+
+ frame = (qcfloat_t*)&((qcint_t*)ed)[prog->cached_fields.frame];
+ *frame = OPA->_float;
+ nextthink = (qcfloat_t*)&((qcint_t*)ed)[prog->cached_fields.nextthink];
+ time = (qcfloat_t*)(prog->globals + prog->cached_globals.time);
+ *nextthink = *time + 0.1;
break;
+ }
case INSTR_GOTO:
st += st->o1.s1 - 1; /* offset the s++ */