Developer Notes
Notes for OHRRPGCE developers. This page is actually directed at the core developers as much as anyone else, as there are some pretty easy to forget gotchas when working on the engine.
FreeBASIC stuff
WITH
WITH is not just shorthand, it stores a pointer and uses that to access .members. Inside a 'WITH foo' block, be careful not to make the reference to 'foo' invalid, eg.:
WITH myarray(i) REDIM myarray(i + 10) 'If you do this, PLACE A BIG WARNING ON THE NEXT LINE 'Accessing myarray(i) members with .dot syntax will now likely segfault END WITH
Bugs
There are several bugs in FB that affect us. A very incomplete list:
- Implicitly declared strings (undeclared variables with $ suffix) are not freed! This leads to lots of memory leaks, which you're just going to have to ignore if using valgrind.
- fbc just loves thowing branch crossing variable definition warnings randomly, especially the linux builds. Real branch crossing warning are bugs that need to be fixed, but unfortunately most of these warnings are completely imaginary (and their random nature suggests they are due to initialised memory in the compiler (as might be caused by a branch crossing a variable definition, actually)).
- There's quite a few things (such as placement NEW) documented as being accessible from -lang fb only which we actually use from -lang deprecated.
Common
GOSUB
We don't use FreeBASIC's GOSUB, instead we use our own implementation. Use RETRACE instead of RETURN, this way we can use the normal meaning of RETURN. GOSUB must be the last statement on the line.
This uses scary macros containing assembly which push the current instruction pointer to the stack (see compat.bi; related details at FB stack internals). While I know of no way for these pointers to end up corrupted or interfere with other code, returning from a GOSUB block can causes problems. Jumping out of scopes is allowed, but you should not be allow to jump into a scope. It's disallowed in C, for example, and FB will throw a branch crossing warning normally, however it doesn't know that a GOSUB will later cause a RETRACE, so you'll get no warning or error.
GOSUB is not allowed inside a WITH, SCOPE (after variable definitions), FOR with a local counter or non-constant end or step, (and possibly other constructs I can't think of right now?).
WITH *blarg GOSUB foo .bar = 3 'BAD: WITH pointer may be corrupted END WITH FOR i as integer = 0 TO 4 GOSUB foo 'BAD: i may be corrupted NEXT FOR i = 1 TO UBOUND(cmdline_args) GOSUB foo 'BAD: loop number may be corrupted NEXT FOR i = 0 TO 2 GOSUB foo 'Allowable, but avoidance suggested NEXT
On the other hand, FOR, WITH, SCOPE and DIM are allowed inside a GOSUB block.
Luckily illegal GOSUBs can be detected using the misc/gosub.el script (which TMC runs every year or two) which . There is also misc/with.el to place warnings after GOSUBs within WITH blocks. I can't remember whether this was necessary because misc/gosub.el won't detect these cases or not.
File functions
Use our alternatives to various FB file related functions. These add error checking and logging and work around FB bugs
- findfiles or isfile or isdir instead of DIR (Note: isfile could be improved by using OS-specific functions, eg. stat() on Unix)
- killdir instead of RMDIR
- makedir instead of MKDIR
- safekill instead of KILL (better to use safekill even if you're sure the file exists)
Platform
__FB_UNIX__ only exists in FB 0.21 or later (which is our requirement now anyway), however it's always defined (taking value 0 or -1), unlike __FB_LINUX__ and so on. I recommend always using our own __UNIX__ define instead, as it's much less confusing. Don't use __FB_LINUX__ except for truely Linux-specific stuff. Example (in compat.bi):
#ifdef __UNIX__ # define SLASH "/" # define LINE_END !"\n" #else # define SLASH "\" # define LINE_END !"\r\n" #endif
Arrays
FB arrays are very limited. See FB Arrays Library for documentation of our custom arrays library.
Custom
ESC
PageUp+PageDown+Esc/Alt+F4/Cmd+Q/etc. work by setting keyval(-1), which causes setkeys to send a stream of ESC keypresses until clearkey(-1) is called. All menus in Custom should exit on a Esc keypress, except for those with unsaved state (eg. a modified help file and the Save/Save+Quit/Discard+Quit game menu). You need to call clearkey(-1) before querying the user whether to save if an Esc keypress will cancel the attempted exit.