1 /*
2 * pr_exec.c -- PROGS execution
3 * $Id: pr_exec.c 6039 2018-05-30 04:01:21Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 1997-1998 Raven Software Corp.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24
25 // HEADER FILES ------------------------------------------------------------
26
27 #include "quakedef.h"
28 #include "q_ctype.h"
29
30 // MACROS ------------------------------------------------------------------
31
32 #define MAX_STACK_DEPTH 64 /* was 32 */
33 #define LOCALSTACK_SIZE 2048
34
35 // TYPES -------------------------------------------------------------------
36
37 typedef struct
38 {
39 int s;
40 dfunction_t *f;
41 } prstack_t;
42
43 /* switch types */
44 enum {
45 SWITCH_F,
46 SWITCH_V,
47 SWITCH_S,
48 SWITCH_E,
49 SWITCH_FNC
50 };
51
52 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
53
54 const char *PR_GlobalString(int ofs);
55 const char *PR_GlobalStringNoContents(int ofs);
56
57 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
58
59 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
60
61 static int EnterFunction(dfunction_t *f);
62 static int LeaveFunction(void);
63 static void PrintStatement(dstatement_t *s);
64 static void PrintCallHistory(void);
65
66 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
67
68 // PUBLIC DATA DEFINITIONS -------------------------------------------------
69
70 qboolean pr_trace;
71 dfunction_t *pr_xfunction;
72 int pr_xstatement;
73 int pr_argc;
74
75 // PRIVATE DATA DEFINITIONS ------------------------------------------------
76
77 static prstack_t pr_stack[MAX_STACK_DEPTH];
78 static int pr_depth;
79 static int localstack[LOCALSTACK_SIZE];
80 static int localstack_used;
81
82 static const char *pr_opnames[] =
83 {
84 "DONE",
85 "MUL_F", "MUL_V", "MUL_FV", "MUL_VF",
86 "DIV",
87 "ADD_F", "ADD_V",
88 "SUB_F", "SUB_V",
89 "EQ_F", "EQ_V", "EQ_S", "EQ_E", "EQ_FNC",
90 "NE_F", "NE_V", "NE_S", "NE_E", "NE_FNC",
91 "LE", "GE", "LT", "GT",
92 "INDIRECT", "INDIRECT", "INDIRECT",
93 "INDIRECT", "INDIRECT", "INDIRECT",
94 "ADDRESS",
95 "STORE_F", "STORE_V", "STORE_S",
96 "STORE_ENT", "STORE_FLD", "STORE_FNC",
97 "STOREP_F", "STOREP_V", "STOREP_S",
98 "STOREP_ENT", "STOREP_FLD", "STOREP_FNC",
99 "RETURN",
100 "NOT_F", "NOT_V", "NOT_S", "NOT_ENT", "NOT_FNC",
101 "IF", "IFNOT",
102 "CALL0", "CALL1", "CALL2", "CALL3", "CALL4",
103 "CALL5", "CALL6", "CALL7", "CALL8",
104 "STATE",
105 "GOTO",
106 "AND", "OR",
107 "BITAND", "BITOR",
108 "OP_MULSTORE_F", "OP_MULSTORE_V", "OP_MULSTOREP_F", "OP_MULSTOREP_V",
109 "OP_DIVSTORE_F", "OP_DIVSTOREP_F",
110 "OP_ADDSTORE_F", "OP_ADDSTORE_V", "OP_ADDSTOREP_F", "OP_ADDSTOREP_V",
111 "OP_SUBSTORE_F", "OP_SUBSTORE_V", "OP_SUBSTOREP_F", "OP_SUBSTOREP_V",
112 "OP_FETCH_GBL_F",
113 "OP_FETCH_GBL_V",
114 "OP_FETCH_GBL_S",
115 "OP_FETCH_GBL_E",
116 "OP_FETCH_GBL_FNC",
117 "OP_CSTATE", "OP_CWSTATE",
118
119 "OP_THINKTIME",
120
121 "OP_BITSET", "OP_BITSETP", "OP_BITCLR", "OP_BITCLRP",
122
123 "OP_RAND0", "OP_RAND1", "OP_RAND2", "OP_RANDV0", "OP_RANDV1", "OP_RANDV2",
124
125 "OP_SWITCH_F", "OP_SWITCH_V", "OP_SWITCH_S", "OP_SWITCH_E", "OP_SWITCH_FNC",
126
127 "OP_CASE",
128 "OP_CASERANGE"
129
130 };
131
132 // CODE --------------------------------------------------------------------
133
134 //==========================================================================
135 //
136 // PR_ExecuteProgram
137 //
138 //==========================================================================
139
140 #if 0
141 #define OPA ((eval_t *)&pr_globals[(unsigned short)st->a])
142 #define OPB ((eval_t *)&pr_globals[(unsigned short)st->b])
143 #define OPC ((eval_t *)&pr_globals[(unsigned short)st->c])
144 #else
145 /* unsigned short casts were needed with progs version 6.
146 * we are now processing progs internally as version 7. */
147 #define OPA ((eval_t *)&pr_globals[st->a])
148 #define OPB ((eval_t *)&pr_globals[st->b])
149 #define OPC ((eval_t *)&pr_globals[st->c])
150 #endif
151
PR_ExecuteProgram(func_t fnum)152 void PR_ExecuteProgram (func_t fnum)
153 {
154 eval_t *ptr, *a, *b, *c;
155 float *vecptr;
156 dstatement_t *st;
157 dfunction_t *f, *newf;
158 edict_t *ed;
159 int jump_ofs;
160 int exitdepth;
161 int profile, startprofile;
162 /* switch/case support: */
163 int case_type = -1;
164 float switch_float = 0;
165
166 if (!fnum || fnum >= progs->numfunctions)
167 {
168 if (*sv_globals.self)
169 {
170 ED_Print(PROG_TO_EDICT(*sv_globals.self));
171 }
172 Host_Error("%s: NULL function", __thisfunc__);
173 }
174
175 f = &pr_functions[fnum];
176
177 pr_trace = false;
178
179 exitdepth = pr_depth;
180
181 st = &pr_statements[EnterFunction(f)];
182 startprofile = profile = 0;
183
184 while (1)
185 {
186 st++; /* next statement */
187 a = OPA;
188 b = OPB;
189 c = OPC;
190
191 if (++profile > 100000)
192 {
193 pr_xstatement = st - pr_statements;
194 PR_RunError("runaway loop error");
195 }
196
197 if (pr_trace)
198 {
199 PrintStatement(st);
200 }
201
202 switch (st->op)
203 {
204 case OP_ADD_F:
205 c->_float = a->_float + b->_float;
206 break;
207 case OP_ADD_V:
208 c->vector[0] = a->vector[0] + b->vector[0];
209 c->vector[1] = a->vector[1] + b->vector[1];
210 c->vector[2] = a->vector[2] + b->vector[2];
211 break;
212
213 case OP_SUB_F:
214 c->_float = a->_float - b->_float;
215 break;
216 case OP_SUB_V:
217 c->vector[0] = a->vector[0] - b->vector[0];
218 c->vector[1] = a->vector[1] - b->vector[1];
219 c->vector[2] = a->vector[2] - b->vector[2];
220 break;
221
222 case OP_MUL_F:
223 c->_float = a->_float * b->_float;
224 break;
225 case OP_MUL_V:
226 c->_float = a->vector[0] * b->vector[0] +
227 a->vector[1] * b->vector[1] +
228 a->vector[2] * b->vector[2];
229 break;
230 case OP_MUL_FV:
231 c->vector[0] = a->_float * b->vector[0];
232 c->vector[1] = a->_float * b->vector[1];
233 c->vector[2] = a->_float * b->vector[2];
234 break;
235 case OP_MUL_VF:
236 c->vector[0] = b->_float * a->vector[0];
237 c->vector[1] = b->_float * a->vector[1];
238 c->vector[2] = b->_float * a->vector[2];
239 break;
240
241 case OP_DIV_F:
242 c->_float = a->_float / b->_float;
243 break;
244
245 case OP_BITAND:
246 c->_float = (int)a->_float & (int)b->_float;
247 break;
248
249 case OP_BITOR:
250 c->_float = (int)a->_float | (int)b->_float;
251 break;
252
253 case OP_GE:
254 c->_float = a->_float >= b->_float;
255 break;
256 case OP_LE:
257 c->_float = a->_float <= b->_float;
258 break;
259 case OP_GT:
260 c->_float = a->_float > b->_float;
261 break;
262 case OP_LT:
263 c->_float = a->_float < b->_float;
264 break;
265 case OP_AND:
266 c->_float = a->_float && b->_float;
267 break;
268 case OP_OR:
269 c->_float = a->_float || b->_float;
270 break;
271
272 case OP_NOT_F:
273 c->_float = !a->_float;
274 break;
275 case OP_NOT_V:
276 c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];
277 break;
278 case OP_NOT_S:
279 c->_float = !a->string || !*PR_GetString(a->string);
280 break;
281 case OP_NOT_FNC:
282 c->_float = !a->function;
283 break;
284 case OP_NOT_ENT:
285 c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);
286 break;
287
288 case OP_EQ_F:
289 c->_float = a->_float == b->_float;
290 break;
291 case OP_EQ_V:
292 c->_float = (a->vector[0] == b->vector[0]) &&
293 (a->vector[1] == b->vector[1]) &&
294 (a->vector[2] == b->vector[2]);
295 break;
296 case OP_EQ_S:
297 c->_float = !strcmp(PR_GetString(a->string), PR_GetString(b->string));
298 break;
299 case OP_EQ_E:
300 c->_float = a->_int == b->_int;
301 break;
302 case OP_EQ_FNC:
303 c->_float = a->function == b->function;
304 break;
305
306 case OP_NE_F:
307 c->_float = a->_float != b->_float;
308 break;
309 case OP_NE_V:
310 c->_float = (a->vector[0] != b->vector[0]) ||
311 (a->vector[1] != b->vector[1]) ||
312 (a->vector[2] != b->vector[2]);
313 break;
314 case OP_NE_S:
315 c->_float = strcmp(PR_GetString(a->string), PR_GetString(b->string));
316 break;
317 case OP_NE_E:
318 c->_float = a->_int != b->_int;
319 break;
320 case OP_NE_FNC:
321 c->_float = a->function != b->function;
322 break;
323
324 case OP_STORE_F:
325 case OP_STORE_ENT:
326 case OP_STORE_FLD: // integers
327 case OP_STORE_S:
328 case OP_STORE_FNC: // pointers
329 b->_int = a->_int;
330 break;
331 case OP_STORE_V:
332 b->vector[0] = a->vector[0];
333 b->vector[1] = a->vector[1];
334 b->vector[2] = a->vector[2];
335 break;
336
337 case OP_STOREP_F:
338 case OP_STOREP_ENT:
339 case OP_STOREP_FLD: // integers
340 case OP_STOREP_S:
341 case OP_STOREP_FNC: // pointers
342 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
343 ptr->_int = a->_int;
344 break;
345 case OP_STOREP_V:
346 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
347 ptr->vector[0] = a->vector[0];
348 ptr->vector[1] = a->vector[1];
349 ptr->vector[2] = a->vector[2];
350 break;
351
352 case OP_MULSTORE_F: // f *= f
353 b->_float *= a->_float;
354 break;
355 case OP_MULSTORE_V: // v *= f
356 b->vector[0] *= a->_float;
357 b->vector[1] *= a->_float;
358 b->vector[2] *= a->_float;
359 break;
360 case OP_MULSTOREP_F: // e.f *= f
361 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
362 c->_float = (ptr->_float *= a->_float);
363 break;
364 case OP_MULSTOREP_V: // e.v *= f
365 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
366 c->vector[0] = (ptr->vector[0] *= a->_float);
367 c->vector[0] = (ptr->vector[1] *= a->_float);
368 c->vector[0] = (ptr->vector[2] *= a->_float);
369 break;
370
371 case OP_DIVSTORE_F: // f /= f
372 b->_float /= a->_float;
373 break;
374 case OP_DIVSTOREP_F: // e.f /= f
375 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
376 c->_float = (ptr->_float /= a->_float);
377 break;
378
379 case OP_ADDSTORE_F: // f += f
380 b->_float += a->_float;
381 break;
382 case OP_ADDSTORE_V: // v += v
383 b->vector[0] += a->vector[0];
384 b->vector[1] += a->vector[1];
385 b->vector[2] += a->vector[2];
386 break;
387 case OP_ADDSTOREP_F: // e.f += f
388 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
389 c->_float = (ptr->_float += a->_float);
390 break;
391 case OP_ADDSTOREP_V: // e.v += v
392 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
393 c->vector[0] = (ptr->vector[0] += a->vector[0]);
394 c->vector[1] = (ptr->vector[1] += a->vector[1]);
395 c->vector[2] = (ptr->vector[2] += a->vector[2]);
396 break;
397
398 case OP_SUBSTORE_F: // f -= f
399 b->_float -= a->_float;
400 break;
401 case OP_SUBSTORE_V: // v -= v
402 b->vector[0] -= a->vector[0];
403 b->vector[1] -= a->vector[1];
404 b->vector[2] -= a->vector[2];
405 break;
406 case OP_SUBSTOREP_F: // e.f -= f
407 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
408 c->_float = (ptr->_float -= a->_float);
409 break;
410 case OP_SUBSTOREP_V: // e.v -= v
411 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
412 c->vector[0] = (ptr->vector[0] -= a->vector[0]);
413 c->vector[1] = (ptr->vector[1] -= a->vector[1]);
414 c->vector[2] = (ptr->vector[2] -= a->vector[2]);
415 break;
416
417 case OP_ADDRESS:
418 ed = PROG_TO_EDICT(a->edict);
419 #ifdef PARANOID
420 NUM_FOR_EDICT(ed); // Make sure it's in range
421 #endif
422 if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
423 {
424 pr_xstatement = st - pr_statements;
425 PR_RunError("assignment to world entity");
426 }
427 c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts;
428 break;
429
430 case OP_LOAD_F:
431 case OP_LOAD_FLD:
432 case OP_LOAD_ENT:
433 case OP_LOAD_S:
434 case OP_LOAD_FNC:
435 ed = PROG_TO_EDICT(a->edict);
436 #ifdef PARANOID
437 NUM_FOR_EDICT(ed); // Make sure it's in range
438 #endif
439 ptr = (eval_t *)((int *)&ed->v + b->_int);
440 c->_int = ptr->_int;
441 break;
442
443 case OP_LOAD_V:
444 ed = PROG_TO_EDICT(a->edict);
445 #ifdef PARANOID
446 NUM_FOR_EDICT(ed); // Make sure it's in range
447 #endif
448 ptr = (eval_t *)((int *)&ed->v + b->_int);
449 c->vector[0] = ptr->vector[0];
450 c->vector[1] = ptr->vector[1];
451 c->vector[2] = ptr->vector[2];
452 break;
453
454 case OP_FETCH_GBL_F:
455 case OP_FETCH_GBL_S:
456 case OP_FETCH_GBL_E:
457 case OP_FETCH_GBL_FNC:
458 { int i = (int)b->_float;
459 if (i < 0 || i > G_INT(st->a - 1))
460 {
461 pr_xstatement = st - pr_statements;
462 PR_RunError("array index out of bounds: %d", i);
463 }
464 ptr = (eval_t *)&pr_globals[st->a + i];
465 c->_int = ptr->_int;
466 } break;
467 case OP_FETCH_GBL_V:
468 { int i = (int)b->_float;
469 if (i < 0 || i > G_INT(st->a - 1))
470 {
471 pr_xstatement = st - pr_statements;
472 PR_RunError("array index out of bounds: %d", i);
473 }
474 ptr = (eval_t *)&pr_globals[st->a + (i * 3)];
475 c->vector[0] = ptr->vector[0];
476 c->vector[1] = ptr->vector[1];
477 c->vector[2] = ptr->vector[2];
478 } break;
479
480 case OP_IFNOT:
481 if (!a->_int)
482 {
483 /* Pa3PyX: a, b, and c used to be signed shorts for progs v6,
484 * now they are signed ints. The problem is, they were used
485 * as signed sometimes and as unsigned other times - most of
486 * the time they were used as unsigned with an explicit cast
487 * in PR_ExecuteProgram(). When we convert the old progs to
488 * to the new format in PR_ConvertOldStmts(), we zero-extend
489 * them instead of sign-extending them for that reason: if we
490 * sign-extend them, most of the code will not work - we will
491 * have negative array offsets in PR_ExecuteProgram(), among
492 * other things. Note that they are cast to unsigned short
493 * in PR_ConvertOldStmts() prior to assigning them to what is
494 * now int. There are a few instances where these shorts are
495 * used as signed as in the case below where negative offsets
496 * are needed. Since we now have a zero-extended number in a,
497 * b, and c, we must change it back to signed short, so that
498 * when it is added with and assigned to an int, the result
499 * ends up sign-extended and we get a proper negative offset,
500 * if there is one.
501 */
502 jump_ofs = st->b;
503 if (is_progs_v6) jump_ofs = (signed short)jump_ofs;
504 st += jump_ofs - 1; /* -1 to offset the st++ */
505 }
506 break;
507
508 case OP_IF:
509 if (a->_int)
510 {
511 jump_ofs = st->b;
512 if (is_progs_v6) jump_ofs = (signed short)jump_ofs;
513 st += jump_ofs - 1; /* -1 to offset the st++ */
514 }
515 break;
516
517 case OP_GOTO:
518 jump_ofs = st->a;
519 if (is_progs_v6) jump_ofs = (signed short)jump_ofs;
520 st += jump_ofs - 1; /* -1 to offset the st++ */
521 break;
522
523 case OP_CALL8:
524 case OP_CALL7:
525 case OP_CALL6:
526 case OP_CALL5:
527 case OP_CALL4:
528 case OP_CALL3:
529 case OP_CALL2: // Copy second arg to shared space
530 vecptr = G_VECTOR(OFS_PARM1);
531 VectorCopy(c->vector, vecptr);
532 case OP_CALL1: // Copy first arg to shared space
533 vecptr = G_VECTOR(OFS_PARM0);
534 VectorCopy(b->vector, vecptr);
535 case OP_CALL0:
536 pr_xfunction->profile += profile - startprofile;
537 startprofile = profile;
538 pr_xstatement = st - pr_statements;
539 pr_argc = st->op - OP_CALL0;
540 if (!a->function)
541 {
542 PR_RunError("NULL function");
543 }
544 newf = &pr_functions[a->function];
545 if (newf->first_statement < 0)
546 { // Built-in function
547 int i = -newf->first_statement;
548 if (i >= pr_numbuiltins)
549 {
550 PR_RunError("Bad builtin call number %d", i);
551 }
552 pr_builtins[i]();
553 break;
554 }
555 // Normal function
556 st = &pr_statements[EnterFunction(newf)];
557 break;
558
559 case OP_DONE:
560 case OP_RETURN:
561 {
562 float *retptr = &pr_globals[OFS_RETURN];
563 float *valptr = &pr_globals[st->a];
564 pr_xfunction->profile += profile - startprofile;
565 startprofile = profile;
566 pr_xstatement = st - pr_statements;
567 *retptr++ = *valptr++;
568 *retptr++ = *valptr++;
569 *retptr = *valptr;
570 st = &pr_statements[LeaveFunction()];
571 if (pr_depth == exitdepth)
572 { // Done
573 return;
574 }
575 } break;
576
577 case OP_STATE:
578 ed = PROG_TO_EDICT(*sv_globals.self);
579 /* Id 1.07 changes
580 #ifdef FPS_20
581 ed->v.nextthink = *sv_globals.time + 0.05;
582 #else
583 ed->v.nextthink = *sv_globals.time + 0.1;
584 #endif
585 */
586 ed->v.nextthink = *sv_globals.time + HX_FRAME_TIME;
587 ed->v.frame = a->_float;
588 ed->v.think = b->function;
589 break;
590
591 case OP_CSTATE: // Cycle state
592 { int startFrame, endFrame;
593 ed = PROG_TO_EDICT(*sv_globals.self);
594 ed->v.nextthink = *sv_globals.time + HX_FRAME_TIME;
595 ed->v.think = pr_xfunction - pr_functions;
596 *sv_globals.cycle_wrapped = false;
597 startFrame = (int)a->_float;
598 endFrame = (int)b->_float;
599 if (startFrame <= endFrame)
600 { // Increment
601 if (ed->v.frame < startFrame || ed->v.frame > endFrame)
602 {
603 ed->v.frame = startFrame;
604 }
605 else
606 {
607 ed->v.frame++;
608 if (ed->v.frame > endFrame)
609 {
610 *sv_globals.cycle_wrapped = true;
611 ed->v.frame = startFrame;
612 }
613 }
614 }
615 else
616 { // Decrement
617 if (ed->v.frame > startFrame || ed->v.frame < endFrame)
618 {
619 ed->v.frame = startFrame;
620 }
621 else
622 {
623 ed->v.frame--;
624 if (ed->v.frame < endFrame)
625 {
626 *sv_globals.cycle_wrapped = true;
627 ed->v.frame = startFrame;
628 }
629 }
630 }
631 } break;
632
633 case OP_CWSTATE: // Cycle weapon state
634 { int startFrame, endFrame;
635 ed = PROG_TO_EDICT(*sv_globals.self);
636 ed->v.nextthink = *sv_globals.time + HX_FRAME_TIME;
637 ed->v.think = pr_xfunction - pr_functions;
638 *sv_globals.cycle_wrapped = false;
639 startFrame = (int)a->_float;
640 endFrame = (int)b->_float;
641 if (startFrame <= endFrame)
642 { // Increment
643 if (ed->v.weaponframe < startFrame
644 || ed->v.weaponframe > endFrame)
645 {
646 ed->v.weaponframe = startFrame;
647 }
648 else
649 {
650 ed->v.weaponframe++;
651 if (ed->v.weaponframe > endFrame)
652 {
653 *sv_globals.cycle_wrapped = true;
654 ed->v.weaponframe = startFrame;
655 }
656 }
657 }
658 else
659 { // Decrement
660 if (ed->v.weaponframe > startFrame
661 || ed->v.weaponframe < endFrame)
662 {
663 ed->v.weaponframe = startFrame;
664 }
665 else
666 {
667 ed->v.weaponframe--;
668 if (ed->v.weaponframe < endFrame)
669 {
670 *sv_globals.cycle_wrapped = true;
671 ed->v.weaponframe = startFrame;
672 }
673 }
674 }
675 } break;
676
677 case OP_THINKTIME:
678 ed = PROG_TO_EDICT(a->edict);
679 #ifdef PARANOID
680 NUM_FOR_EDICT(ed); // Make sure it's in range
681 #endif
682 if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
683 {
684 pr_xstatement = st - pr_statements;
685 PR_RunError("assignment to world entity");
686 }
687 ed->v.nextthink = *sv_globals.time + b->_float;
688 break;
689
690 case OP_BITSET: // f (+) f
691 b->_float = (int)b->_float | (int)a->_float;
692 break;
693 case OP_BITSETP: // e.f (+) f
694 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
695 ptr->_float = (int)ptr->_float | (int)a->_float;
696 break;
697 case OP_BITCLR: // f (-) f
698 b->_float = (int)b->_float & ~((int)a->_float);
699 break;
700 case OP_BITCLRP: // e.f (-) f
701 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
702 ptr->_float = (int)ptr->_float & ~((int)a->_float);
703 break;
704
705 case OP_RAND0:
706 { float val;
707 val = rand() * (1.0 / RAND_MAX);
708 G_FLOAT(OFS_RETURN) = val;
709 } break;
710 case OP_RAND1:
711 { float val;
712 val = rand() * (1.0 / RAND_MAX) * a->_float;
713 G_FLOAT(OFS_RETURN) = val;
714 } break;
715 case OP_RAND2:
716 { float val;
717 if (a->_float < b->_float)
718 {
719 val = a->_float + (rand() * (1.0 / RAND_MAX) * (b->_float - a->_float));
720 }
721 else
722 {
723 val = b->_float + (rand() * (1.0 / RAND_MAX) * (a->_float - b->_float));
724 }
725 G_FLOAT(OFS_RETURN) = val;
726 } break;
727 case OP_RANDV0:
728 { float val;
729 float *retptr = &G_FLOAT(OFS_RETURN);
730 val = rand() * (1.0 / RAND_MAX);
731 *retptr++ = val;
732 val = rand() * (1.0 / RAND_MAX);
733 *retptr++ = val;
734 val = rand() * (1.0 / RAND_MAX);
735 *retptr = val;
736 } break;
737 case OP_RANDV1:
738 { float val;
739 float *retptr = &G_FLOAT(OFS_RETURN);
740 val = rand() * (1.0 / RAND_MAX) * a->vector[0];
741 *retptr++ = val;
742 val = rand() * (1.0 / RAND_MAX) * a->vector[1];
743 *retptr++ = val;
744 val = rand() * (1.0 / RAND_MAX) * a->vector[2];
745 *retptr = val;
746 } break;
747 case OP_RANDV2:
748 { float val;
749 int i;
750 float *retptr = &G_FLOAT(OFS_RETURN);
751 for (i = 0; i < 3; i++)
752 {
753 if (a->vector[i] < b->vector[i])
754 {
755 val = a->vector[i] + (rand() * (1.0 / RAND_MAX) * (b->vector[i] - a->vector[i]));
756 }
757 else
758 {
759 val = b->vector[i] + (rand() * (1.0 / RAND_MAX) * (a->vector[i] - b->vector[i]));
760 }
761 *retptr++ = val;
762 }
763 } break;
764 case OP_SWITCH_F:
765 case_type = SWITCH_F;
766 switch_float = a->_float;
767 jump_ofs = st->b;
768 if (is_progs_v6) jump_ofs = (signed short)jump_ofs;
769 st += jump_ofs - 1; /* -1 to offset the st++ */
770 break;
771 case OP_SWITCH_V:
772 case OP_SWITCH_S:
773 case OP_SWITCH_E:
774 case OP_SWITCH_FNC:
775 pr_xstatement = st - pr_statements;
776 PR_RunError("%s not done yet!", pr_opnames[st->op]);
777 break;
778
779 case OP_CASERANGE:
780 if (case_type != SWITCH_F)
781 {
782 pr_xstatement = st - pr_statements;
783 PR_RunError("caserange fucked!");
784 }
785 if ((switch_float >= a->_float) && (switch_float <= b->_float))
786 {
787 jump_ofs = st->c;
788 if (is_progs_v6) jump_ofs = (signed short)jump_ofs;
789 st += jump_ofs - 1; /* -1 to offset the st++ */
790 }
791 break;
792 case OP_CASE:
793 switch (case_type)
794 {
795 case SWITCH_F:
796 if (switch_float == a->_float)
797 {
798 jump_ofs = st->b;
799 if (is_progs_v6) jump_ofs = (signed short)jump_ofs;
800 st += jump_ofs - 1; /* -1 to offset the st++ */
801 }
802 break;
803 case SWITCH_V:
804 case SWITCH_S:
805 case SWITCH_E:
806 case SWITCH_FNC:
807 pr_xstatement = st - pr_statements;
808 PR_RunError("OP_CASE for %s not done yet!",
809 pr_opnames[case_type + OP_SWITCH_F - SWITCH_F]);
810 break;
811 default:
812 pr_xstatement = st - pr_statements;
813 PR_RunError("fucked case!");
814 }
815 break;
816
817 default:
818 pr_xstatement = st - pr_statements;
819 PR_RunError("Bad opcode %i", st->op);
820 }
821 } /* end of while(1) loop */
822 }
823 #undef OPA
824 #undef OPB
825 #undef OPC
826
827
828 //==========================================================================
829 //
830 // EnterFunction
831 //
832 //==========================================================================
833
EnterFunction(dfunction_t * f)834 static int EnterFunction (dfunction_t *f)
835 {
836 int i, j, c, o;
837
838 pr_stack[pr_depth].s = pr_xstatement;
839 pr_stack[pr_depth].f = pr_xfunction;
840 pr_depth++;
841 if (pr_depth >= MAX_STACK_DEPTH)
842 {
843 PR_RunError("stack overflow");
844 }
845
846 // save off any locals that the new function steps on
847 c = f->locals;
848 if (localstack_used + c > LOCALSTACK_SIZE)
849 {
850 PR_RunError ("%s: locals stack overflow", __thisfunc__);
851 }
852
853 for (i = 0; i < c ; i++)
854 {
855 localstack[localstack_used + i] = ((int *)pr_globals)[f->parm_start + i];
856 }
857 localstack_used += c;
858
859 // copy parameters
860 o = f->parm_start;
861 for (i = 0; i < f->numparms; i++)
862 {
863 for (j = 0; j < f->parm_size[i]; j++)
864 {
865 ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0 + i*3 + j];
866 o++;
867 }
868 }
869
870 pr_xfunction = f;
871 return f->first_statement - 1; // offset the s++
872 }
873
874
875 //==========================================================================
876 //
877 // LeaveFunction
878 //
879 //==========================================================================
880
LeaveFunction(void)881 static int LeaveFunction (void)
882 {
883 int i, c;
884
885 if (pr_depth <= 0)
886 {
887 Host_Error("prog stack underflow");
888 }
889
890 // Restore locals from the stack
891 c = pr_xfunction->locals;
892 localstack_used -= c;
893 if (localstack_used < 0)
894 {
895 PR_RunError("%s: locals stack underflow", __thisfunc__);
896 }
897
898 for (i = 0; i < c; i++)
899 {
900 ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used + i];
901 }
902
903 // up stack
904 pr_depth--;
905 pr_xfunction = pr_stack[pr_depth].f;
906 return pr_stack[pr_depth].s;
907 }
908
909
910 //==========================================================================
911 //
912 // PR_RunError
913 //
914 //==========================================================================
915
PR_RunError(const char * error,...)916 void PR_RunError (const char *error, ...)
917 {
918 va_list argptr;
919 char string[1024];
920
921 va_start (argptr, error);
922 q_vsnprintf (string, sizeof(string), error, argptr);
923 va_end (argptr);
924
925 PrintStatement(pr_statements + pr_xstatement);
926 PrintCallHistory();
927
928 Con_Printf("%s\n", string);
929
930 pr_depth = 0; // dump the stack so host_error can shutdown functions
931
932 Host_Error("Program error");
933 }
934
935
936 //==========================================================================
937 //
938 // PrintCallHistory
939 //
940 //==========================================================================
941
PrintCallHistory(void)942 static void PrintCallHistory (void)
943 {
944 int i;
945 dfunction_t *f;
946
947 if (pr_depth == 0)
948 {
949 Con_Printf("<NO STACK>\n");
950 return;
951 }
952
953 pr_stack[pr_depth].f = pr_xfunction;
954 for (i = pr_depth; i >= 0; i--)
955 {
956 f = pr_stack[i].f;
957 if (!f)
958 {
959 Con_Printf("<NO FUNCTION>\n");
960 }
961 else
962 {
963 Con_Printf("%12s : %s\n", PR_GetString(f->s_file), PR_GetString(f->s_name));
964 }
965 }
966 }
967
968
969 //==========================================================================
970 //
971 // PrintStatement
972 //
973 //==========================================================================
974
PrintStatement(dstatement_t * s)975 static void PrintStatement (dstatement_t *s)
976 {
977 int i;
978
979 if ((unsigned int)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))
980 {
981 Con_Printf("%s ", pr_opnames[s->op]);
982 i = strlen(pr_opnames[s->op]);
983 for ( ; i < 10; i++)
984 {
985 Con_Printf(" ");
986 }
987 }
988
989 if (s->op == OP_IF || s->op == OP_IFNOT)
990 {
991 Con_Printf("%sbranch %i", PR_GlobalString(s->a), s->b);
992 }
993 else if (s->op == OP_GOTO)
994 {
995 Con_Printf("branch %i", s->a);
996 }
997 else if ((unsigned int)(s->op-OP_STORE_F) < 6)
998 {
999 Con_Printf("%s", PR_GlobalString(s->a));
1000 Con_Printf("%s", PR_GlobalStringNoContents(s->b));
1001 }
1002 else
1003 {
1004 if (s->a)
1005 {
1006 Con_Printf("%s", PR_GlobalString(s->a));
1007 }
1008 if (s->b)
1009 {
1010 Con_Printf("%s", PR_GlobalString(s->b));
1011 }
1012 if (s->c)
1013 {
1014 Con_Printf("%s", PR_GlobalStringNoContents(s->c));
1015 }
1016 }
1017 Con_Printf("\n");
1018 }
1019
1020
1021 //==========================================================================
1022 //
1023 // PR_Profile_f
1024 //
1025 //==========================================================================
1026
PR_Profile_f(void)1027 void PR_Profile_f (void)
1028 {
1029 int i, j;
1030 int pmax;
1031 dfunction_t *f, *bestFunc;
1032 int total;
1033 int funcCount;
1034 qboolean byHC;
1035 const char *saveName = NULL;
1036 FILE *saveFile = NULL;
1037 int currentFile;
1038 int bestFile;
1039 int tally;
1040 const char *s;
1041
1042 if (!sv.active)
1043 return;
1044
1045 byHC = false;
1046 funcCount = 10;
1047 for (i = 1; i < Cmd_Argc(); i++)
1048 {
1049 s = Cmd_Argv(i);
1050 if (*s == 'h' || *s == 'H')
1051 { // Sort by HC source file
1052 byHC = true;
1053 }
1054 else if (*s == 's' || *s == 'S')
1055 { // Save to file
1056 if (i + 1 < Cmd_Argc() && !q_isdigit(*Cmd_Argv(i + 1)))
1057 {
1058 i++;
1059 saveName = FS_MakePath(FS_USERDIR, NULL, Cmd_Argv(i));
1060 }
1061 else
1062 {
1063 saveName = FS_MakePath(FS_USERDIR, NULL, "profile.txt");
1064 }
1065 }
1066 else if (q_isdigit(*s))
1067 { // Specify function count
1068 funcCount = atoi(Cmd_Argv(i));
1069 if (funcCount < 1)
1070 {
1071 funcCount = 1;
1072 }
1073 }
1074 }
1075
1076 total = 0;
1077 for (i = 0; i < progs->numfunctions; i++)
1078 {
1079 total += pr_functions[i].profile;
1080 }
1081
1082 if (saveName)
1083 { // Create the output file
1084 saveFile = fopen(saveName, "w");
1085 if (saveFile == NULL)
1086 Con_Printf("Could not open %s\n", saveName);
1087 }
1088
1089 if (byHC == false)
1090 {
1091 j = 0;
1092 do
1093 {
1094 pmax = 0;
1095 bestFunc = NULL;
1096 for (i = 0; i < progs->numfunctions; i++)
1097 {
1098 f = &pr_functions[i];
1099 if (f->profile > pmax)
1100 {
1101 pmax = f->profile;
1102 bestFunc = f;
1103 }
1104 }
1105 if (bestFunc)
1106 {
1107 if (j < funcCount)
1108 {
1109 if (saveFile)
1110 {
1111 fprintf(saveFile, "%05.2f %s\n",
1112 ((float)bestFunc->profile / (float)total) * 100.0,
1113 PR_GetString(bestFunc->s_name));
1114 }
1115 else
1116 {
1117 Con_Printf("%05.2f %s\n",
1118 ((float)bestFunc->profile / (float)total) * 100.0,
1119 PR_GetString(bestFunc->s_name));
1120 }
1121 }
1122 j++;
1123 bestFunc->profile = 0;
1124 }
1125 } while (bestFunc);
1126
1127 if (saveFile)
1128 {
1129 fclose(saveFile);
1130 }
1131 return;
1132 }
1133
1134 currentFile = -1;
1135 do
1136 {
1137 tally = 0;
1138 bestFile = Q_MAXINT;
1139 for (i = 0; i < progs->numfunctions; i++)
1140 {
1141 if (pr_functions[i].s_file > currentFile
1142 && pr_functions[i].s_file < bestFile)
1143 {
1144 bestFile = pr_functions[i].s_file;
1145 tally = pr_functions[i].profile;
1146 continue;
1147 }
1148 if (pr_functions[i].s_file == bestFile)
1149 {
1150 tally += pr_functions[i].profile;
1151 }
1152 }
1153 currentFile = bestFile;
1154 if (tally && currentFile != Q_MAXINT)
1155 {
1156 if (saveFile)
1157 {
1158 fprintf(saveFile, "\"%s\"\n", PR_GetString(currentFile));
1159 }
1160 else
1161 {
1162 Con_Printf("\"%s\"\n", PR_GetString(currentFile));
1163 }
1164
1165 j = 0;
1166 do
1167 {
1168 pmax = 0;
1169 bestFunc = NULL;
1170 for (i = 0; i < progs->numfunctions; i++)
1171 {
1172 f = &pr_functions[i];
1173 if (f->s_file == currentFile && f->profile > pmax)
1174 {
1175 pmax = f->profile;
1176 bestFunc = f;
1177 }
1178 }
1179 if (bestFunc)
1180 {
1181 if (j < funcCount)
1182 {
1183 if (saveFile)
1184 {
1185 fprintf(saveFile, " %05.2f %s\n",
1186 ((float)bestFunc->profile / (float)total) * 100.0,
1187 PR_GetString(bestFunc->s_name));
1188 }
1189 else
1190 {
1191 Con_Printf(" %05.2f %s\n",
1192 ((float)bestFunc->profile / (float)total) * 100.0,
1193 PR_GetString(bestFunc->s_name));
1194 }
1195 }
1196 j++;
1197 bestFunc->profile = 0;
1198 }
1199 } while (bestFunc);
1200 }
1201 } while (currentFile != Q_MAXINT);
1202
1203 if (saveFile)
1204 {
1205 fclose(saveFile);
1206 }
1207 }
1208
1209