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.
Contents |
[edit] FreeBASIC stuff
[edit] 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
[edit] Converting doubles to integers
- INT is actually the floor function. It return a double. Both unfortunate.
- CINT returns the nearest integer to a double (rounding to even to break ties). Returns an integer
- FIX truncates (rounds to 0). Returns a double.
- Assigning an double to an integer variable uses CINT
INT is usually the wrong function to use.
[edit] 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.
- SHELL on Linux (used in findfiles and isdir) (and maybe other unices) leaks file descriptors! valgrind reports these. Luckily the limit very high.
- OPEN on Linux can't open files which contain a \ character, it appears that the rtlib is doing something it shouldn't.
[edit] Common
[edit] UDTs
I've added warnings to all the types that are manually allocated/freed, which looks like:
'WARNING: don't add strings to this TYPE foo ... END TYPE
Don't add members of other types which need to constructed or destructed either (which is just other types containing strings). Please slap such a warning on a Type if you manually allocate/free memory for it anywhere. If you do want to add a string to such a type, you either need to replace Allocate/Deallocate with New/Delete, or to manually call .Destructor() before deleting it (strings don't actually need fancy initialisation, aside from zeroing out the string descriptor memory).
[edit] 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.
Also, every GOSUB must be balanced by a RETRACE. You can not GOSUB twice, RETRACE once, and then EXIT FUNCTION.
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.
[edit] 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/isdir/findfiles could be improved by using OS-specific functions, eg. stat() on Unix. Browsing could be greatly sped up.)
- killdir instead of RMDIR
- makedir instead of MKDIR
- safekill instead of KILL (better to use safekill even if you're sure the file exists)
- If you want to know the number of bytes successfully read from the file (like C's read()), use fb_FileGetIOB (See lumpfile.bas for example)
[edit] A note on files
FB's file functions are mostly wrappers around the C runtime, but add a lot of additional stuff. Unlike in C, reading off the end of a file succeeds, reading zeroed out bytes (even if using fb_FileGetIOB; which returns the number of bytes actually read, not the amount written to memory). However, writing off the end of a file will still write garbage between the end of the existing file and the start of the new data. You can use the extendfile Sub to guard against this before writing.
[edit] Platform
Note: __FB_UNIX__ has been fixed for the next FB release. Yay! __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
[edit] Arrays
FB arrays are very limited. See FB Arrays Library for documentation of our custom arrays library.
[edit] Custom
[edit] 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.