PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/quakeforge/branches/release_0_5_2/libs/gamecode/engine/pr_exec.c

#
C | 907 lines | 746 code | 75 blank | 86 comment | 102 complexity | 28d2f2ce95c889b9b608c4b8cabfb718 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0, AGPL-1.0, Unlicense
  1. /*
  2. pr_exec.c
  3. (description)
  4. Copyright (C) 1996-1997 Id Software, Inc.
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. See the GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to:
  15. Free Software Foundation, Inc.
  16. 59 Temple Place - Suite 330
  17. Boston, MA 02111-1307, USA
  18. */
  19. static const char rcsid[] =
  20. "$Id: pr_exec.c 8535 2002-09-14 07:51:53Z taniwha $";
  21. #ifdef HAVE_CONFIG_H
  22. # include "config.h"
  23. #endif
  24. #ifdef HAVE_STRING_H
  25. # include <string.h>
  26. #endif
  27. #ifdef HAVE_STRINGS_H
  28. # include <strings.h>
  29. #endif
  30. #include <stdarg.h>
  31. #include "QF/cvar.h"
  32. #include "QF/dstring.h"
  33. #include "QF/mathlib.h"
  34. #include "QF/progs.h"
  35. #include "QF/sys.h"
  36. #include "QF/zone.h"
  37. #include "compat.h"
  38. void
  39. PR_PrintStatement (progs_t * pr, dstatement_t *s)
  40. {
  41. int addr = s - pr->pr_statements;
  42. int ofs;
  43. opcode_t *op;
  44. if (pr_debug->int_val && pr->debug) {
  45. const char *source_line = PR_Get_Source_Line (pr, addr);
  46. if (source_line)
  47. Sys_Printf ("%s\n", source_line);
  48. }
  49. op = PR_Opcode (s->op);
  50. if (!op) {
  51. Sys_Printf ("Unknown instruction %d\n", s->op);
  52. return;
  53. }
  54. Sys_Printf ("%04x ", addr);
  55. if (pr_debug->int_val > 1)
  56. Sys_Printf ("%02x %04x(%s) %04x(%s) %04x(%s)\t",
  57. s->op,
  58. s->a, pr_type_name[op->type_a],
  59. s->b, pr_type_name[op->type_b],
  60. s->c, pr_type_name[op->type_c]);
  61. Sys_Printf ("%s ", op->opname);
  62. switch (s->op) {
  63. case OP_IF:
  64. case OP_IFNOT:
  65. case OP_IFBE:
  66. case OP_IFB:
  67. case OP_IFAE:
  68. case OP_IFA:
  69. ofs = (short) s->b;
  70. Sys_Printf ("%s branch %i (%i)",
  71. PR_GlobalString (pr, s->a, ev_integer)->str, ofs, addr + ofs);
  72. break;
  73. case OP_GOTO:
  74. ofs = (short) s->a;
  75. Sys_Printf ("branch %i (%i)", ofs, addr + ofs);
  76. break;
  77. case OP_RETURN:
  78. case OP_DONE:
  79. Sys_Printf ("%s", PR_GlobalString (pr, s->a, ev_void)->str);
  80. break;
  81. default:
  82. if (op->type_a != ev_void)
  83. Sys_Printf ("%s", PR_GlobalString (pr, s->a, op->type_a)->str);
  84. if (op->type_b != ev_void) {
  85. if (op->type_c != ev_void)
  86. Sys_Printf (", %s", PR_GlobalString (pr, s->b, op->type_b)->str);
  87. else
  88. Sys_Printf (", %s",
  89. PR_GlobalStringNoContents (pr, s->b, op->type_b)->str);
  90. }
  91. if (op->type_c != ev_void) {
  92. if (op->type_b == ev_pointer && op->type_c == ev_integer)
  93. Sys_Printf (", %s", PR_GlobalString (pr, s->c, op->type_c)->str);
  94. else
  95. Sys_Printf (", %s",
  96. PR_GlobalStringNoContents (pr, s->c, op->type_c)->str);
  97. }
  98. }
  99. Sys_Printf ("\n");
  100. }
  101. void
  102. PR_StackTrace (progs_t * pr)
  103. {
  104. int i;
  105. dfunction_t *f;
  106. if (pr->pr_depth == 0) {
  107. Sys_Printf ("<NO STACK>\n");
  108. return;
  109. }
  110. pr->pr_stack[pr->pr_depth].f = pr->pr_xfunction;
  111. for (i = pr->pr_depth; i >= 0; i--) {
  112. f = pr->pr_stack[i].f;
  113. if (!f) {
  114. Sys_Printf ("<NO FUNCTION>\n");
  115. } else
  116. Sys_Printf ("%12s : %s\n", PR_GetString (pr, f->s_file),
  117. PR_GetString (pr, f->s_name));
  118. }
  119. }
  120. void
  121. PR_Profile (progs_t * pr)
  122. {
  123. int max, num, i;
  124. dfunction_t *best, *f;
  125. num = 0;
  126. do {
  127. max = 0;
  128. best = NULL;
  129. for (i = 0; i < pr->progs->numfunctions; i++) {
  130. f = &pr->pr_functions[i];
  131. if (f->profile > max) {
  132. max = f->profile;
  133. best = f;
  134. }
  135. }
  136. if (best) {
  137. if (num < 10)
  138. Sys_Printf ("%7i %s\n", best->profile,
  139. PR_GetString (pr, best->s_name));
  140. num++;
  141. best->profile = 0;
  142. }
  143. } while (best);
  144. }
  145. /*
  146. PR_RunError
  147. Aborts the currently executing function
  148. */
  149. void
  150. PR_RunError (progs_t * pr, const char *error, ...)
  151. {
  152. char string[1024];
  153. va_list argptr;
  154. va_start (argptr, error);
  155. vsnprintf (string, sizeof (string), error, argptr);
  156. va_end (argptr);
  157. PR_DumpState (pr);
  158. Sys_Printf ("%s\n", string);
  159. // dump the stack so PR_Error can shutdown functions
  160. pr->pr_depth = 0;
  161. PR_Error (pr, "Program error");
  162. }
  163. /*
  164. PR_EnterFunction
  165. Returns the new program statement counter
  166. */
  167. int
  168. PR_EnterFunction (progs_t * pr, dfunction_t *f)
  169. {
  170. int i, j, c, o;
  171. int k;
  172. //Sys_Printf("%s:\n", PR_GetString(pr,f->s_name));
  173. pr->pr_stack[pr->pr_depth].s = pr->pr_xstatement;
  174. pr->pr_stack[pr->pr_depth].f = pr->pr_xfunction;
  175. pr->pr_depth++;
  176. if (pr->pr_depth >= MAX_STACK_DEPTH)
  177. PR_RunError (pr, "stack overflow");
  178. // save off any locals that the new function steps on
  179. c = f->locals;
  180. if (pr->localstack_used + c > LOCALSTACK_SIZE)
  181. PR_RunError (pr, "PR_EnterFunction: locals stack overflow");
  182. memcpy (&pr->localstack[pr->localstack_used],
  183. &pr->pr_globals[f->parm_start],
  184. sizeof (pr_type_t) * c);
  185. pr->localstack_used += c;
  186. if (pr_deadbeef_locals->int_val)
  187. for (k = f->parm_start; k < f->parm_start + c; k++)
  188. pr->pr_globals[k].integer_var = 0xdeadbeef;
  189. // copy parameters
  190. o = f->parm_start;
  191. if (f->numparms >= 0) {
  192. for (i = 0; i < f->numparms; i++) {
  193. for (j = 0; j < f->parm_size[i]; j++) {
  194. memcpy (&pr->pr_globals[o],
  195. &pr->pr_globals[OFS_PARM0 + i * 3 + j],
  196. sizeof (pr_type_t));
  197. o++;
  198. }
  199. }
  200. } else {
  201. pr_type_t *argc = &pr->pr_globals[o++];
  202. pr_type_t *argv = &pr->pr_globals[o++];
  203. for (i = 0; i < -f->numparms - 1; i++) {
  204. for (j = 0; j < f->parm_size[i]; j++) {
  205. memcpy (&pr->pr_globals[o],
  206. &pr->pr_globals[OFS_PARM0 + i * 3 + j],
  207. sizeof (pr_type_t));
  208. o++;
  209. }
  210. }
  211. argc->integer_var = pr->pr_argc - i;
  212. argv->integer_var = o;
  213. while (i < MAX_PARMS) {
  214. memcpy (&pr->pr_globals[o],
  215. &pr->pr_globals[OFS_PARM0 + i * 3],
  216. 3);
  217. o += 3;
  218. i++;
  219. }
  220. }
  221. pr->pr_xfunction = f;
  222. return f->first_statement - 1; // offset the s++
  223. }
  224. int
  225. PR_LeaveFunction (progs_t * pr)
  226. {
  227. int c;
  228. if (pr->pr_depth <= 0)
  229. PR_Error (pr, "prog stack underflow");
  230. // restore locals from the stack
  231. c = pr->pr_xfunction->locals;
  232. pr->localstack_used -= c;
  233. if (pr->localstack_used < 0)
  234. PR_RunError (pr, "PR_LeaveFunction: locals stack underflow");
  235. memcpy (&pr->pr_globals[pr->pr_xfunction->parm_start],
  236. &pr->localstack[pr->localstack_used],
  237. sizeof (pr_type_t) * c);
  238. // up stack
  239. pr->pr_depth--;
  240. pr->pr_xfunction = pr->pr_stack[pr->pr_depth].f;
  241. return pr->pr_stack[pr->pr_depth].s;
  242. }
  243. static void
  244. signal_hook (int sig, void *data)
  245. {
  246. progs_t *pr = (progs_t *) data;
  247. PR_DumpState (pr);
  248. }
  249. #define OPA (*op_a)
  250. #define OPB (*op_b)
  251. #define OPC (*op_c)
  252. /*
  253. This gets around the problem of needing to test for -0.0 but denormals
  254. causing exceptions (or wrong results for what we need) on the alpha.
  255. */
  256. #define FNZ(x) ((x).integer_var && (x).integer_var != 0x80000000)
  257. /*
  258. PR_ExecuteProgram
  259. The interpretation main loop
  260. */
  261. void
  262. PR_ExecuteProgram (progs_t * pr, func_t fnum)
  263. {
  264. int exitdepth, profile, startprofile;
  265. int pointer;
  266. dfunction_t *f, *newf;
  267. dstatement_t *st;
  268. edict_t *ed;
  269. pr_type_t *ptr;
  270. if (!fnum || fnum >= pr->progs->numfunctions) {
  271. if (*pr->globals.self)
  272. ED_Print (pr, PROG_TO_EDICT (pr, *pr->globals.self));
  273. PR_RunError (pr, "PR_ExecuteProgram: NULL function");
  274. }
  275. f = &pr->pr_functions[fnum];
  276. //Sys_Printf("%s:\n", PR_GetString(pr,f->s_name));
  277. pr->pr_trace = false;
  278. // make a stack frame
  279. exitdepth = pr->pr_depth;
  280. st = &pr->pr_statements[PR_EnterFunction (pr, f)];
  281. startprofile = profile = 0;
  282. Sys_PushSignalHook (signal_hook, pr);
  283. while (1) {
  284. pr_type_t *op_a, *op_b, *op_c;
  285. st++;
  286. if (++profile > 1000000 && !pr->no_exec_limit) {
  287. pr->pr_xstatement = st - pr->pr_statements;
  288. PR_RunError (pr, "runaway loop error");
  289. }
  290. op_a = pr->pr_globals + st->a;
  291. op_b = pr->pr_globals + st->b;
  292. op_c = pr->pr_globals + st->c;
  293. if (pr->pr_trace)
  294. PR_PrintStatement (pr, st);
  295. switch (st->op) {
  296. case OP_ADD_F:
  297. OPC.float_var = OPA.float_var + OPB.float_var;
  298. break;
  299. case OP_ADD_V:
  300. VectorAdd (OPA.vector_var, OPB.vector_var, OPC.vector_var);
  301. break;
  302. case OP_ADD_S:
  303. {
  304. char *a = PR_GetString (pr, OPA.string_var);
  305. char *b = PR_GetString (pr, OPB.string_var);
  306. int lena = strlen (a);
  307. int size = lena + strlen (b) + 1;
  308. char *c = Hunk_TempAlloc (size);
  309. strcpy (c, a);
  310. strcpy (c + lena, b);
  311. OPC.string_var = PR_SetString (pr, c);
  312. }
  313. break;
  314. case OP_SUB_F:
  315. OPC.float_var = OPA.float_var - OPB.float_var;
  316. break;
  317. case OP_SUB_V:
  318. VectorSubtract (OPA.vector_var, OPB.vector_var, OPC.vector_var);
  319. break;
  320. case OP_MUL_F:
  321. OPC.float_var = OPA.float_var * OPB.float_var;
  322. break;
  323. case OP_MUL_V:
  324. OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var);
  325. break;
  326. case OP_MUL_FV:
  327. VectorScale (OPB.vector_var, OPA.float_var, OPC.vector_var);
  328. break;
  329. case OP_MUL_VF:
  330. VectorScale (OPA.vector_var, OPB.float_var, OPC.vector_var);
  331. break;
  332. case OP_DIV_F:
  333. OPC.float_var = OPA.float_var / OPB.float_var;
  334. break;
  335. case OP_BITAND:
  336. OPC.float_var = (int) OPA.float_var & (int) OPB.float_var;
  337. break;
  338. case OP_BITOR:
  339. OPC.float_var = (int) OPA.float_var | (int) OPB.float_var;
  340. break;
  341. case OP_BITXOR_F:
  342. OPC.float_var = (int) OPA.float_var ^ (int) OPB.float_var;
  343. break;
  344. case OP_BITNOT_F:
  345. OPC.float_var = ~ (int) OPA.float_var;
  346. break;
  347. case OP_SHL_F:
  348. OPC.float_var = (int) OPA.float_var << (int) OPB.float_var;
  349. break;
  350. case OP_SHR_F:
  351. OPC.float_var = (int) OPA.float_var >> (int) OPB.float_var;
  352. break;
  353. case OP_SHL_I:
  354. OPC.integer_var = OPA.integer_var << OPB.integer_var;
  355. break;
  356. case OP_SHR_I:
  357. OPC.integer_var = OPA.integer_var >> OPB.integer_var;
  358. break;
  359. case OP_GE_F:
  360. OPC.float_var = OPA.float_var >= OPB.float_var;
  361. break;
  362. case OP_LE_F:
  363. OPC.float_var = OPA.float_var <= OPB.float_var;
  364. break;
  365. case OP_GT_F:
  366. OPC.float_var = OPA.float_var > OPB.float_var;
  367. break;
  368. case OP_LT_F:
  369. OPC.float_var = OPA.float_var < OPB.float_var;
  370. break;
  371. case OP_AND: // OPA and OPB have to be float for -0.0
  372. OPC.integer_var = FNZ (OPA) && FNZ (OPB);
  373. break;
  374. case OP_OR: // OPA and OPB have to be float for -0.0
  375. OPC.integer_var = FNZ (OPA) || FNZ (OPB);
  376. break;
  377. case OP_NOT_F:
  378. OPC.integer_var = !FNZ (OPA);
  379. break;
  380. case OP_NOT_V:
  381. OPC.integer_var = VectorIsZero (OPA.vector_var);
  382. break;
  383. case OP_NOT_S:
  384. OPC.integer_var = !OPA.string_var ||
  385. !*PR_GetString (pr, OPA.string_var);
  386. break;
  387. case OP_NOT_FNC:
  388. OPC.integer_var = !OPA.func_var;
  389. break;
  390. case OP_NOT_ENT:
  391. OPC.integer_var = !OPA.entity_var;
  392. break;
  393. case OP_EQ_F:
  394. OPC.integer_var = OPA.float_var == OPB.float_var;
  395. break;
  396. case OP_EQ_V:
  397. OPC.integer_var = VectorCompare (OPA.vector_var,
  398. OPB.vector_var);
  399. break;
  400. case OP_EQ_E:
  401. OPC.integer_var = OPA.integer_var == OPB.integer_var;
  402. break;
  403. case OP_EQ_FNC:
  404. OPC.integer_var = OPA.func_var == OPB.func_var;
  405. break;
  406. case OP_NE_F:
  407. OPC.integer_var = OPA.float_var != OPB.float_var;
  408. break;
  409. case OP_NE_V:
  410. OPC.integer_var = !VectorCompare (OPA.vector_var,
  411. OPB.vector_var);
  412. break;
  413. case OP_LE_S:
  414. case OP_GE_S:
  415. case OP_LT_S:
  416. case OP_GT_S:
  417. case OP_NE_S:
  418. case OP_EQ_S:
  419. {
  420. int cmp = strcmp (PR_GetString (pr, OPA.string_var),
  421. PR_GetString (pr, OPB.string_var));
  422. switch (st->op) {
  423. case OP_LE_S: cmp = (cmp <= 0); break;
  424. case OP_GE_S: cmp = (cmp >= 0); break;
  425. case OP_LT_S: cmp = (cmp < 0); break;
  426. case OP_GT_S: cmp = (cmp > 0); break;
  427. case OP_NE_S: break;
  428. case OP_EQ_S: cmp = !cmp; break;
  429. default: break;
  430. }
  431. OPC.integer_var = cmp;
  432. }
  433. break;
  434. case OP_NE_E:
  435. OPC.integer_var = OPA.integer_var != OPB.integer_var;
  436. break;
  437. case OP_NE_FNC:
  438. OPC.integer_var = OPA.func_var != OPB.func_var;
  439. break;
  440. // ==================
  441. case OP_STORE_F:
  442. case OP_STORE_ENT:
  443. case OP_STORE_FLD: // integers
  444. case OP_STORE_S:
  445. case OP_STORE_FNC: // pointers
  446. case OP_STORE_I:
  447. case OP_STORE_P:
  448. OPB.integer_var = OPA.integer_var;
  449. break;
  450. case OP_STORE_V:
  451. VectorCopy (OPA.vector_var, OPB.vector_var);
  452. break;
  453. case OP_STOREP_F:
  454. case OP_STOREP_ENT:
  455. case OP_STOREP_FLD: // integers
  456. case OP_STOREP_S:
  457. case OP_STOREP_FNC: // pointers
  458. case OP_STOREP_I:
  459. case OP_STOREP_P:
  460. //FIXME put bounds checking back
  461. ptr = pr->pr_globals + OPB.integer_var;
  462. ptr->integer_var = OPA.integer_var;
  463. break;
  464. case OP_STOREP_V:
  465. //FIXME put bounds checking back
  466. ptr = pr->pr_globals + OPB.integer_var;
  467. VectorCopy (OPA.vector_var, ptr->vector_var);
  468. break;
  469. case OP_ADDRESS:
  470. if (pr_boundscheck->int_val
  471. && (OPA.entity_var < 0 || OPA.entity_var >=
  472. pr->pr_edictareasize)) {
  473. pr->pr_xstatement = st - pr->pr_statements;
  474. PR_RunError (pr, "Progs attempted to address an out of "
  475. "bounds edict");
  476. }
  477. if (pr_boundscheck->int_val
  478. && (OPA.entity_var == 0 && pr->null_bad)) {
  479. pr->pr_xstatement = st - pr->pr_statements;
  480. PR_RunError (pr, "assignment to world entity");
  481. }
  482. if (pr_boundscheck->int_val
  483. && (OPB.integer_var < 0 || OPB.integer_var >=
  484. pr->progs->entityfields)) {
  485. pr->pr_xstatement = st - pr->pr_statements;
  486. PR_RunError (pr, "Progs attempted to address an invalid "
  487. "field in an edict");
  488. }
  489. ed = PROG_TO_EDICT (pr, OPA.entity_var);
  490. OPC.integer_var = &ed->v[OPB.integer_var] - pr->pr_globals;
  491. break;
  492. case OP_ADDRESS_F:
  493. case OP_ADDRESS_V:
  494. case OP_ADDRESS_S:
  495. case OP_ADDRESS_ENT:
  496. case OP_ADDRESS_FLD:
  497. case OP_ADDRESS_FNC:
  498. case OP_ADDRESS_I:
  499. case OP_ADDRESS_P:
  500. OPC.integer_var = st->a;
  501. break;
  502. case OP_LOAD_F:
  503. case OP_LOAD_FLD:
  504. case OP_LOAD_ENT:
  505. case OP_LOAD_S:
  506. case OP_LOAD_FNC:
  507. case OP_LOAD_I:
  508. case OP_LOAD_P:
  509. if (pr_boundscheck->int_val
  510. && (OPA.entity_var < 0 || OPA.entity_var >=
  511. pr->pr_edictareasize)) {
  512. pr->pr_xstatement = st - pr->pr_statements;
  513. PR_RunError (pr, "Progs attempted to read an out of "
  514. "bounds edict number");
  515. }
  516. if (pr_boundscheck->int_val
  517. && (OPB.integer_var < 0 || OPB.integer_var >=
  518. pr->progs->entityfields)) {
  519. pr->pr_xstatement = st - pr->pr_statements;
  520. PR_RunError (pr, "Progs attempted to read an invalid "
  521. "field in an edict");
  522. }
  523. ed = PROG_TO_EDICT (pr, OPA.entity_var);
  524. OPC.integer_var = ed->v[OPB.integer_var].integer_var;
  525. break;
  526. case OP_LOAD_V:
  527. if (pr_boundscheck->int_val
  528. && (OPA.entity_var < 0 || OPA.entity_var >=
  529. pr->pr_edictareasize)) {
  530. pr->pr_xstatement = st - pr->pr_statements;
  531. PR_RunError (pr, "Progs attempted to read an out of "
  532. "bounds edict number");
  533. }
  534. if (pr_boundscheck->int_val
  535. && (OPB.integer_var < 0
  536. || OPB.integer_var + 2 >= pr->progs->entityfields)) {
  537. pr->pr_xstatement = st - pr->pr_statements;
  538. PR_RunError (pr, "Progs attempted to read an invalid "
  539. "field in an edict");
  540. }
  541. ed = PROG_TO_EDICT (pr, OPA.entity_var);
  542. memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC));
  543. break;
  544. case OP_LOADB_F:
  545. case OP_LOADB_S:
  546. case OP_LOADB_ENT:
  547. case OP_LOADB_FLD:
  548. case OP_LOADB_FNC:
  549. case OP_LOADB_I:
  550. case OP_LOADB_P:
  551. //FIXME put bounds checking in
  552. pointer = OPA.integer_var + OPB.integer_var;
  553. ptr = pr->pr_globals + pointer;
  554. OPC.integer_var = ptr->integer_var;
  555. break;
  556. case OP_LOADB_V:
  557. //FIXME put bounds checking in
  558. pointer = OPA.integer_var + OPB.integer_var;
  559. ptr = pr->pr_globals + pointer;
  560. VectorCopy (ptr->vector_var, OPC.vector_var);
  561. break;
  562. case OP_LOADBI_F:
  563. case OP_LOADBI_S:
  564. case OP_LOADBI_ENT:
  565. case OP_LOADBI_FLD:
  566. case OP_LOADBI_FNC:
  567. case OP_LOADBI_I:
  568. case OP_LOADBI_P:
  569. //FIXME put bounds checking in
  570. pointer = OPA.integer_var + (short) st->b;
  571. ptr = pr->pr_globals + pointer;
  572. OPC.integer_var = ptr->integer_var;
  573. break;
  574. case OP_LOADBI_V:
  575. //FIXME put bounds checking in
  576. pointer = OPA.integer_var + (short) st->b;
  577. ptr = pr->pr_globals + pointer;
  578. VectorCopy (ptr->vector_var, OPC.vector_var);
  579. break;
  580. case OP_LEA:
  581. pointer = OPA.integer_var + OPB.integer_var;
  582. OPC.integer_var = pointer;
  583. break;
  584. case OP_LEAI:
  585. pointer = OPA.integer_var + (short) st->b;
  586. OPC.integer_var = pointer;
  587. break;
  588. case OP_STOREB_F:
  589. case OP_STOREB_S:
  590. case OP_STOREB_ENT:
  591. case OP_STOREB_FLD:
  592. case OP_STOREB_FNC:
  593. case OP_STOREB_I:
  594. case OP_STOREB_P:
  595. //FIXME put bounds checking in
  596. pointer = OPB.integer_var + OPC.integer_var;
  597. ptr = pr->pr_globals + pointer;
  598. ptr->integer_var = OPA.integer_var;
  599. break;
  600. case OP_STOREB_V:
  601. //FIXME put bounds checking in
  602. pointer = OPB.integer_var + OPC.integer_var;
  603. ptr = pr->pr_globals + pointer;
  604. VectorCopy (OPA.vector_var, ptr->vector_var);
  605. break;
  606. case OP_STOREBI_F:
  607. case OP_STOREBI_S:
  608. case OP_STOREBI_ENT:
  609. case OP_STOREBI_FLD:
  610. case OP_STOREBI_FNC:
  611. case OP_STOREBI_I:
  612. case OP_STOREBI_P:
  613. //FIXME put bounds checking in
  614. pointer = OPB.integer_var + (short) st->c;
  615. ptr = pr->pr_globals + pointer;
  616. ptr->integer_var = OPA.integer_var;
  617. break;
  618. case OP_STOREBI_V:
  619. //FIXME put bounds checking in
  620. pointer = OPB.integer_var + (short) st->c;
  621. ptr = pr->pr_globals + pointer;
  622. VectorCopy (OPA.vector_var, ptr->vector_var);
  623. break;
  624. // ==================
  625. case OP_IFNOT:
  626. if (!OPA.integer_var)
  627. st += (short)st->b - 1; // offset the s++
  628. break;
  629. case OP_IF:
  630. if (OPA.integer_var)
  631. st += (short)st->b - 1; // offset the s++
  632. break;
  633. case OP_IFBE:
  634. if (OPA.integer_var <= 0)
  635. st += (short)st->b - 1; // offset the s++
  636. break;
  637. case OP_IFB:
  638. if (OPA.integer_var < 0)
  639. st += (short)st->b - 1; // offset the s++
  640. break;
  641. case OP_IFAE:
  642. if (OPA.integer_var >= 0)
  643. st += (short)st->b - 1; // offset the s++
  644. break;
  645. case OP_IFA:
  646. if (OPA.integer_var > 0)
  647. st += (short)st->b - 1; // offset the s++
  648. break;
  649. case OP_GOTO:
  650. st += (short)st->a - 1; // offset the s++
  651. break;
  652. case OP_JUMP:
  653. if (pr_boundscheck->int_val
  654. && (OPA.uinteger_var >= pr->progs->numstatements)) {
  655. pr->pr_xstatement = st - pr->pr_statements;
  656. PR_RunError (pr, "Invalid jump destination");
  657. }
  658. st = &pr->pr_statements[OPA.uinteger_var];
  659. break;
  660. case OP_JUMPB:
  661. //FIXME put bounds checking in
  662. pointer = OPA.integer_var + OPB.integer_var;
  663. ptr = pr->pr_globals + pointer;
  664. pointer = ptr->integer_var;
  665. if (pr_boundscheck->int_val
  666. && (pointer >= pr->progs->numstatements)) {
  667. pr->pr_xstatement = st - pr->pr_statements;
  668. PR_RunError (pr, "Invalid jump destination");
  669. }
  670. st = &pr->pr_statements[pointer];
  671. break;
  672. case OP_CALL0:
  673. case OP_CALL1:
  674. case OP_CALL2:
  675. case OP_CALL3:
  676. case OP_CALL4:
  677. case OP_CALL5:
  678. case OP_CALL6:
  679. case OP_CALL7:
  680. case OP_CALL8:
  681. pr->pr_xfunction->profile += profile - startprofile;
  682. startprofile = profile;
  683. pr->pr_xstatement = st - pr->pr_statements;
  684. pr->pr_argc = st->op - OP_CALL0;
  685. if (!OPA.func_var)
  686. PR_RunError (pr, "NULL function");
  687. newf = &pr->pr_functions[OPA.func_var];
  688. if (newf->first_statement < 0) {
  689. // negative statements are built in functions
  690. int i = -newf->first_statement;
  691. if (i >= pr->numbuiltins || !pr->builtins[i]
  692. || !pr->builtins[i]->proc)
  693. PR_RunError (pr, "Bad builtin call number");
  694. pr->builtins[i]->proc (pr);
  695. break;
  696. }
  697. st = &pr->pr_statements[PR_EnterFunction (pr, newf)];
  698. break;
  699. case OP_DONE:
  700. case OP_RETURN:
  701. memcpy (&pr->pr_globals[OFS_RETURN], &OPA, 3 * sizeof (OPA));
  702. st = &pr->pr_statements[PR_LeaveFunction (pr)];
  703. if (pr->pr_depth == exitdepth) {
  704. Sys_PopSignalHook ();
  705. return; // all done
  706. }
  707. break;
  708. case OP_STATE:
  709. ed = PROG_TO_EDICT (pr, *pr->globals.self);
  710. ed->v[pr->fields.nextthink].float_var = *pr->globals.time +
  711. 0.1;
  712. ed->v[pr->fields.frame].float_var = OPA.float_var;
  713. ed->v[pr->fields.think].func_var = OPB.func_var;
  714. break;
  715. case OP_ADD_I:
  716. OPC.integer_var = OPA.integer_var + OPB.integer_var;
  717. break;
  718. case OP_SUB_I:
  719. OPC.integer_var = OPA.integer_var - OPB.integer_var;
  720. break;
  721. case OP_MUL_I:
  722. OPC.integer_var = OPA.integer_var * OPB.integer_var;
  723. break;
  724. /*
  725. case OP_DIV_VF:
  726. {
  727. float temp = 1.0f / OPB.float_var;
  728. VectorScale (OPA.vector_var, temp, OPC.vector_var);
  729. }
  730. break;
  731. */
  732. case OP_DIV_I:
  733. OPC.integer_var = OPA.integer_var / OPB.integer_var;
  734. break;
  735. case OP_MOD_I:
  736. OPC.integer_var = OPA.integer_var % OPB.integer_var;
  737. break;
  738. case OP_MOD_F:
  739. OPC.float_var = (int) OPA.float_var % (int) OPB.float_var;
  740. break;
  741. case OP_CONV_IF:
  742. OPC.float_var = OPA.integer_var;
  743. break;
  744. case OP_CONV_FI:
  745. OPC.integer_var = OPA.float_var;
  746. break;
  747. case OP_BITAND_I:
  748. OPC.integer_var = OPA.integer_var & OPB.integer_var;
  749. break;
  750. case OP_BITOR_I:
  751. OPC.integer_var = OPA.integer_var | OPB.integer_var;
  752. break;
  753. case OP_BITXOR_I:
  754. OPC.integer_var = OPA.integer_var ^ OPB.integer_var;
  755. break;
  756. case OP_BITNOT_I:
  757. OPC.integer_var = ~OPA.integer_var;
  758. break;
  759. case OP_GE_I:
  760. case OP_GE_P:
  761. OPC.integer_var = OPA.integer_var >= OPB.integer_var;
  762. break;
  763. case OP_LE_I:
  764. case OP_LE_P:
  765. OPC.integer_var = OPA.integer_var <= OPB.integer_var;
  766. break;
  767. case OP_GT_I:
  768. case OP_GT_P:
  769. OPC.integer_var = OPA.integer_var > OPB.integer_var;
  770. break;
  771. case OP_LT_I:
  772. case OP_LT_P:
  773. OPC.integer_var = OPA.uinteger_var < OPB.uinteger_var;
  774. break;
  775. case OP_GE_UI:
  776. OPC.integer_var = OPA.uinteger_var >= OPB.uinteger_var;
  777. break;
  778. case OP_LE_UI:
  779. OPC.integer_var = OPA.uinteger_var <= OPB.uinteger_var;
  780. break;
  781. case OP_GT_UI:
  782. OPC.integer_var = OPA.uinteger_var > OPB.uinteger_var;
  783. break;
  784. case OP_LT_UI:
  785. OPC.integer_var = OPA.integer_var < OPB.integer_var;
  786. break;
  787. case OP_AND_I:
  788. OPC.integer_var = OPA.integer_var && OPB.integer_var;
  789. break;
  790. case OP_OR_I:
  791. OPC.integer_var = OPA.integer_var || OPB.integer_var;
  792. break;
  793. case OP_NOT_I:
  794. case OP_NOT_P:
  795. OPC.integer_var = !OPA.integer_var;
  796. break;
  797. case OP_EQ_I:
  798. case OP_EQ_P:
  799. OPC.integer_var = OPA.integer_var == OPB.integer_var;
  800. break;
  801. case OP_NE_I:
  802. case OP_NE_P:
  803. OPC.integer_var = OPA.integer_var != OPB.integer_var;
  804. break;
  805. // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
  806. /*
  807. case OP_BOUNDCHECK:
  808. if (OPA.integer_var < 0 || OPA.integer_var >= st->b) {
  809. pr->pr_xstatement = st - pr->pr_statements;
  810. PR_RunError (pr, "Progs boundcheck failed at line number "
  811. "%d, value is < 0 or >= %d", st->b, st->c);
  812. }
  813. break;
  814. */
  815. default:
  816. pr->pr_xstatement = st - pr->pr_statements;
  817. PR_RunError (pr, "Bad opcode %i", st->op);
  818. }
  819. }
  820. }