OpenTTD
squirrel.cpp
Go to the documentation of this file.
1 /* $Id: squirrel.cpp 26797 2014-09-07 16:03:41Z rubidium $ */
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  size_t size;
436  FILE *file;
437  SQInteger ret;
438  unsigned short us;
439  unsigned char uc;
440  SQLEXREADFUNC func;
441 
442  if (strncmp(this->GetAPIName(), "AI", 2) == 0) {
443  file = FioFOpenFile(filename, "rb", AI_DIR, &size);
444  if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
445  } else if (strncmp(this->GetAPIName(), "GS", 2) == 0) {
446  file = FioFOpenFile(filename, "rb", GAME_DIR, &size);
447  if (file == NULL) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size);
448  } else {
449  NOT_REACHED();
450  }
451 
452  if (file != NULL) {
453  SQFile f(file, size);
454  ret = fread(&us, 1, sizeof(us), file);
455  /* Most likely an empty file */
456  if (ret != 2) us = 0;
457 
458  switch (us) {
459  case SQ_BYTECODE_STREAM_TAG: { // BYTECODE
460  if (fseek(file, -2, SEEK_CUR) < 0) {
461  FioFCloseFile(file);
462  return sq_throwerror(vm, "cannot seek the file");
463  }
464  if (SQ_SUCCEEDED(sq_readclosure(vm, _io_file_read, &f))) {
465  FioFCloseFile(file);
466  return SQ_OK;
467  }
468  FioFCloseFile(file);
469  return sq_throwerror(vm, "Couldn't read bytecode");
470  }
471  case 0xFFFE:
472  /* Either this file is encoded as big-endian and we're on a little-endian
473  * machine, or this file is encoded as little-endian and we're on a big-endian
474  * machine. Either way, swap the bytes of every word we read. */
475  func = _io_file_lexfeed_UCS2_swap;
476  break;
477  case 0xFEFF: func = _io_file_lexfeed_UCS2_no_swap; break;
478  case 0xBBEF: // UTF-8
479  case 0xEFBB: // UTF-8 on big-endian machine
480  if (fread(&uc, 1, sizeof(uc), file) == 0) {
481  FioFCloseFile(file);
482  return sq_throwerror(vm, "I/O error");
483  }
484  if (uc != 0xBF) {
485  FioFCloseFile(file);
486  return sq_throwerror(vm, "Unrecognized encoding");
487  }
488  func = _io_file_lexfeed_UTF8;
489  break;
490  default: // ASCII
491  func = _io_file_lexfeed_ASCII;
492  if (fseek(file, -2, SEEK_CUR) < 0) {
493  FioFCloseFile(file);
494  return sq_throwerror(vm, "cannot seek the file");
495  }
496  break;
497  }
498 
499  if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) {
500  FioFCloseFile(file);
501  return SQ_OK;
502  }
503  FioFCloseFile(file);
504  return SQ_ERROR;
505  }
506  return sq_throwerror(vm, "cannot open the file");
507 }
508 
509 bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root)
510 {
511  /* Make sure we are always in the root-table */
512  if (in_root) sq_pushroottable(vm);
513 
514  SQInteger ops_left = vm->_ops_till_suspend;
515  /* Load and run the script */
516  if (SQ_SUCCEEDED(LoadFile(vm, script, SQTrue))) {
517  sq_push(vm, -2);
518  if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue, 100000))) {
519  sq_pop(vm, 1);
520  /* After compiling the file we want to reset the amount of opcodes. */
521  vm->_ops_till_suspend = ops_left;
522  return true;
523  }
524  }
525 
526  vm->_ops_till_suspend = ops_left;
527  DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script);
528  return false;
529 }
530 
531 bool Squirrel::LoadScript(const char *script)
532 {
533  return LoadScript(this->vm, script);
534 }
535 
536 Squirrel::~Squirrel()
537 {
538  this->Uninitialize();
539 }
540 
542 {
543  /* Clean up the stuff */
544  sq_pop(this->vm, 1);
545  sq_close(this->vm);
546 }
547 
549 {
550  this->Uninitialize();
551  this->Initialize();
552 }
553 
554 void Squirrel::InsertResult(bool result)
555 {
556  sq_pushbool(this->vm, result);
557  if (this->IsSuspended()) { // Called before resuming a suspended script?
558  vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1);
559  vm->Pop();
560  }
561 }
562 
563 void Squirrel::InsertResult(int result)
564 {
565  sq_pushinteger(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 /* static */ void Squirrel::DecreaseOps(HSQUIRRELVM vm, int ops)
573 {
574  vm->DecreaseOps(ops);
575 }
576 
578 {
579  return this->vm->_suspended != 0;
580 }
581 
583 {
584  return this->crashed;
585 }
586 
588 {
589  this->crashed = true;
590 }
591 
593 {
594  return sq_can_suspend(this->vm);
595 }
596 
598 {
599  return this->vm->_ops_till_suspend;
600 }
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:582
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:342
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:398
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:597
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:50
void CrashOccurred()
Set the script status to crashed.
Definition: squirrel.cpp:587
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:437
static void DecreaseOps(HSQUIRRELVM vm, int amount)
Tell the VM to remove amount ops from the number of ops till suspend.
Definition: squirrel.cpp:572
#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:474
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:126
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:577
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:39
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:548
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:592
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:110
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:531
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:233
void Uninitialize()
Perform all the cleanups for the engine.
Definition: squirrel.cpp:541
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