-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.c
221 lines (184 loc) · 5.33 KB
/
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//This is basically a sample program.
//It deomnstrates the code required to get qclib up and running.
//This code does not demonstrate entities, however.
//It does demonstrate the built in qc compiler, and does demonstrate a globals-only progs interface.
//It also demonstrates basic builtin(s).
#include "progtype.h"
#include "progslib.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
//builtins and builtin management.
void PF_prints (progfuncs_t *prinst, struct globalvars_s *gvars)
{
char *s;
s = prinst->VarString(prinst, 0);
printf("%s", s);
}
void PF_printv (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
printf("%f %f %f\n", G_FLOAT(OFS_PARM0+0), G_FLOAT(OFS_PARM0+1), G_FLOAT(OFS_PARM0+2));
}
void PF_printf (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
printf("%f\n", G_FLOAT(OFS_PARM0));
}
void PF_bad (progfuncs_t *prinst, struct globalvars_s *gvars)
{
printf("bad builtin\n");
}
builtin_t builtins[] = {
PF_bad,
PF_prints,
PF_printv,
PF_printf
};
//Called when the qc library has some sort of serious error.
void Sys_Abort(char *s, ...)
{ //quake handles this with a longjmp.
va_list ap;
va_start(ap, s);
vprintf(s, ap);
va_end(ap);
exit(1);
}
//Called when the library has something to say.
//Kinda required for the compiler...
//Not really that useful for the normal vm.
int Sys_Printf(char *s, ...)
{ //look up quake's va function to find out how to deal with variable arguments properly.
return printf("%s", s);
}
#include <stdio.h>
//copy file into buffer. note that the buffer will have been sized to fit the file (obtained via FileSize)
unsigned char *Sys_ReadFile (char *fname, void *buffer, int buflen)
{
int len;
FILE *f;
if (!strncmp(fname, "src/", 4))
fname+=4; //skip the src part
f = fopen(fname, "rb");
if (!f)
return NULL;
fseek(f, 0, SEEK_END);
len = ftell(f);
if (buflen < len)
return NULL;
fseek(f, 0, SEEK_SET);
fread(buffer, 1, len, f);
fclose(f);
return buffer;
}
//Finds the size of a file.
int Sys_FileSize (char *fname)
{
int len;
FILE *f;
if (!strncmp(fname, "src/", 4))
fname+=4; //skip the src part
f = fopen(fname, "rb");
if (!f)
return -1;
fseek(f, 0, SEEK_END);
len = ftell(f);
fclose(f);
return len;
}
//Writes a file.
pbool Sys_WriteFile (char *fname, void *data, int len)
{
FILE *f;
f = fopen(fname, "wb");
if (!f)
return 0;
fwrite(data, 1, len, f);
fclose(f);
return 1;
}
void runtest(char *progsname)
{
progfuncs_t *pf;
func_t func;
progsnum_t pn;
progparms_t ext;
memset(&ext, 0, sizeof(ext));
ext.progsversion = PROGSTRUCT_VERSION;
ext.ReadFile = Sys_ReadFile;
ext.FileSize= Sys_FileSize;
ext.Abort = Sys_Abort;
ext.printf = printf;
ext.numglobalbuiltins = sizeof(builtins)/sizeof(builtins[0]);
ext.globalbuiltins = builtins;
pf = InitProgs(&ext);
pf->Configure(pf, 1024*1024, 1); //memory quantity of 1mb. Maximum progs loadable into the instance of 1
//If you support multiple progs types, you should tell the VM the offsets here, via RegisterFieldVar
pn = pf->LoadProgs(pf, progsname, 0, NULL, 0); //load the progs, don't care about the crc, and use those builtins.
if (pn < 0)
printf("test: Failed to load progs \"%s\"\n", progsname);
else
{
//allocate qc-acessable strings here for 64bit cpus. (allocate via AddString, tempstringbase is a holding area not used by the actual vm)
//you can call functions before InitEnts if you want. it's not really advised for anything except naming additional progs. This sample only allows one max.
pf->InitEnts(pf, 10); //Now we know how many fields required, we can say how many maximum ents we want to allow. 10 in this case. This can be huge without too many problems.
//now it's safe to ED_Alloc.
func = pf->FindFunction(pf, "main", PR_ANY); //find the function 'main' in the first progs that has it.
if (!func)
printf("Couldn't find function\n");
else
pf->ExecuteProgram(pf, func); //call the function
}
CloseProgs(pf);
}
//Run a compiler and nothing else.
//Note that this could be done with an autocompile of PR_COMPILEALWAYS.
void compile(int argc, char **argv)
{
progfuncs_t *pf;
progparms_t ext;
if (0)
{
char *testsrcfile = //newstyle progs.src must start with a #.
//it's newstyle to avoid using multiple source files.
"#pragma PROGS_DAT \"testprogs.dat\"\r\n"
"//INTERMEDIATE FILE - EDIT TEST.C INSTEAD\r\n"
"\r\n"
"void(...) print = #1;\r\n"
"void() main =\r\n"
"{\r\n"
" print(\"hello world\\n\");\r\n"
"};\r\n";
//so that the file exists. We could insert it via the callbacks instead
Sys_WriteFile("progs.src", testsrcfile, strlen(testsrcfile));
}
memset(&ext, 0, sizeof(ext));
ext.progsversion = PROGSTRUCT_VERSION;
ext.ReadFile = Sys_ReadFile;
ext.FileSize= Sys_FileSize;
ext.WriteFile= Sys_WriteFile;
ext.Abort = Sys_Abort;
ext.printf = printf;
pf = InitProgs(&ext);
if (pf->StartCompile)
{
if (pf->StartCompile(pf, argc, argv))
{
while(pf->ContinueCompile(pf) == 1)
;
}
}
else
printf("no compiler in this qcvm build\n");
CloseProgs(pf);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Invalid arguments!\nPlease run as, for example:\n%s testprogs.dat -srcfile progs.src\nThe first argument is the name of the progs.dat to run, the remaining arguments are the qcc args to use", argv[0]);
return 0;
}
compile(argc-1, argv+1);
runtest(argv[1]);
return 0;
}