+
+/*===================================================================*/
+/*============================= exec.c ==============================*/
+/*===================================================================*/
+
+/* 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 union {
+ qcint _int;
+ qcint string;
+ qcint function;
+ qcint edict;
+ qcfloat _float;
+ qcfloat vector[3];
+ qcint ivector[3];
+} qcany;
+
+typedef char qcfloat_size_is_correct [sizeof(qcfloat) == 4 ?1:-1];
+typedef char qcint_size_is_correct [sizeof(qcint) == 4 ?1:-1];
+
+enum {
+ VMERR_OK,
+ VMERR_TEMPSTRING_ALLOC,
+
+ VMERR_END
+};
+
+#define VM_JUMPS_DEFAULT 1000000
+
+/* execute-flags */
+#define VMXF_DEFAULT 0x0000 /* default flags - nothing */
+#define VMXF_TRACE 0x0001 /* trace: print statements before executing */
+#define VMXF_PROFILE 0x0002 /* profile: increment the profile counters */
+
+struct qc_program_s;
+
+typedef int (*prog_builtin)(struct qc_program_s *prog);
+
+typedef struct {
+ qcint stmt;
+ size_t localsp;
+ prog_section_function *function;
+} qc_exec_stack;
+
+typedef struct qc_program_s {
+ char *filename;
+
+ MEM_VECTOR_MAKE(prog_section_statement, code);
+ MEM_VECTOR_MAKE(prog_section_def, defs);
+ MEM_VECTOR_MAKE(prog_section_def, fields);
+ MEM_VECTOR_MAKE(prog_section_function, functions);
+ MEM_VECTOR_MAKE(char, strings);
+ MEM_VECTOR_MAKE(qcint, globals);
+ MEM_VECTOR_MAKE(qcint, entitydata);
+
+ size_t tempstring_start;
+ size_t tempstring_at;
+
+ qcint vmerror;
+
+ MEM_VECTOR_MAKE(size_t, profile);
+
+ MEM_VECTOR_MAKE(prog_builtin, builtins);
+
+ /* size_t ip; */
+ qcint entities;
+ size_t entityfields;
+ bool allowworldwrites;
+
+ MEM_VECTOR_MAKE(qcint, localstack);
+ MEM_VECTOR_MAKE(qc_exec_stack, stack);
+ size_t statement;
+
+ int argc; /* current arg count for debugging */
+} qc_program;
+
+qc_program* prog_load(const char *filename);
+void prog_delete(qc_program *prog);
+
+bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps);
+
+char* prog_getstring (qc_program *prog, qcint str);
+prog_section_def* prog_entfield (qc_program *prog, qcint off);
+prog_section_def* prog_getdef (qc_program *prog, qcint off);
+qcany* prog_getedict (qc_program *prog, qcint e);
+qcint prog_tempstring(qc_program *prog, const char *_str);
+
+/*===================================================================*/
+/*======================= main.c commandline ========================*/
+/*===================================================================*/
+
+#if 0
+/* Helpers to allow for a whole lot of flags. Otherwise we'd limit
+ * to 32 or 64 -f options...
+ */
+typedef struct {
+ size_t idx; /* index into an array of 32 bit words */
+ uint8_t bit; /* index _into_ the 32 bit word, thus just uint8 */
+} longbit;
+#define LONGBIT(bit) { ((bit)/32), ((bit)%32) }
+#else
+typedef uint32_t longbit;
+#define LONGBIT(bit) (bit)
+#endif
+
+/* Used to store the list of flags with names */
+typedef struct {
+ const char *name;
+ longbit bit;
+} opt_flag_def;
+
+/*===================================================================*/
+/* list of -f flags, like -fdarkplaces-string-table-bug */
+enum {
+ DP_STRING_TABLE_BUG,
+ OMIT_NULLBYTES,
+
+ NUM_F_FLAGS
+};
+static const opt_flag_def opt_flag_list[] = {
+ { "darkplaces-string-table-bug", LONGBIT(DP_STRING_TABLE_BUG) },
+ { "omit-nullbytes", LONGBIT(OMIT_NULLBYTES) },
+};
+static const size_t opt_flag_list_count = sizeof(opt_flag_list) / sizeof(opt_flag_list[0]);
+
+/* other options: */
+extern uint32_t opt_O; /* -Ox */
+extern const char *opt_output; /* -o file */
+
+/*===================================================================*/
+#define OPT_FLAG(i) (!! (opt_flags[(i)/32] & (1<< ((i)%32))))
+extern uint32_t opt_flags[1 + (NUM_F_FLAGS / 32)];
+