OpenTTD
squirrel.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include <stdarg.h>
13 #include "../stdafx.h"
14 #include "../debug.h"
15 #include "squirrel_std.hpp"
16 #include "../fileio_func.h"
17 #include "../string_func.h"
18 #include <sqstdaux.h>
19 #include <../squirrel/sqpcheader.h>
20 #include <../squirrel/sqvm.h>
21 
22 #include "../safeguards.h"
23 
24 void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column)
25 {
26  SQChar buf[1024];
27 
28  seprintf(buf, lastof(buf), "Error %s:" OTTD_PRINTF64 "/" OTTD_PRINTF64 ": %s", source, line, column, desc);
29 
30  /* Check if we have a custom print function */
31  Squirrel *engine = (Squirrel *)sq_getforeignptr(vm);
32  engine->crashed = true;
33  SQPrintFunc *func = engine->print_func;
34  if (func == NULL) {
35  DEBUG(misc, 0, "[Squirrel] Compile error: %s", buf);
36  } else {
37  (*func)(true, buf);
38  }
39 }
40 
41 void Squirrel::ErrorPrintFunc(HSQUIRRELVM vm, const SQChar *s, ...)
42 {
43  va_list arglist;
44  SQChar buf[1024];
45 
46  va_start(arglist, s);
47  vseprintf(buf, lastof(buf), s, arglist);
48  va_end(arglist);
49 
50  /* Check if we have a custom print function */
51  SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func;
52  if (func == NULL) {
53  fprintf(stderr, "%s", buf);
54  } else {
55  (*func)(true, buf);
56  }
57 }
58 
59 void Squirrel::RunError(HSQUIRRELVM vm, const SQChar *error)
60 {
61  /* Set the print function to something that prints to stderr */
62  SQPRINTFUNCTION pf = sq_getprintfunc(vm);
63  sq_setprintfunc(vm, &Squirrel::ErrorPrintFunc);
64 
65  /* Check if we have a custom print function */
66  SQChar buf[1024];
67  seprintf(buf, lastof(buf), "Your script made an error: %s\n", error);
68  Squirrel *engine = (Squirrel *)sq_getforeignptr(vm);
69  SQPrintFunc *func = engine->print_func;
70  if (func == NULL) {
71  fprintf(stderr, "%s", buf);
72  } else {
73  (*func)(true, buf);
74  }
75 
76  /* Print below the error the stack, so the users knows what is happening */
77  sqstd_printcallstack(vm);
78  /* Reset the old print function */
79  sq_setprintfunc(vm, pf);
80 }
81 
82 SQInteger Squirrel::_RunError(HSQUIRRELVM vm)
83 {
84  const SQChar *sErr = 0;
85 
86  if (sq_gettop(vm) >= 1) {
87  if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) {
88  Squirrel::RunError(vm, sErr);
89  return 0;
90  }
91  }
92 
93  Squirrel::RunError(vm, "unknown error");
94  return 0;
95 }
96 
97 void Squirrel::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...)
98 {
99  va_list arglist;
100  SQChar buf[1024];
101 
102  va_start(arglist, s);
103  vseprintf(buf, lastof(buf) - 2, s, arglist);
104  va_end(arglist);
105  strecat(buf, "\n", lastof(buf));
106 
107  /* Check if we have a custom print function */
108  SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func;
109  if (func == NULL) {
110  printf("%s", buf);
111  } else {
112  (*func)(false, buf);
113  }
114 }
115 
116 void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params, void *userdata, int size)
117 {
118  sq_pushstring(this->vm, method_name, -1);
119 
120  if (size != 0) {
121  void *ptr = sq_newuserdata(vm, size);
122  memcpy(ptr, userdata, size);
123  }
124 
125  sq_newclosure(this->vm, proc, size != 0 ? 1 : 0);
126  if (nparam != 0) sq_setparamscheck(this->vm, nparam, params);
127  sq_setnativeclosurename(this->vm, -1, method_name);
128  sq_newslot(this->vm, -3, SQFalse);
129 }
130 
131 void Squirrel::AddConst(const char *var_name, int value)
132 {
133  sq_pushstring(this->vm, var_name, -1);
134  sq_pushinteger(this->vm, value);
135  sq_newslot(this->vm, -3, SQTrue);
136 }
137 
138 void Squirrel::AddConst(const char *var_name, bool value)
139 {
140  sq_pushstring(this->vm, var_name, -1);
141  sq_pushbool(this->vm, value);
142  sq_newslot(this->vm, -3, SQTrue);
143 }
144 
145 void Squirrel::AddClassBegin(const char *class_name)
146 {
147  sq_pushroottable(this->vm);
148  sq_pushstring(this->vm, class_name, -1);
149  sq_newclass(this->vm, SQFalse);
150 }
151 
152 void Squirrel::AddClassBegin(const char *class_name, const char *parent_class)
153 {
154  sq_pushroottable(this->vm);
155  sq_pushstring(this->vm, class_name, -1);
156  sq_pushstring(this->vm, parent_class, -1);
157  if (SQ_FAILED(sq_get(this->vm, -3))) {
158  DEBUG(misc, 0, "[squirrel] Failed to initialize class '%s' based on parent class '%s'", class_name, parent_class);
159  DEBUG(misc, 0, "[squirrel] Make sure that '%s' exists before trying to define '%s'", parent_class, class_name);
160  return;
161  }
162  sq_newclass(this->vm, SQTrue);
163 }
164 
166 {
167  sq_newslot(vm, -3, SQFalse);
168  sq_pop(vm, 1);
169 }
170 
171 bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name)
172 {
173  assert(!this->crashed);
174  int top = sq_gettop(this->vm);
175  /* Go to the instance-root */
176  sq_pushobject(this->vm, instance);
177  /* Find the function-name inside the script */
178  sq_pushstring(this->vm, method_name, -1);
179  if (SQ_FAILED(sq_get(this->vm, -2))) {
180  sq_settop(this->vm, top);
181  return false;
182  }
183  sq_settop(this->vm, top);
184  return true;
185 }
186 
187 bool Squirrel::Resume(int suspend)
188 {
189  assert(!this->crashed);
190  /* Did we use more operations than we should have in the
191  * previous tick? If so, subtract that from the current run. */
192  if (this->overdrawn_ops > 0 && suspend > 0) {
193  this->overdrawn_ops -= suspend;
194  /* Do we need to wait even more? */
195  if (this->overdrawn_ops >= 0) return true;
196 
197  /* We can now only run whatever is "left". */
198  suspend = -this->overdrawn_ops;
199  }
200 
201  this->crashed = !sq_resumecatch(this->vm, suspend);
202  this->overdrawn_ops = -this->vm->_ops_till_suspend;
203  return this->vm->_suspended != 0;
204 }
205 
207 {
208  assert(!this->crashed);
209  sq_resumeerror(this->vm);
210 }
211 
213 {
214  sq_collectgarbage(this->vm);
215 }
216 
217 bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend)
218 {
219  assert(!this->crashed);
220  /* Store the stack-location for the return value. We need to
221  * restore this after saving or the stack will be corrupted
222  * if we're in the middle of a DoCommand. */
223  SQInteger last_target = this->vm->_suspended_target;
224  /* Store the current top */
225  int top = sq_gettop(this->vm);
226  /* Go to the instance-root */
227  sq_pushobject(this->vm, instance);
228  /* Find the function-name inside the script */
229  sq_pushstring(this->vm, method_name, -1);
230  if (SQ_FAILED(sq_get(this->vm, -2))) {
231  DEBUG(misc, 0, "[squirrel] Could not find '%s' in the class", method_name);
232  sq_settop(this->vm, top);
233  return false;
234  }
235  /* Call the method */
236  sq_pushobject(this->vm, instance);
237  if (SQ_FAILED(sq_call(this->vm, 1, ret == NULL ? SQFalse : SQTrue, SQTrue, suspend))) return false;
238  if (ret != NULL) sq_getstackobj(vm, -1, ret);
239  /* Reset the top, but don't do so for the script main function, as we need
240  * a correct stack when resuming. */
241  if (suspend == -1 || !this->IsSuspended()) sq_settop(this->vm, top);
242  /* Restore the return-value location. */
243  this->vm->_suspended_target = last_target;
244 
245  return true;
246 }
247 
248 bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend)
249 {
250  HSQOBJECT ret;
251  if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
252  if (ret._type != OT_STRING) return false;
253  *res = stredup(ObjectToString(&ret));
254  ValidateString(*res);
255  return true;
256 }
257 
258 bool Squirrel::CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend)
259 {
260  HSQOBJECT ret;
261  if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
262  if (ret._type != OT_INTEGER) return false;
263  *res = ObjectToInteger(&ret);
264  return true;
265 }
266 
267 bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend)
268 {
269  HSQOBJECT ret;
270  if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
271  if (ret._type != OT_BOOL) return false;
272  *res = ObjectToBool(&ret);
273  return true;
274 }
275 
276 /* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name)
277 {
278  Squirrel *engine = (Squirrel *)sq_getforeignptr(vm);
279 
280  int oldtop = sq_gettop(vm);
281 
282  /* First, find the class */
283  sq_pushroottable(vm);
284 
285  if (prepend_API_name) {
286  size_t len = strlen(class_name) + strlen(engine->GetAPIName()) + 1;
287  char *class_name2 = (char *)alloca(len);
288  seprintf(class_name2, class_name2 + len - 1, "%s%s", engine->GetAPIName(), class_name);
289 
290  sq_pushstring(vm, class_name2, -1);
291  } else {
292  sq_pushstring(vm, class_name, -1);
293  }
294 
295  if (SQ_FAILED(sq_get(vm, -2))) {
296  DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name);
297  sq_settop(vm, oldtop);
298  return false;
299  }
300 
301  /* Create the instance */
302  if (SQ_FAILED(sq_createinstance(vm, -1))) {
303  DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name);
304  sq_settop(vm, oldtop);
305  return false;
306  }
307 
308  if (instance != NULL) {
309  /* Find our instance */
310  sq_getstackobj(vm, -1, instance);
311  /* Add a reference to it, so it survives for ever */
312  sq_addref(vm, instance);
313  }
314  sq_remove(vm, -2); // Class-name
315  sq_remove(vm, -2); // Root-table
316 
317  /* Store it in the class */
318  sq_setinstanceup(vm, -1, real_instance);
319  if (release_hook != NULL) sq_setreleasehook(vm, -1, release_hook);
320 
321  if (instance != NULL) sq_settop(vm, oldtop);
322 
323  return true;
324 }
325 
326 bool Squirrel::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance)
327 {
328  return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, NULL);
329 }
330 
331 Squirrel::Squirrel(const char *APIName) :
333 {
334  this->Initialize();
335 }
336 
338 {
339  this->global_pointer = NULL;
340  this->print_func = NULL;
341  this->crashed = false;
342  this->overdrawn_ops = 0;
343  this->vm = sq_open(1024);
344 
345  /* Handle compile-errors ourself, so we can display it nicely */
346  sq_setcompilererrorhandler(this->vm, &Squirrel::CompileError);
347  sq_notifyallexceptions(this->vm, SQTrue);
348  /* Set a good print-function */
349  sq_setprintfunc(this->vm, &Squirrel::PrintFunc);
350  /* Handle runtime-errors ourself, so we can display it nicely */
351  sq_newclosure(this->vm, &Squirrel::_RunError, 0);
352  sq_seterrorhandler(this->vm);
353 
354  /* Set the foreign pointer, so we can always find this instance from within the VM */
355  sq_setforeignptr(this->vm, this);
356 
357  sq_pushroottable(this->vm);
359 }
360 
361 class SQFile {
362 private:
363  FILE *file;
364  size_t size;
365  size_t pos;
366 
367 public:
368  SQFile(FILE *file, size_t size) : file(file), size(size), pos(0) {}
369 
370  size_t Read(void *buf, size_t elemsize, size_t count)
371  {
372  assert(elemsize != 0);
373  if (this->pos + (elemsize * count) > this->size) {
374  count = (this->size - this->pos) / elemsize;
375  }
376  if (count == 0) return 0;
377  size_t ret = fread(buf, elemsize, count, this->file);
378  this->pos += ret * elemsize;
379  return ret;
380  }
381 };
382 
383 static WChar _io_file_lexfeed_ASCII(SQUserPointer file)
384 {
385  unsigned char c;
386  if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return c;
387  return 0;
388 }
389 
390 static WChar _io_file_lexfeed_UTF8(SQUserPointer file)
391 {
392  char buffer[5];
393 
394  /* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */
395  if (((SQFile *)file)->Read(buffer, sizeof(buffer[0]), 1) != 1) return 0;
396  uint len = Utf8EncodedCharLen(buffer[0]);
397  if (len == 0) return -1;
398 
399  /* Read the remaining bits. */
400  if (len > 1 && ((SQFile *)file)->Read(buffer + 1, sizeof(buffer[0]), len - 1) != len - 1) return 0;
401 
402  /* Convert the character, and when definitely invalid, bail out as well. */
403  WChar c;
404  if (Utf8Decode(&c, buffer) != len) return -1;
405 
406  return c;
407 }
408 
409 static WChar _io_file_lexfeed_UCS2_no_swap(SQUserPointer file)
410 {
411  unsigned short c;
412  if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return (WChar)c;
413  return 0;
414 }
415 
416 static WChar _io_file_lexfeed_UCS2_swap(SQUserPointer file)
417 {
418  unsigned short c;
419  if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) {
420  c = ((c >> 8) & 0x00FF)| ((c << 8) & 0xFF00);
421  return (WChar)c;
422  }
423  return 0;
424 }
425 
426 static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger size)
427 {
428  SQInteger ret = ((SQFile *)file)->Read(buf, 1, size);
429  if (ret == 0) return -1;
430  return ret;
431 }
432 
433 SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror)
434 {
435  FILE *file;
436  size_t size;
437  if (strncmp(this->GetAPIName(), "AI", 2) == 0) {
438  file = FioFOpenFile(filename, "rb", AI_DIR, &size);
439  if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
440  } else if (strncmp(this->GetAPIName(), "GS", 2) == 0) {
441  file = FioFOpenFile(filename, "rb", GAME_DIR, &size);
442  if (file == NULL) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size);
443  } else {
444  NOT_REACHED();
445  }
446 
447  if (file == NULL) {
448  return sq_throwerror(vm, "cannot open the file");
449  }
450  unsigned short bom = 0;
451  if (size >= 2) {
452  size_t sr = fread(&bom, 1, sizeof(bom), file);
453  (void)sr; // Inside tar, no point checking return value of fread
454  }
455 
456  SQLEXREADFUNC func;
457  switch (bom) {
458  case SQ_BYTECODE_STREAM_TAG: { // BYTECODE
459  if (fseek(file, -2, SEEK_CUR) < 0) {
460  FioFCloseFile(file);
461  return sq_throwerror(vm, "cannot seek the file");
462  }
463 
464  SQFile f(file, size);
465  if (SQ_SUCCEEDED(sq_readclosure(vm, _io_file_read, &f))) {
466  FioFCloseFile(file);
467  return SQ_OK;
468  }
469  FioFCloseFile(file);
470  return sq_throwerror(vm, "Couldn't read bytecode");
471  }
472  case 0xFFFE:
473  /* Either this file is encoded as big-endian and we're on a little-endian
474  * machine, or this file is encoded as little-endian and we're on a big-endian
475  * machine. Either way, swap the bytes of every word we read. */
476  func = _io_file_lexfeed_UCS2_swap;
477  size -= 2; // Skip BOM
478  break;
479  case 0xFEFF:
480  func = _io_file_lexfeed_UCS2_no_swap;
481  size -= 2; // Skip BOM
482  break;
483  case 0xBBEF: // UTF-8
484  case 0xEFBB: { // UTF-8 on big-endian machine
485  /* Similarly, check the file is actually big enough to finish checking BOM */
486  if (size < 3) {
487  FioFCloseFile(file);
488  return sq_throwerror(vm, "I/O error");
489  }
490  unsigned char uc;
491  if (fread(&uc, 1, sizeof(uc), file) != sizeof(uc) || uc != 0xBF) {
492  FioFCloseFile(file);
493  return sq_throwerror(vm, "Unrecognized encoding");
494  }
495  func = _io_file_lexfeed_UTF8;
496  size -= 3; // Skip BOM
497  break;
498  }
499  default: // ASCII
500  func = _io_file_lexfeed_ASCII;
501  /* Account for when we might not have fread'd earlier */
502  if (size >= 2 && fseek(file, -2, SEEK_CUR) < 0) {
503  FioFCloseFile(file);
504  return sq_throwerror(vm, "cannot seek the file");
505  }
506  break;
507  }
508 
509  SQFile f(file, size);
510  if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) {
511  FioFCloseFile(file);
512  return SQ_OK;
513  }
514  FioFCloseFile(file);
515  return SQ_ERROR;
516 }
517 
518 bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root)
519 {
520  /* Make sure we are always in the root-table */
521  if (in_root) sq_pushroottable(vm);
522 
523  SQInteger ops_left = vm->_ops_till_suspend;
524  /* Load and run the script */
525  if (SQ_SUCCEEDED(LoadFile(vm, script, SQTrue))) {
526  sq_push(vm, -2);
527  if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue, 100000))) {
528  sq_pop(vm, 1);
529  /* After compiling the file we want to reset the amount of opcodes. */
530  vm->_ops_till_suspend = ops_left;
531  return true;
532  }
533  }
534 
535  vm->_ops_till_suspend = ops_left;
536  DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script);
537  return false;
538 }
539 
540 bool Squirrel::LoadScript(const char *script)
541 {
542  return LoadScript(this->vm, script);
543 }
544 
545 Squirrel::~Squirrel()
546 {
547  this->Uninitialize();
548 }
549 
551 {
552  /* Clean up the stuff */
553  sq_pop(this->vm, 1);
554  sq_close(this->vm);
555 }
556 
558 {
559  this->Uninitialize();
560  this->Initialize();
561 }
562 
563 void Squirrel::InsertResult(bool result)
564 {
565  sq_pushbool(this->vm, result);
566  if (this->IsSuspended()) { // Called before resuming a suspended script?
567  vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1);
568  vm->Pop();
569  }
570 }
571 
572 void Squirrel::InsertResult(int result)
573 {
574  sq_pushinteger(this->vm, result);
575  if (this->IsSuspended()) { // Called before resuming a suspended script?
576  vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1);
577  vm->Pop();
578  }
579 }
580 
581 /* static */ void Squirrel::DecreaseOps(HSQUIRRELVM vm, int ops)
582 {
583  vm->DecreaseOps(ops);
584 }
585 
587 {
588  return this->vm->_suspended != 0;
589 }
590 
592 {
593  return this->crashed;
594 }
595 
597 {
598  this->crashed = true;
599 }
600 
602 {
603  return sq_can_suspend(this->vm);
604 }
605 
607 {
608  return this->vm->_ops_till_suspend;
609 }
static const char * ObjectToString(HSQOBJECT *ptr)
Convert a Squirrel-object to a string.
Definition: squirrel.hpp:202
static void PrintFunc(HSQUIRRELVM vm, const SQChar *s,...)
If a user runs &#39;print&#39; inside a script, this function gets the params.
Definition: squirrel.cpp:97
bool HasScriptCrashed()
Find out if the squirrel script made an error before.
Definition: squirrel.cpp:591
void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam=0, const char *params=NULL, void *userdata=NULL, int size=0)
Adds a function to the stack.
Definition: squirrel.cpp:116
void * global_pointer
Can be set by who ever initializes Squirrel.
Definition: squirrel.hpp:28
static char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
Definition: depend.cpp:99
void FioFCloseFile(FILE *f)
Close a file in a safe way.
Definition: fileio.cpp:334
bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend)
Call a method of an instance, in various flavors.
Definition: squirrel.cpp:217
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:409
static void CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column)
The CompileError handler.
Definition: squirrel.cpp:24
void CollectGarbage()
Tell the VM to do a garbage collection run.
Definition: squirrel.cpp:212
SQInteger GetOpsTillSuspend()
How many operations can we execute till suspension?
Definition: squirrel.cpp:606
defines the Squirrel Standard Function class
static SQInteger _RunError(HSQUIRRELVM vm)
The internal RunError handler.
Definition: squirrel.cpp:82
int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap)
Safer implementation of vsnprintf; same as vsnprintf except:
Definition: string.cpp:62
void CrashOccurred()
Set the script status to crashed.
Definition: squirrel.cpp:596
Subdirectory for all game scripts.
Definition: fileio_type.h:123
size_t Utf8Decode(WChar *c, const char *s)
Decode and consume the next UTF-8 encoded character.
Definition: string.cpp:448
static void DecreaseOps(HSQUIRRELVM vm, int amount)
Tell the VM to remove amount ops from the number of ops till suspend.
Definition: squirrel.cpp:581
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
bool CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance)
Exactly the same as CreateClassInstanceVM, only callable without instance of Squirrel.
Definition: squirrel.cpp:326
bool crashed
True if the squirrel script made an error.
Definition: squirrel.hpp:30
const char * GetAPIName()
Get the API name.
Definition: squirrel.hpp:42
static int8 Utf8EncodedCharLen(char c)
Return the length of an UTF-8 encoded value based on a single char.
Definition: string_func.h:118
static bool ObjectToBool(HSQOBJECT *ptr)
Convert a Squirrel-object to a bool.
Definition: squirrel.hpp:212
void ResumeError()
Resume the VM with an error so it prints a stack trace.
Definition: squirrel.cpp:206
FILE * FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Definition: fileio.cpp:465
int overdrawn_ops
The amount of operations we have overdrawn.
Definition: squirrel.hpp:31
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:138
static bool CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name=false)
Creates a class instance.
Definition: squirrel.cpp:276
Subdirectory for all GS libraries.
Definition: fileio_type.h:124
bool IsSuspended()
Did the squirrel code suspend or return normally.
Definition: squirrel.cpp:586
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:36
Subdirectory for all AI libraries.
Definition: fileio_type.h:122
static int ObjectToInteger(HSQOBJECT *ptr)
Convert a Squirrel-object to an integer.
Definition: squirrel.hpp:207
void Reset()
Completely reset the engine; start from scratch.
Definition: squirrel.cpp:557
void squirrel_register_global_std(Squirrel *engine)
Register all standard functions that are available on first startup.
bool CanSuspend()
Are we allowed to suspend the squirrel script at this moment?
Definition: squirrel.cpp:601
void AddConst(const char *var_name, int value)
Adds a const to the stack.
Definition: squirrel.cpp:131
bool MethodExists(HSQOBJECT instance, const char *method_name)
Check if a method exists in an instance.
Definition: squirrel.cpp:171
SQRESULT LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror)
Load a file to a given VM.
Definition: squirrel.cpp:433
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:112
Subdirectory for all AI files.
Definition: fileio_type.h:121
void AddClassBegin(const char *class_name)
Adds a class to the global scope.
Definition: squirrel.cpp:145
HSQUIRRELVM vm
The VirtualMachine instance for squirrel.
Definition: squirrel.hpp:27
static void RunError(HSQUIRRELVM vm, const SQChar *error)
The RunError handler.
Definition: squirrel.cpp:59
const char * APIName
Name of the API used for this squirrel.
Definition: squirrel.hpp:32
bool LoadScript(const char *script)
Load a script.
Definition: squirrel.cpp:540
void ValidateString(const char *str)
Scans the string for valid characters and if it finds invalid ones, replaces them with a question mar...
Definition: string.cpp:245
void Uninitialize()
Perform all the cleanups for the engine.
Definition: squirrel.cpp:550
void AddClassEnd()
Finishes adding a class to the global scope.
Definition: squirrel.cpp:165
SQPrintFunc * print_func
Points to either NULL, or a custom print handler.
Definition: squirrel.hpp:29
uint32 WChar
Type for wide characters, i.e.
Definition: string_type.h:35
static void ErrorPrintFunc(HSQUIRRELVM vm, const SQChar *s,...)
If an error has to be print, this function is called.
Definition: squirrel.cpp:41
void Initialize()
Perform all initialization steps to create the engine.
Definition: squirrel.cpp:337
bool Resume(int suspend=-1)
Resume a VM when it was suspended via a throw.
Definition: squirrel.cpp:187