]> git.xonotic.org Git - xonotic/gmqcc.git/blob - exec.c
executor: loader
[xonotic/gmqcc.git] / exec.c
1 #include "gmqcc.h"
2
3 #define QCVM_EXECUTOR
4
5 /* darkplaces has (or will have) a 64 bit prog loader
6  * where the 32 bit qc program is autoconverted on load.
7  * Since we may want to support that as well, let's redefine
8  * float and int here.
9  */
10 typedef float   qcfloat;
11 typedef int32_t qcint;
12
13 typedef char qcfloat_size_is_correct [sizeof(qcfloat) == 4 ?1:-1];
14 typedef char qcint_size_is_correct   [sizeof(int)     == 4 ?1:-1];
15
16 typedef struct {
17     uint32_t offset;
18     uint32_t length;
19 } prog_section;
20
21 typedef struct {
22     uint32_t     version;
23     uint16_t     crc16;
24     uint16_t     skip;
25
26     prog_section statements;
27     prog_section defs;
28     prog_section fields;
29     prog_section functions;
30     prog_section strings;
31     prog_section globals;
32     uint32_t     entfield;
33 } prog_header;
34
35 typedef prog_section_both      prog_def;
36 typedef prog_section_function  prog_function;
37 typedef prog_section_statement prog_statement;
38
39 typedef struct {
40     char           *filename;
41
42     prog_statement *code;
43     prog_def       *defs;
44     prog_def       *fields;
45     prog_function  *functions;
46     char           *strings;
47     qcint          *globals;
48     qcint          *entitydata;
49 } qc_program;
50
51 qc_program* prog_load(const char *filename)
52 {
53     qc_program *prog;
54     prog_header header;
55     FILE *file;
56
57     file = fopen(filename, "rb");
58     if (!file)
59         return NULL;
60
61     if (fread(&header, sizeof(header), 1, file) != 1) {
62         perror("read");
63         fclose(file);
64         return NULL;
65     }
66
67     if (header.version != 6) {
68         printf("header says this is a version %i progs, we need version 6\n",
69                header.version);
70         fclose(file);
71         return NULL;
72     }
73
74     prog = (qc_program*)mem_a(sizeof(qc_program));
75     if (!prog) {
76         fclose(file);
77         printf("failed to allocate program data\n");
78         return NULL;
79     }
80     memset(prog, 0, sizeof(*prog));
81
82     prog->filename = util_strdup(filename);
83     if (!prog->filename)
84         goto error;
85 #define read_data(hdrvar, progvar, type)                                         \
86     if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) {                      \
87         perror("fseek");                                                         \
88         goto error;                                                              \
89     }                                                                            \
90     prog->progvar = (type*)mem_a(header.hdrvar.length * sizeof(*prog->progvar)); \
91     if (!prog->progvar)                                                          \
92         goto error;                                                              \
93     if (fread(prog->progvar, sizeof(*prog->progvar), header.hdrvar.length, file) \
94         != header.hdrvar.length) {                                               \
95         perror("read");                                                          \
96         goto error;                                                              \
97     }
98 #define read_data1(x, y) read_data(x, x, y)
99
100     read_data (statements, code, prog_statement);
101     read_data1(defs,             prog_def);
102     read_data1(fields,           prog_def);
103     read_data1(functions,        prog_function);
104     read_data1(strings,          char);
105     read_data1(globals,          qcint);
106
107     fclose(file);
108
109     return prog;
110
111 error:
112     if (prog->filename)   mem_d(prog->filename);
113     if (prog->code)       mem_d(prog->code);
114     if (prog->defs)       mem_d(prog->defs);
115     if (prog->fields)     mem_d(prog->fields);
116     if (prog->functions)  mem_d(prog->functions);
117     if (prog->strings)    mem_d(prog->strings);
118     if (prog->globals)    mem_d(prog->globals);
119     if (prog->entitydata) mem_d(prog->entitydata);
120     mem_d(prog);
121     return NULL;
122 }
123
124 void prog_delete(qc_program *prog)
125 {
126     if (prog->filename)   mem_d(prog->filename);
127     if (prog->code)       mem_d(prog->code);
128     if (prog->defs)       mem_d(prog->defs);
129     if (prog->fields)     mem_d(prog->fields);
130     if (prog->functions)  mem_d(prog->functions);
131     if (prog->strings)    mem_d(prog->strings);
132     if (prog->globals)    mem_d(prog->globals);
133     if (prog->entitydata) mem_d(prog->entitydata);
134     mem_d(prog);
135 }
136
137 #if defined(QCVM_EXECUTOR)
138 int main(int argc, char **argv)
139 {
140     qc_program *prog;
141
142     if (argc != 2) {
143         printf("usage: %s prog.dat\n", argv[0]);
144         exit(1);
145     }
146
147     prog = prog_load(argv[1]);
148     if (!prog) {
149         printf("failed to load program '%s'\n", argv[1]);
150         exit(1);
151     }
152
153     prog_delete(prog);
154     return 0;
155 }
156 #endif